-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
GitHub proxy part 6: proxing Git using SSH transport #49980
base: master
Are you sure you want to change the base?
Conversation
73db1b8
to
1cd0ec1
Compare
a887119
to
a5cb9a6
Compare
a5cb9a6
to
97bbddf
Compare
// GitHubProxyCASSH uses same algorithms as UserCASSH. | ||
GitHubProxyCASSH: RSA2048, | ||
// GitClient uses same algorithms as UserCASSH. | ||
GitClient: RSA2048, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why we're not defaulting to P256 or Ed25519 here? The comment for the legacy
suite states "new features should always use the new algorithms".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure that hooking into lib/srv/forward.Server
to essentially add a completely separate mode gated by a flag (or like three different and potentially conflicting flags) is easier than writing something new that's going to be structurally guaranteed to work as intended just for the purpose of forwarding the ssh git protocol?
// GitServerGetter defines a service to get Git servers. | ||
services.GitServerGetter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If ClientI
already has a way to get a gitserver.Client
which has GetGitServer
and ListGitServers
, why do we need to extend ClientI with methods at the top level?
@@ -285,6 +286,11 @@ func (r *Router) DialHost(ctx context.Context, clientSrcAddr, clientDstAddr net. | |||
return nil, trace.Wrap(err) | |||
} | |||
} | |||
} else if target.GetGitHub() != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we have a subkind to check here? Let's try to safeguard ourselves against a regular ssh server getting a non-nil but empty github section due to serialization and deserialization mistakes.
@@ -418,6 +435,9 @@ func (r remoteSite) GetClusterNetworkingConfig(ctx context.Context) (types.Clust | |||
// getServer attempts to locate a node matching the provided host and port in | |||
// the provided site. | |||
func getServer(ctx context.Context, host, port string, site site) (types.Server, error) { | |||
if org, ok := types.GetGitHubOrgFromNodeAddr(host); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if a regular SSH server has a hostname that matches the pattern we've decided to reserve for github orgs?
@@ -79,6 +80,8 @@ import ( | |||
// return nil, trace.Wrap(err) | |||
// } | |||
type Server struct { | |||
component string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is a "component"? Please add a godoc for this.
if s.component == teleport.ComponentForwardingGit && s.targetServer != nil { | ||
return s.targetServer | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if targetServer is nil but the component is set to ComponentForwardingGit?
// gitServerWatcher provides the Git server set for the remote site | ||
gitServerWatcher *services.GenericWatcher[types.Server, readonly.Server] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agentless SSH across clusters relies on the root cluster generating the credentials that must be trusted by the destination. Seeing as how the destination is github, and the credentials must be in a plugincredential in the root, what's the point of interacting with git servers in a leaf cluster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The resource watcher will also constantly spew errors and reset if the underlying event stream can't be initialized because the leaf auth server doesn't know about the existence of git_server.
@@ -233,6 +234,7 @@ func (h *AuthHandlers) CreateIdentityContext(sconn *ssh.ServerConn) (IdentityCon | |||
} | |||
identity.PreviousIdentityExpires = asTime | |||
} | |||
identity.GitHubUserID = certificate.Extensions[teleport.CertExtensionGitHubUserID] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have traits and roles and the only server that's going to interact with the github user ID is in our control (because it's a MITM server in the proxy) why do we need to bake anything in the SSH certificate of the user? Doing so also prevents us from having different user IDs for different orgs, for example.
// | ||
// Sample command: git-upload-pack 'my-org/my-repo.git' | ||
func parseSSHCommand(command string) (*sshCommand, error) { | ||
gitService, path, ok := strings.Cut(strings.TrimSpace(command), " ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a real shell command lexer instead of writing something that appears to work but might accidentally let an attacker bypass auditing or authorization.
"SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s", | ||
"SHA256:br9IjFspm1vxR3iA35FWE+4VTyz1hYVLIE2t1/CeyWQ", | ||
"SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM", | ||
"SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://api.github.com/meta only lists three keys, I think that one of these four is the DSA key that's no longer used and was never supported by x/crypto/ssh anyway. Can we get rid of that?
userExpires := c.IdentityExpires.Sub(c.Clock.Now()) | ||
if userExpires > defaultGitHubUserCertTTL { | ||
return defaultGitHubUserCertTTL | ||
} | ||
return userExpires |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
userExpires := c.IdentityExpires.Sub(c.Clock.Now()) | |
if userExpires > defaultGitHubUserCertTTL { | |
return defaultGitHubUserCertTTL | |
} | |
return userExpires | |
userTTL := c.IdentityExpires.Sub(c.Clock.Now()) | |
return min(userTTL, defaultGitHubUserCertTTL) |
will do 👍 |
i am splitting out some parts of this PR to separate ones like |
Related:
will stack another PR for
tsh git ssh/config/clone
commands on top of this