Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TargetPort to RouteToApp & use it to route connections to multi-port TCP apps #49047

Open
wants to merge 10 commits into
base: r7s/ports-app-spec
Choose a base branch
from

Conversation

ravicious
Copy link
Member

@ravicious ravicious commented Nov 15, 2024

#47706 made it so that it's possible to configure a multi-port TCP app. This PR makes it possible to generate a cert with TargetPort and then makes the app agent use that field from the cert to route the connection to the target port. This is described in the "Passing the port number from the client to the app agent" section of the RFD and backwards compatibility is described in the "Server-client compatibility" section.

Best reviewed commit-by-commit. The actual implementation is rather simple, but I had to change a bunch of stuff to make tests for this feature more terse.

I manually tested that this works by modifying the code in lib/teleterm that generates app certs to include a hardcoded TargetPort. Then I configured a TCP app with an appropriate port range with Postgres running on that port and then I connected to it. All of the audit events include a separate field with the target port.

@ravicious ravicious added do-not-merge no-changelog Indicates that a PR does not require a changelog entry labels Nov 15, 2024
Comment on lines -547 to -548
+ // long as the port is defined in the app spec. When specified, it must be between 1 and 65535 and
+ // the URI is expected to use this port as well.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't true that the URI is expected to include TargetPort. This is a section that I forgot to update in the RFD PR when I was making this change.

Also wow, whatever GitHub uses for syntax highlighting breaks terribly when the things that being changed uses diff syntax. :~)

require.True(t, net.ParseIP(identity.LoginIP).IsLoopback())
require.Equal(t, []string{teleport.UsageAppsOnly}, identity.Usage)
require.Equal(t, "app-a", identity.RouteToApp.Name)
require.Equal(t, uint16(1337), identity.RouteToApp.TargetPort)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just copy-pasted the test case above and added a single line which checks TargetPort.

@ravicious ravicious marked this pull request as ready for review November 15, 2024 12:15
@ravicious
Copy link
Member Author

@marcoandredinis @espadolini I'm adding you both since you already have context on this. This is the last server-side change that's needed for multi-port TCP app access.

@github-actions github-actions bot added application-access rfd Request for Discussion size/md labels Nov 15, 2024
@ravicious ravicious removed the rfd Request for Discussion label Nov 15, 2024
return targetPort == port
}

return targetPort >= port && targetPort <= endPort
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return targetPort >= port && targetPort <= endPort
return port <= targetPort && targetPort <= endPort

// In theory, this behavior could be removed in the future if we guarantee that all clients always
// send a target port when connecting to multi-port apps, but no such effort was undertaken so far.
if targetPort == 0 {
firstPort := int(app.GetTCPPorts()[0].Port)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sort of spooky, we're only checking for app.GetTCPPorts() being nonempty in the caller so if we change it in the wrong way we might end up with a panic here. The logic is also a bit too spread out, perhaps we can rework it as something like this instead?

var dialTarget string
switch {
	case len(app.GetTCPPorts()) < 1:
		// dialTarget = addr.String
	case targetPort == 0:
		// dialTarget = joinhostport(host, firstport)
	default:
		// check for port in range then dialTarget = joinhostport(host, port)
}
dialer.Dial(dialTarget)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, should we error out if there's a target port but the app is not multi-port?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
application-access do-not-merge no-changelog Indicates that a PR does not require a changelog entry size/md
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants