-
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
Cache per-cluster SSH certificates under ~/.tsh #5938
Conversation
c3d9dda
to
82d3d63
Compare
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.
Looks mostly fine, but we definitely need to test k8s/db access and u2f before merging because there's a ton of refactoring in here.
Ping me after you address the comments and I can help with some of it.
|
||
// read in key for this user in proxy | ||
key, err := a.GetKey() | ||
if err != nil { | ||
if trace.IsNotFound(err) { | ||
return a, nil | ||
} | ||
return nil, trace.Wrap(err) | ||
} | ||
|
||
a.log.Infof("Loading key for %q", username) | ||
|
||
// load key into the agent | ||
_, err = a.LoadKey(*key) | ||
if err != nil { | ||
return nil, trace.Wrap(err) | ||
} | ||
|
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.
why is this removed?
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.
In order to fetch a SSH key we now have to provide a cluster name. Here in KeyAgent
, however, the choice of the cluster isn't known, so this initial key loading cannot be done so simply anymore. It has to be moved outside to a context that can indicate which of the cluster-specific SSH keys is meant to be loaded.
type withKubeCerts struct { | ||
teleportClusterName string | ||
// WithSSHCerts is a CertOption for handling SSH certificates. | ||
type WithSSHCerts struct{} |
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.
since these are now stateless, can you make them into vars?
var WithSSHCerts = withSSHCerts{}
type withSSHCerts struct {}
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.
I'd rather keep the exported CertOption
structs for possible field additions in the future. Also, WithDBCerts
still has some state (dbName
for logging out of a specific DB).
bd04762
to
858d292
Compare
Please re-review, I introduced new changes with the rebase. I had to roll back on my idea of requesting certs even for clusters specified just with
Update: The error seems to have been fixed so it comes up only in connection with impersonation requests. |
c785f69
to
f789619
Compare
@andrejtokarcik something doesn't handle missing SSH certs correctly:
|
Looks like the above problem only happens when I delete the root SSH cert.
|
Co-authored-by: Andrew Lytvynov <andrew@goteleport.com>
lib/client/api.go
Outdated
} | ||
// try to authenticate using every non interactive auth method we have: | ||
var errs []error | ||
for i, m := range tc.authMethods() { |
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.
here, tc.authMethods()
will return nil
if SSH cert is missing for the cluster.
tc.authMethods
(and the underlying LocalKeyAgent.AuthMethods()
) should return an error if no SSH cert is present.
@klizhentas for docs - when the user upgrades |
3e0edc8
to
60795b8
Compare
60795b8
to
914067f
Compare
m = append(m, agentMethods...) | ||
} | ||
if len(m) == 0 { | ||
return nil, trace.BadParameter("no auth method available") |
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.
return nil, trace.BadParameter("no auth method available") | |
return nil, trace.NotFound("no SSH auth method available, try logging in again") |
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.
I wouldn't reformulate in this way as it would make the relogin log unreadable. Current version:
DEBU [CLIENT] Activating relogin on no auth method available. client/api.go:455
Also, RetryWithRelogin
wouldn't handle NotFoundError
as well:
Lines 447 to 451 in 879f8c2
// Assume that failed handshake is a result of expired credentials, | |
// retry the login procedure | |
if !utils.IsHandshakeFailedError(err) && !utils.IsCertExpiredError(err) && !trace.IsBadParameter(err) && !trace.IsTrustError(err) { | |
return trace.Wrap(err) | |
} |
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.
OK, as long as this error is never returned to users in non-debug output
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.
Or maybe it would actually help in handling the errors more correctly when the user has to re-login manually....
for i := range signers { | ||
// filter out non-certificates (like regular public SSH keys stored in the SSH agent): | ||
_, ok := signers[i].PublicKey().(*ssh.Certificate) | ||
if ok { | ||
m = append(m, sshutils.NewAuthMethodForCert(signers[i])) | ||
} | ||
} | ||
return m | ||
if len(m) == 0 { | ||
return nil, trace.BadParameter("no auth method available") |
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.
return nil, trace.BadParameter("no auth method available") | |
return nil, trace.NotFound("no SSH auth method available, try logging in again") |
LGTM, there are still a few edge cases with corrupt |
…e/dynamodb-gsi-autoscaling * 'master' of github.com:gravitational/teleport: (41 commits) Refactor ssh.ClientConfig used by tctl and API clients to use the first valid principal as User. Update Architecture Overview With Link To User Roles (#6224) Add `lint-api` target and fix lint errors (#6169) ssh: fix relogin with jumphosts (#6213) drone: use emptyDir for /var/lib/docker filesystem and prevent repetitive docker pulls (#6145) Remove ARM64 FIPS builds (#6236) tsh Profile SSH certs fix (#6214) mfa: fix gRPC unimplemented check in cert reissue Open Sources Access Controls Docs (#6188) (#6217) add PAM environment with interpolation support Cache per-cluster SSH certificates under ~/.tsh (#5938) add special resource type for access plugin data Enable DynamoDB autoscaling on global secondary indices (#6112) darwin fips builds (#5866) kube: add kubernetes_labels to role JSON schema mfa: send username instead of SSH login name in MFA cert request fix nil slice bug RFD 16: Add a section on `tctl rm` resetting resources back to defaults (#5673) Update application access docs (#6055) (#6137) Bump linux FIPS builds to use go1.16.2b7 release (#6143) ...
When
-J
is set, this also loads/reissues the SSH cert for the cluster associated with the jumphost's certificate. Fixes #5637.Warning: Although I'm pretty confident about the current design, more testing is still needed, especially for scenarios involving MFA, access requests, k8s/DB/app access.