diff --git a/lib/client/api.go b/lib/client/api.go index 6b0457a44ca5a..e93d6f6cd0343 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -600,7 +600,8 @@ func RetryWithRelogin(ctx context.Context, tc *TeleportClient, fn func() error) func IsErrorResolvableWithRelogin(err error) bool { // Assume that failed handshake is a result of expired credentials. return utils.IsHandshakeFailedError(err) || utils.IsCertExpiredError(err) || - trace.IsBadParameter(err) || trace.IsTrustError(err) || keys.IsPrivateKeyPolicyError(err) || trace.IsNotFound(err) + trace.IsBadParameter(err) || trace.IsTrustError(err) || + keys.IsPrivateKeyPolicyError(err) || IsNoCredentialsError(err) } // GetProfile gets the profile for the specified proxy address, or diff --git a/lib/client/client_store.go b/lib/client/client_store.go index 6ffce20fc565a..c2cd18b9240b2 100644 --- a/lib/client/client_store.go +++ b/lib/client/client_store.go @@ -14,6 +14,7 @@ limitations under the License. package client import ( + "errors" "net/url" "os" "time" @@ -76,11 +77,25 @@ func (s *Store) AddKey(key *Key) error { return nil } +// ErrNoCredentials is returned by the client store when a specific key is not found. +// This error can be used to determine whether a client should retrieve new credentials, +// like how it is used with lib/client.RetryWithRelogin. +var ErrNoCredentials = trace.NotFound("no credentials") + +// IsNoCredentialsError returns whether the given error is an ErrNoCredentials error. +func IsNoCredentialsError(err error) bool { + return errors.Is(err, ErrNoCredentials) +} + // GetKey gets the requested key with trusted the requested certificates. The key's -// trusted certs will be retrieved from the trusted certs store. +// trusted certs will be retrieved from the trusted certs store. If the key is not +// found or is missing data (certificates, etc.), then an ErrNoCredentials error +// is returned. func (s *Store) GetKey(idx KeyIndex, opts ...CertOption) (*Key, error) { key, err := s.KeyStore.GetKey(idx, opts...) - if err != nil { + if trace.IsNotFound(err) { + return nil, trace.Wrap(ErrNoCredentials, err.Error()) + } else if err != nil { return nil, trace.Wrap(err) }