Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/profile/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ type Profile struct {
// MFAMode ("auto", "platform", "cross-platform").
// Equivalent to the --mfa-mode tsh flag.
MFAMode string `yaml:"mfa_mode,omitempty"`

// PrivateKeyPolicy is a key policy enforced for this profile.
PrivateKeyPolicy keys.PrivateKeyPolicy `yaml:"private_key_policy"`
}

// Copy returns a shallow copy of p, or nil if p is nil.
Expand Down
2 changes: 1 addition & 1 deletion api/utils/keys/yubikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func (y *yubiKey) generatePrivateKey(slot piv.Slot, touchPolicy piv.TouchPolicy)
}

// Create a self signed certificate and store it in the PIV slot so that other
// Teleport Clients know to reuse the stored key instead of genearting a new one.
// Teleport Clients know to reuse the stored key instead of generating a new one.
priv, err := yk.PrivateKey(slot, pub, piv.KeyAuth{})
if err != nil {
return nil, trace.Wrap(err)
Expand Down
57 changes: 22 additions & 35 deletions lib/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ func (c *Config) LoadProfile(ps ProfileStore, proxyAddr string) error {
c.KeysDir = profile.Dir
c.AuthConnector = profile.AuthConnector
c.LoadAllCAs = profile.LoadAllCAs
c.PrivateKeyPolicy = profile.PrivateKeyPolicy
c.AuthenticatorAttachment, err = parseMFAMode(profile.MFAMode)
if err != nil {
return trace.BadParameter("unable to parse mfa mode in user profile: %v.", err)
Expand Down Expand Up @@ -629,6 +630,7 @@ func (c *Config) SaveProfile(makeCurrent bool) error {
AuthConnector: c.AuthConnector,
MFAMode: c.AuthenticatorAttachment.String(),
LoadAllCAs: c.LoadAllCAs,
PrivateKeyPolicy: c.PrivateKeyPolicy,
}

if err := c.ClientStore.SaveProfile(p, makeCurrent); err != nil {
Expand Down Expand Up @@ -3016,11 +3018,6 @@ func (tc *TeleportClient) Login(ctx context.Context) (*Key, error) {
return nil, trace.Wrap(err)
}

// Set private key policy from ping response if not already set.
if tc.PrivateKeyPolicy == "" {
tc.PrivateKeyPolicy = pr.Auth.PrivateKeyPolicy
}

Comment thread
GavinFrazar marked this conversation as resolved.
key, err := tc.SSHLogin(ctx, sshLoginFunc)
if err != nil {
return nil, trace.Wrap(err)
Expand Down Expand Up @@ -3182,7 +3179,7 @@ type SSHLoginFunc func(context.Context, *keys.PrivateKey) (*auth.SSHLoginRespons
// SSHLogin uses the given login function to login the client. This function handles
// private key logic and parsing the resulting auth response.
func (tc *TeleportClient) SSHLogin(ctx context.Context, sshLoginFunc SSHLoginFunc) (*Key, error) {
priv, err := tc.GetNewLoginKey(ctx, tc.PrivateKeyPolicy)
priv, err := tc.GetNewLoginKey(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
Expand All @@ -3195,7 +3192,8 @@ func (tc *TeleportClient) SSHLogin(ctx context.Context, sshLoginFunc SSHLoginFun
fmt.Fprintf(tc.Stderr, "Unmet private key policy %q.\n", privateKeyPolicy)

// Set the private key policy to the expected value and re-login.
priv, err = tc.GetNewLoginKey(ctx, privateKeyPolicy)
tc.PrivateKeyPolicy = privateKeyPolicy
priv, err = tc.GetNewLoginKey(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down Expand Up @@ -3241,39 +3239,23 @@ func (tc *TeleportClient) SSHLogin(ctx context.Context, sshLoginFunc SSHLoginFun
}

// GetNewLoginKey gets a new private key for login.
func (tc *TeleportClient) GetNewLoginKey(ctx context.Context, keyPolicy keys.PrivateKeyPolicy) (*keys.PrivateKey, error) {
key, err := tc.LocalAgent().GetCoreKey()
if err == nil {
// If we find an existing key with a non-zero key polic and it meets
// the given keyPolicy requirement, then we should use the existing key.
if coreKeyPolicy := keys.GetPrivateKeyPolicy(key.PrivateKey); coreKeyPolicy != keys.PrivateKeyPolicyNone {
if err := keyPolicy.VerifyPolicy(coreKeyPolicy); err == nil {
return key.PrivateKey, nil
}
}
Comment thread
GavinFrazar marked this conversation as resolved.
} else if !trace.IsNotFound(err) {
return nil, trace.Wrap(err)
}

switch keyPolicy {
case keys.PrivateKeyPolicyHardwareKey, keys.PrivateKeyPolicyHardwareKeyTouch:
func (tc *TeleportClient) GetNewLoginKey(ctx context.Context) (priv *keys.PrivateKey, err error) {
switch tc.PrivateKeyPolicy {
case keys.PrivateKeyPolicyHardwareKey:
log.Debugf("Attempting to login with YubiKey private key.")

priv, err := keys.GetOrGenerateYubiKeyPrivateKey(keyPolicy == keys.PrivateKeyPolicyHardwareKeyTouch)
if err != nil {
return nil, trace.Wrap(err)
}
return priv, nil
priv, err = keys.GetOrGenerateYubiKeyPrivateKey(false)
case keys.PrivateKeyPolicyHardwareKeyTouch:
log.Debugf("Attempting to login with YubiKey private key with touch required.")
priv, err = keys.GetOrGenerateYubiKeyPrivateKey(true)
default:
log.Debugf("Attempting to login with a new RSA private key.")
priv, err = native.GeneratePrivateKey()
}

// Generate a new standard key.
priv, err := native.GeneratePrivateKey()
if err != nil {
return nil, trace.Wrap(err)
}
return priv, nil
if err != nil {
return nil, trace.Wrap(err)
}
return priv, nil
}

// new SSHLogin generates a new SSHLogin using the given login key.
Expand Down Expand Up @@ -3780,6 +3762,11 @@ func (tc *TeleportClient) applyProxySettings(proxySettings webclient.ProxySettin
// authentication settings, overriding existing fields in tc.
func (tc *TeleportClient) applyAuthSettings(authSettings webclient.AuthenticationSettings) {
tc.LoadAllCAs = authSettings.LoadAllCAs

// Update the private key policy from auth settings if it is stricter than the saved setting.
if authSettings.PrivateKeyPolicy != "" && authSettings.PrivateKeyPolicy.VerifyPolicy(tc.PrivateKeyPolicy) != nil {
tc.PrivateKeyPolicy = authSettings.PrivateKeyPolicy
}
}

// AddTrustedCA adds a new CA as trusted CA for this client, used in tests
Expand Down
7 changes: 4 additions & 3 deletions lib/client/client_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,10 @@ func (s *Store) ReadProfileStatus(profileName string) (*ProfileStatus, error) {
}
key, err := s.GetKey(idx, WithAllCerts...)
if err != nil {
if trace.IsNotFound(err) {
// If we can't find a key to match the profile, return a partial status. This
// is used for some superficial functions `tsh logout` and `tsh status`.
if trace.IsNotFound(err) || trace.IsConnectionProblem(err) {
// If we can't find a key to match the profile, or can't connect to
// the key (hardware key), return a partial status. This is used for
// some superficial functions `tsh logout` and `tsh status`.
return &ProfileStatus{
Name: profileName,
Dir: profile.Dir,
Expand Down
2 changes: 0 additions & 2 deletions lib/teleterm/clusters/cluster_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@ func (c *Cluster) updateClientFromPingResponse(ctx context.Context) (*webclient.
return nil, trace.Wrap(err)
}

c.clusterClient.PrivateKeyPolicy = pingResp.Auth.PrivateKeyPolicy

return pingResp, nil
}

Expand Down
1 change: 1 addition & 0 deletions tool/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func ShowClusterAlerts(ctx context.Context, client ClusterAlertGetter, w io.Writ
// get any "on login" alerts
alertCtx, cancelAlertCtx := context.WithTimeout(ctx, constants.TimeoutGetClusterAlerts)
defer cancelAlertCtx()

alerts, err := client.GetClusterAlerts(alertCtx, types.GetClusterAlertsRequest{
Labels: labels,
Severity: minSeverity,
Expand Down
23 changes: 17 additions & 6 deletions tool/tsh/tsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import (
"github.com/gravitational/teleport/api/types"
apievents "github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/api/types/wrappers"
"github.com/gravitational/teleport/api/utils/keys"
"github.com/gravitational/teleport/lib/asciitable"
"github.com/gravitational/teleport/lib/auth"
wancli "github.com/gravitational/teleport/lib/auth/webauthncli"
Expand Down Expand Up @@ -1731,10 +1732,16 @@ func onLogin(cf *CLIConf) error {
}

// Show on-login alerts, all high severity alerts are shown by onStatus
// so can be excluded here.
// so can be excluded here, except when Hardware Key Touch is required
// which skips on-status alerts.
alertSeverityMax := types.AlertSeverity_MEDIUM
if tc.PrivateKeyPolicy == keys.PrivateKeyPolicyHardwareKeyTouch {
alertSeverityMax = types.AlertSeverity_HIGH
}

if err := common.ShowClusterAlerts(cf.Context, tc, os.Stderr, map[string]string{
types.AlertOnLogin: "yes",
}, types.AlertSeverity_LOW, types.AlertSeverity_MEDIUM); err != nil {
}, types.AlertSeverity_LOW, alertSeverityMax); err != nil {
log.WithError(err).Warn("Failed to display cluster alerts.")
}

Expand Down Expand Up @@ -3242,7 +3249,7 @@ func makeClientForProxy(cf *CLIConf, proxy string, useProfileLogin bool) (*clien
// be found, or the key isn't supported as an agent key.
if profileSiteName != "" {
if err := tc.LoadKeyForCluster(profileSiteName); err != nil {
if !trace.IsNotFound(err) {
if !trace.IsNotFound(err) && !trace.IsConnectionProblem(err) {
return nil, trace.Wrap(err)
}
log.WithError(err).Infof("Could not load key for %s into the local agent.", profileSiteName)
Expand Down Expand Up @@ -3584,9 +3591,13 @@ func onStatus(cf *CLIConf) error {
return nil
}

if err := common.ShowClusterAlerts(cf.Context, tc, os.Stderr, nil,
types.AlertSeverity_HIGH, types.AlertSeverity_HIGH); err != nil {
log.WithError(err).Warn("Failed to display cluster alerts.")
if tc.PrivateKeyPolicy == keys.PrivateKeyPolicyHardwareKeyTouch {
log.Debug("Skipping cluster alerts due to Hardware Key Touch requirement.")
} else {
if err := common.ShowClusterAlerts(cf.Context, tc, os.Stderr, nil,
types.AlertSeverity_HIGH, types.AlertSeverity_HIGH); err != nil {
log.WithError(err).Warn("Failed to display cluster alerts.")
}
}

return nil
Expand Down