forked from TrueCloudLab/certificates
Allow to use custom SSH user/host key files.
This commit is contained in:
parent
00ebee870b
commit
004ea12212
4 changed files with 73 additions and 15 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/db"
|
||||
"github.com/smallstep/cli/crypto/pemutil"
|
||||
|
@ -120,8 +121,21 @@ func (a *Authority) init() error {
|
|||
}
|
||||
}
|
||||
|
||||
a.sshCAHostCertSignKey = a.intermediateIdentity.Key.(crypto.Signer)
|
||||
a.sshCAUserCertSignKey = a.intermediateIdentity.Key.(crypto.Signer)
|
||||
// Decrypt and load SSH keys
|
||||
if a.config.SSH != nil {
|
||||
if a.config.SSH.HostKey != "" {
|
||||
a.sshCAHostCertSignKey, err = parseCryptoSigner(a.config.SSH.HostKey, a.config.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if a.config.SSH.UserKey != "" {
|
||||
a.sshCAUserCertSignKey, err = parseCryptoSigner(a.config.SSH.UserKey, a.config.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store all the provisioners
|
||||
for _, p := range a.config.AuthorityConfig.Provisioners {
|
||||
|
@ -149,3 +163,19 @@ func (a *Authority) GetDatabase() db.AuthDB {
|
|||
func (a *Authority) Shutdown() error {
|
||||
return a.db.Shutdown()
|
||||
}
|
||||
|
||||
func parseCryptoSigner(filename, password string) (crypto.Signer, error) {
|
||||
var opts []pemutil.Options
|
||||
if password != "" {
|
||||
opts = append(opts, pemutil.WithPassword([]byte(password)))
|
||||
}
|
||||
key, err := pemutil.Read(filename, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signer, ok := key.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("key %s of type %T cannot be used for signing operations", filename, key)
|
||||
}
|
||||
return signer, nil
|
||||
}
|
||||
|
|
|
@ -78,20 +78,13 @@ func (a *Authority) authorizeToken(ott string) (provisioner.Interface, error) {
|
|||
func (a *Authority) Authorize(ctx context.Context, ott string) ([]provisioner.SignOption, error) {
|
||||
var errContext = apiCtx{"ott": ott}
|
||||
switch m := provisioner.MethodFromContext(ctx); m {
|
||||
case provisioner.SignMethod, provisioner.SignSSHMethod:
|
||||
p, err := a.authorizeToken(ott)
|
||||
if err != nil {
|
||||
return nil, &apiError{errors.Wrap(err, "authorizeSign"), http.StatusUnauthorized, errContext}
|
||||
case provisioner.SignMethod:
|
||||
return a.authorizeSign(ctx, ott)
|
||||
case provisioner.SignSSHMethod:
|
||||
if a.sshCAHostCertSignKey == nil && a.sshCAUserCertSignKey == nil {
|
||||
return nil, &apiError{errors.New("authorize: ssh signing is not enabled"), http.StatusNotImplemented, errContext}
|
||||
}
|
||||
|
||||
// Call the provisioner AuthorizeSign method to apply provisioner specific
|
||||
// auth claims and get the signing options.
|
||||
opts, err := p.AuthorizeSign(ctx, ott)
|
||||
if err != nil {
|
||||
return nil, &apiError{errors.Wrap(err, "authorizeSign"), http.StatusUnauthorized, errContext}
|
||||
}
|
||||
|
||||
return opts, nil
|
||||
return a.authorizeSign(ctx, ott)
|
||||
case provisioner.RevokeMethod:
|
||||
return nil, &apiError{errors.New("authorize: revoke method is not supported"), http.StatusInternalServerError, errContext}
|
||||
default:
|
||||
|
@ -99,6 +92,22 @@ func (a *Authority) Authorize(ctx context.Context, ott string) ([]provisioner.Si
|
|||
}
|
||||
}
|
||||
|
||||
// authorizeSign loads the provisioner from the token, checks that it has not
|
||||
// been used again and calls the provisioner AuthorizeSign method. returns a
|
||||
// list of methods to apply to the signing flow.
|
||||
func (a *Authority) authorizeSign(ctx context.Context, ott string) ([]provisioner.SignOption, error) {
|
||||
var errContext = apiCtx{"ott": ott}
|
||||
p, err := a.authorizeToken(ott)
|
||||
if err != nil {
|
||||
return nil, &apiError{errors.Wrap(err, "authorizeSign"), http.StatusUnauthorized, errContext}
|
||||
}
|
||||
opts, err := p.AuthorizeSign(ctx, ott)
|
||||
if err != nil {
|
||||
return nil, &apiError{errors.Wrap(err, "authorizeSign"), http.StatusUnauthorized, errContext}
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// AuthorizeSign authorizes a signature request by validating and authenticating
|
||||
// a OTT that must be sent w/ the request.
|
||||
func (a *Authority) AuthorizeSign(ott string) ([]provisioner.SignOption, error) {
|
||||
|
|
|
@ -50,6 +50,7 @@ type Config struct {
|
|||
IntermediateKey string `json:"key"`
|
||||
Address string `json:"address"`
|
||||
DNSNames []string `json:"dnsNames"`
|
||||
SSH *SSHConfig `json:"ssh,omitempty"`
|
||||
Logger json.RawMessage `json:"logger,omitempty"`
|
||||
DB *db.Config `json:"db,omitempty"`
|
||||
Monitoring json.RawMessage `json:"monitoring,omitempty"`
|
||||
|
@ -98,6 +99,12 @@ func (c *AuthConfig) Validate(audiences provisioner.Audiences) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SSHConfig contains the user and host keys.
|
||||
type SSHConfig struct {
|
||||
HostKey string `json:"hostKey"`
|
||||
UserKey string `json:"userKey"`
|
||||
}
|
||||
|
||||
// LoadConfiguration parses the given filename in JSON format and returns the
|
||||
// configuration struct.
|
||||
func LoadConfiguration(filename string) (*Config, error) {
|
||||
|
|
|
@ -81,8 +81,20 @@ func (a *Authority) SignSSH(key ssh.PublicKey, opts provisioner.SSHOptions, sign
|
|||
var signer ssh.Signer
|
||||
switch cert.CertType {
|
||||
case ssh.UserCert:
|
||||
if a.sshCAUserCertSignKey == nil {
|
||||
return nil, &apiError{
|
||||
err: errors.New("signSSH: user certificate signing is not enabled"),
|
||||
code: http.StatusNotImplemented,
|
||||
}
|
||||
}
|
||||
signer, err = ssh.NewSignerFromSigner(a.sshCAUserCertSignKey)
|
||||
case ssh.HostCert:
|
||||
if a.sshCAHostCertSignKey == nil {
|
||||
return nil, &apiError{
|
||||
err: errors.New("signSSH: host certificate signing is not enabled"),
|
||||
code: http.StatusNotImplemented,
|
||||
}
|
||||
}
|
||||
signer, err = ssh.NewSignerFromSigner(a.sshCAHostCertSignKey)
|
||||
default:
|
||||
return nil, &apiError{
|
||||
|
|
Loading…
Reference in a new issue