forked from TrueCloudLab/certificates
Merge pull request #714 from smallstep/host-or-user-only-ssh-ca
SSH host or SSH user only CA
This commit is contained in:
commit
4a899fbafc
3 changed files with 61 additions and 13 deletions
|
@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
- Support for CloudKMS RSA-PSS signers without using templates.
|
||||
- Add flags to support individual passwords for the intermediate and SSH keys.
|
||||
- Global support for group admins in the OIDC provisioner.
|
||||
- Support host-only or user-only SSH CA.
|
||||
### Changed
|
||||
- Using go 1.17 for binaries
|
||||
### Fixed
|
||||
|
|
|
@ -361,6 +361,8 @@ func (a *Authority) init() error {
|
|||
// Append public key to list of host certs
|
||||
a.sshCAHostCerts = append(a.sshCAHostCerts, a.sshCAHostCertSignKey.PublicKey())
|
||||
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, a.sshCAHostCertSignKey.PublicKey())
|
||||
// Configure template variables.
|
||||
tmplVars.SSH.HostKey = a.sshCAHostCertSignKey.PublicKey()
|
||||
}
|
||||
if a.config.SSH.UserKey != "" {
|
||||
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||
|
@ -387,35 +389,32 @@ func (a *Authority) init() error {
|
|||
// Append public key to list of user certs
|
||||
a.sshCAUserCerts = append(a.sshCAUserCerts, a.sshCAUserCertSignKey.PublicKey())
|
||||
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, a.sshCAUserCertSignKey.PublicKey())
|
||||
// Configure template variables.
|
||||
tmplVars.SSH.UserKey = a.sshCAUserCertSignKey.PublicKey()
|
||||
}
|
||||
|
||||
// Append other public keys
|
||||
// Append other public keys and add them to the template variables.
|
||||
for _, key := range a.config.SSH.Keys {
|
||||
publicKey := key.PublicKey()
|
||||
switch key.Type {
|
||||
case provisioner.SSHHostCert:
|
||||
if key.Federated {
|
||||
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, key.PublicKey())
|
||||
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, publicKey)
|
||||
tmplVars.SSH.HostFederatedKeys = append(tmplVars.SSH.HostFederatedKeys, publicKey)
|
||||
} else {
|
||||
a.sshCAHostCerts = append(a.sshCAHostCerts, key.PublicKey())
|
||||
a.sshCAHostCerts = append(a.sshCAHostCerts, publicKey)
|
||||
}
|
||||
case provisioner.SSHUserCert:
|
||||
if key.Federated {
|
||||
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, key.PublicKey())
|
||||
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, publicKey)
|
||||
tmplVars.SSH.UserFederatedKeys = append(tmplVars.SSH.UserFederatedKeys, publicKey)
|
||||
} else {
|
||||
a.sshCAUserCerts = append(a.sshCAUserCerts, key.PublicKey())
|
||||
a.sshCAUserCerts = append(a.sshCAUserCerts, publicKey)
|
||||
}
|
||||
default:
|
||||
return errors.Errorf("unsupported type %s", key.Type)
|
||||
}
|
||||
}
|
||||
|
||||
// Configure template variables.
|
||||
tmplVars.SSH.HostKey = a.sshCAHostCertSignKey.PublicKey()
|
||||
tmplVars.SSH.UserKey = a.sshCAUserCertSignKey.PublicKey()
|
||||
// On the templates we skip the first one because there's a distinction
|
||||
// between the main key and federated keys.
|
||||
tmplVars.SSH.HostFederatedKeys = append(tmplVars.SSH.HostFederatedKeys, a.sshCAHostFederatedCerts[1:]...)
|
||||
tmplVars.SSH.UserFederatedKeys = append(tmplVars.SSH.UserFederatedKeys, a.sshCAUserFederatedCerts[1:]...)
|
||||
}
|
||||
|
||||
// Check if a KMS with decryption capability is required and available
|
||||
|
|
|
@ -87,6 +87,52 @@ func (m sshTestOptionsModifier) Modify(cert *ssh.Certificate, opts provisioner.S
|
|||
return fmt.Errorf(string(m))
|
||||
}
|
||||
|
||||
func TestAuthority_initHostOnly(t *testing.T) {
|
||||
auth := testAuthority(t, func(a *Authority) error {
|
||||
a.config.SSH.UserKey = ""
|
||||
return nil
|
||||
})
|
||||
|
||||
// Check keys
|
||||
keys, err := auth.GetSSHRoots(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, 1, keys.HostKeys)
|
||||
assert.Len(t, 0, keys.UserKeys)
|
||||
|
||||
// Check templates, user templates should work fine.
|
||||
_, err = auth.GetSSHConfig(context.Background(), "user", nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = auth.GetSSHConfig(context.Background(), "host", map[string]string{
|
||||
"Certificate": "ssh_host_ecdsa_key-cert.pub",
|
||||
"Key": "ssh_host_ecdsa_key",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAuthority_initUserOnly(t *testing.T) {
|
||||
auth := testAuthority(t, func(a *Authority) error {
|
||||
a.config.SSH.HostKey = ""
|
||||
return nil
|
||||
})
|
||||
|
||||
// Check keys
|
||||
keys, err := auth.GetSSHRoots(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, 0, keys.HostKeys)
|
||||
assert.Len(t, 1, keys.UserKeys)
|
||||
|
||||
// Check templates, host templates should work fine.
|
||||
_, err = auth.GetSSHConfig(context.Background(), "host", map[string]string{
|
||||
"Certificate": "ssh_host_ecdsa_key-cert.pub",
|
||||
"Key": "ssh_host_ecdsa_key",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = auth.GetSSHConfig(context.Background(), "user", nil)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestAuthority_SignSSH(t *testing.T) {
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
assert.FatalError(t, err)
|
||||
|
@ -153,6 +199,8 @@ func TestAuthority_SignSSH(t *testing.T) {
|
|||
}{
|
||||
{"ok-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
||||
{"ok-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
||||
{"ok-user-only", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
|
||||
{"ok-host-only", fields{nil, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
|
||||
{"ok-opts-type-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert}, false},
|
||||
{"ok-opts-type-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert}, false},
|
||||
{"ok-opts-principals", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user", Principals: []string{"user"}}, []provisioner.SignOption{userTemplateWithUser}}, want{CertType: ssh.UserCert, Principals: []string{"user"}}, false},
|
||||
|
|
Loading…
Reference in a new issue