Skip to content

Commit aedd7fc

Browse files
committedSep 28, 2021
Be able to start a SSH host or SSH user only CA
In previous versions if the host or user CA is not configured, the start of step-ca was crashing. This allows to configure a user or host only ssh ca.
1 parent 28bd2ef commit aedd7fc

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed
 

Diff for: ‎authority/authority.go

+12-13
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ func (a *Authority) init() error {
361361
// Append public key to list of host certs
362362
a.sshCAHostCerts = append(a.sshCAHostCerts, a.sshCAHostCertSignKey.PublicKey())
363363
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, a.sshCAHostCertSignKey.PublicKey())
364+
// Configure template variables.
365+
tmplVars.SSH.HostKey = a.sshCAHostCertSignKey.PublicKey()
364366
}
365367
if a.config.SSH.UserKey != "" {
366368
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
@@ -387,35 +389,32 @@ func (a *Authority) init() error {
387389
// Append public key to list of user certs
388390
a.sshCAUserCerts = append(a.sshCAUserCerts, a.sshCAUserCertSignKey.PublicKey())
389391
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, a.sshCAUserCertSignKey.PublicKey())
392+
// Configure template variables.
393+
tmplVars.SSH.UserKey = a.sshCAUserCertSignKey.PublicKey()
390394
}
391395

392-
// Append other public keys
396+
// Append other public keys and add them to the template variables.
393397
for _, key := range a.config.SSH.Keys {
398+
publicKey := key.PublicKey()
394399
switch key.Type {
395400
case provisioner.SSHHostCert:
396401
if key.Federated {
397-
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, key.PublicKey())
402+
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, publicKey)
403+
tmplVars.SSH.HostFederatedKeys = append(tmplVars.SSH.HostFederatedKeys, publicKey)
398404
} else {
399-
a.sshCAHostCerts = append(a.sshCAHostCerts, key.PublicKey())
405+
a.sshCAHostCerts = append(a.sshCAHostCerts, publicKey)
400406
}
401407
case provisioner.SSHUserCert:
402408
if key.Federated {
403-
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, key.PublicKey())
409+
a.sshCAUserFederatedCerts = append(a.sshCAUserFederatedCerts, publicKey)
410+
tmplVars.SSH.UserFederatedKeys = append(tmplVars.SSH.UserFederatedKeys, publicKey)
404411
} else {
405-
a.sshCAUserCerts = append(a.sshCAUserCerts, key.PublicKey())
412+
a.sshCAUserCerts = append(a.sshCAUserCerts, publicKey)
406413
}
407414
default:
408415
return errors.Errorf("unsupported type %s", key.Type)
409416
}
410417
}
411-
412-
// Configure template variables.
413-
tmplVars.SSH.HostKey = a.sshCAHostCertSignKey.PublicKey()
414-
tmplVars.SSH.UserKey = a.sshCAUserCertSignKey.PublicKey()
415-
// On the templates we skip the first one because there's a distinction
416-
// between the main key and federated keys.
417-
tmplVars.SSH.HostFederatedKeys = append(tmplVars.SSH.HostFederatedKeys, a.sshCAHostFederatedCerts[1:]...)
418-
tmplVars.SSH.UserFederatedKeys = append(tmplVars.SSH.UserFederatedKeys, a.sshCAUserFederatedCerts[1:]...)
419418
}
420419

421420
// Check if a KMS with decryption capability is required and available

Diff for: ‎authority/ssh_test.go

+48
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,52 @@ func (m sshTestOptionsModifier) Modify(cert *ssh.Certificate, opts provisioner.S
8787
return fmt.Errorf(string(m))
8888
}
8989

90+
func TestAuthority_initHostOnly(t *testing.T) {
91+
auth := testAuthority(t, func(a *Authority) error {
92+
a.config.SSH.UserKey = ""
93+
return nil
94+
})
95+
96+
// Check keys
97+
keys, err := auth.GetSSHRoots(context.Background())
98+
assert.NoError(t, err)
99+
assert.Len(t, 1, keys.HostKeys)
100+
assert.Len(t, 0, keys.UserKeys)
101+
102+
// Check templates, user templates should work fine.
103+
_, err = auth.GetSSHConfig(context.Background(), "user", nil)
104+
assert.NoError(t, err)
105+
106+
_, err = auth.GetSSHConfig(context.Background(), "host", map[string]string{
107+
"Certificate": "ssh_host_ecdsa_key-cert.pub",
108+
"Key": "ssh_host_ecdsa_key",
109+
})
110+
assert.Error(t, err)
111+
}
112+
113+
func TestAuthority_initUserOnly(t *testing.T) {
114+
auth := testAuthority(t, func(a *Authority) error {
115+
a.config.SSH.HostKey = ""
116+
return nil
117+
})
118+
119+
// Check keys
120+
keys, err := auth.GetSSHRoots(context.Background())
121+
assert.NoError(t, err)
122+
assert.Len(t, 0, keys.HostKeys)
123+
assert.Len(t, 1, keys.UserKeys)
124+
125+
// Check templates, host templates should work fine.
126+
_, err = auth.GetSSHConfig(context.Background(), "host", map[string]string{
127+
"Certificate": "ssh_host_ecdsa_key-cert.pub",
128+
"Key": "ssh_host_ecdsa_key",
129+
})
130+
assert.NoError(t, err)
131+
132+
_, err = auth.GetSSHConfig(context.Background(), "user", nil)
133+
assert.Error(t, err)
134+
}
135+
90136
func TestAuthority_SignSSH(t *testing.T) {
91137
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
92138
assert.FatalError(t, err)
@@ -153,6 +199,8 @@ func TestAuthority_SignSSH(t *testing.T) {
153199
}{
154200
{"ok-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
155201
{"ok-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
202+
{"ok-user-only", fields{signer, nil}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{userTemplate, userOptions}}, want{CertType: ssh.UserCert}, false},
203+
{"ok-host-only", fields{nil, signer}, args{pub, provisioner.SignSSHOptions{}, []provisioner.SignOption{hostTemplate, hostOptions}}, want{CertType: ssh.HostCert}, false},
156204
{"ok-opts-type-user", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "user"}, []provisioner.SignOption{userTemplate}}, want{CertType: ssh.UserCert}, false},
157205
{"ok-opts-type-host", fields{signer, signer}, args{pub, provisioner.SignSSHOptions{CertType: "host"}, []provisioner.SignOption{hostTemplate}}, want{CertType: ssh.HostCert}, false},
158206
{"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},

0 commit comments

Comments
 (0)
Please sign in to comment.