Refactor ssh.ClientConfig used by tctl and API clients to use the first valid principal as User.

This commit is contained in:
Brian Joerger
2021-03-30 17:53:29 -07:00
committed by Russell Jones
parent b72c54b231
commit 826ed676fa
7 changed files with 37 additions and 35 deletions
+1 -1
View File
@@ -190,7 +190,7 @@ func getExpectedTLSConfig(t *testing.T) *tls.Config {
}
func getExpectedSSHConfig(t *testing.T) *ssh.ClientConfig {
config, err := sshutils.SSHClientConfig(sshCert, keyPEM, [][]byte{sshCACert})
config, err := sshutils.ProxyClientSSHConfig(sshCert, keyPEM, [][]byte{sshCACert})
require.NoError(t, err)
return config
+2 -1
View File
@@ -86,10 +86,11 @@ func (i *IdentityFile) TLSConfig() (*tls.Config, error) {
// SSHClientConfig returns the identity file's associated SSHClientConfig.
func (i *IdentityFile) SSHClientConfig() (*ssh.ClientConfig, error) {
ssh, err := sshutils.SSHClientConfig(i.Certs.SSH, i.PrivateKey, i.CACerts.SSH)
ssh, err := sshutils.ProxyClientSSHConfig(i.Certs.SSH, i.PrivateKey, i.CACerts.SSH)
if err != nil {
return nil, trace.Wrap(err)
}
return ssh, nil
}
+1 -1
View File
@@ -131,7 +131,7 @@ func (p *Profile) SSHClientConfig() (*ssh.ClientConfig, error) {
return nil, trace.Wrap(err)
}
ssh, err := sshutils.SSHClientConfig(cert, key, [][]byte{caCerts})
ssh, err := sshutils.ProxyClientSSHConfig(cert, key, [][]byte{caCerts})
if err != nil {
return nil, trace.Wrap(err)
}
+14 -5
View File
@@ -47,9 +47,12 @@ func ParseCertificate(buf []byte) (*ssh.Certificate, error) {
return cert, nil
}
// SSHClientConfig returns an ssh.ClientConfig with SSH credentials from this
// ProxyClientSSHConfig returns an ssh.ClientConfig with SSH credentials from this
// Key and HostKeyCallback matching SSH CAs in the Key.
func SSHClientConfig(sshCert, privKey []byte, caCerts [][]byte) (*ssh.ClientConfig, error) {
//
// The config is set up to authenticate to proxy with the first available principal.
//
func ProxyClientSSHConfig(sshCert, privKey []byte, caCerts [][]byte) (*ssh.ClientConfig, error) {
cert, err := ParseCertificate(sshCert)
if err != nil {
return nil, trace.Wrap(err, "failed to extract username from SSH certificate")
@@ -57,16 +60,22 @@ func SSHClientConfig(sshCert, privKey []byte, caCerts [][]byte) (*ssh.ClientConf
authMethod, err := AsAuthMethod(cert, privKey)
if err != nil {
return nil, trace.Wrap(err, "failed to convert identity file to auth method")
return nil, trace.Wrap(err, "failed to convert key pair to auth method")
}
hostKeyCallback, err := HostKeyCallback(caCerts)
if err != nil {
return nil, trace.Wrap(err, "failed to convert identity file to HostKeyCallback")
return nil, trace.Wrap(err, "failed to convert certificate authorities to HostKeyCallback")
}
// The KeyId is not always a valid principal, so we use the first valid principal instead.
user := cert.KeyId
if len(cert.ValidPrincipals) > 0 {
user = cert.ValidPrincipals[0]
}
return &ssh.ClientConfig{
User: cert.KeyId,
User: user,
Auth: []ssh.AuthMethod{authMethod},
HostKeyCallback: hostKeyCallback,
Timeout: defaults.DefaultDialTimeout,
+16 -24
View File
@@ -218,10 +218,23 @@ func (k *Key) clientTLSConfig(cipherSuites []uint16, tlsCertRaw []byte) (*tls.Co
return tlsConfig, nil
}
// ClientSSHConfig returns an ssh.ClientConfig with SSH credentials from this
// ProxyClientSSHConfig returns an ssh.ClientConfig with SSH credentials from this
// Key and HostKeyCallback matching SSH CAs in the Key.
func (k *Key) ClientSSHConfig() (*ssh.ClientConfig, error) {
return sshutils.SSHClientConfig(k.Cert, k.Priv, k.SSHCAs())
//
// The config is set up to authenticate to proxy with the first available principal
// and ( if keyStore != nil ) trust local SSH CAs without asking for public keys.
//
func (k *Key) ProxyClientSSHConfig(keyStore LocalKeyStore) (*ssh.ClientConfig, error) {
sshConfig, err := sshutils.ProxyClientSSHConfig(k.Cert, k.Priv, k.SSHCAs())
if err != nil {
return nil, trace.Wrap(err)
}
if keyStore != nil {
sshConfig.HostKeyCallback = NewKeyStoreCertChecker(keyStore)
}
return sshConfig, nil
}
// CertUsername returns the name of the Teleport user encoded in the SSH certificate.
@@ -403,27 +416,6 @@ func (k *Key) HostKeyCallback() (ssh.HostKeyCallback, error) {
return sshutils.HostKeyCallback(k.SSHCAs())
}
// ProxyClientSSHConfig returns an ssh.ClientConfig with SSH credentials from this
// Key and HostKeyCallback matching SSH CAs in the Key.
//
// The config is set up to authenticate to proxy with the first
// available principal and trust local SSH CAs without asking
// for public keys.
//
func ProxyClientSSHConfig(k *Key, keyStore LocalKeyStore) (*ssh.ClientConfig, error) {
sshConfig, err := k.ClientSSHConfig()
if err != nil {
return nil, trace.Wrap(err)
}
principals, err := k.CertPrincipals()
if err != nil {
return nil, trace.Wrap(err)
}
sshConfig.User = principals[0]
sshConfig.HostKeyCallback = NewKeyStoreCertChecker(keyStore)
return sshConfig, nil
}
// RootClusterName extracts the root cluster name from the issuer
// of the Teleport TLS certificate.
func (k *Key) RootClusterName() (string, error) {
+1 -1
View File
@@ -227,7 +227,7 @@ func TestProxySSHConfig(t *testing.T) {
err = s.store.AddKnownHostKeys("127.0.0.1", []ssh.PublicKey{caPub})
require.NoError(t, err)
clientConfig, err := ProxyClientSSHConfig(key, s.store)
clientConfig, err := key.ProxyClientSSHConfig(s.store)
require.NoError(t, err)
called := atomic.NewInt32(0)
+2 -2
View File
@@ -384,7 +384,7 @@ func applyConfig(ccf *GlobalCLIFlags, cfg *service.Config) (*AuthServiceClientCo
if err != nil {
return nil, trace.Wrap(err)
}
authConfig.SSH, err = key.ClientSSHConfig()
authConfig.SSH, err = key.ProxyClientSSHConfig(nil)
if err != nil {
return nil, trace.Wrap(err)
}
@@ -462,7 +462,7 @@ func loadConfigFromProfile(ccf *GlobalCLIFlags, cfg *service.Config) (*AuthServi
return nil, trace.Wrap(err)
}
authConfig.TLS.InsecureSkipVerify = ccf.Insecure
authConfig.SSH, err = client.ProxyClientSSHConfig(key, keyStore)
authConfig.SSH, err = key.ProxyClientSSHConfig(keyStore)
if err != nil {
return nil, trace.Wrap(err)
}