Add wip support for kms.

This commit is contained in:
Mariano Cano 2020-01-09 18:42:26 -08:00
parent d13754166a
commit c62526b39f
4 changed files with 102 additions and 26 deletions

View file

@ -12,6 +12,8 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/kms"
kmsapi "github.com/smallstep/certificates/kms/apiv1"
"github.com/smallstep/certificates/sshutil"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/crypto/pemutil"
@ -28,6 +30,9 @@ type Authority struct {
config *Config
rootX509Certs []*x509.Certificate
intermediateIdentity *x509util.Identity
keyManager kms.KeyManager
x509Signer crypto.Signer
x509Issuer *x509.Certificate
sshCAUserCertSignKey ssh.Signer
sshCAHostCertSignKey ssh.Signer
sshCAUserCerts []ssh.PublicKey
@ -76,6 +81,14 @@ func (a *Authority) init() error {
}
var err error
if a.keyManager == nil {
a.keyManager, err = kms.New(context.Background(), *a.config.KMS)
if err != nil {
return err
}
}
// Initialize step-ca Database if it's not already initialized with WithDB.
// If a.config.DB is nil then a simple, barebones in memory DB will be used.
if a.db == nil {
@ -107,27 +120,47 @@ func (a *Authority) init() error {
a.certificates.Store(hex.EncodeToString(sum[:]), crt)
}
// Decrypt and load intermediate public / private key pair.
if len(a.config.Password) > 0 {
a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(
a.config.IntermediateCert,
a.config.IntermediateKey,
pemutil.WithPassword([]byte(a.config.Password)),
)
if a.x509Signer == nil {
crt, err := pemutil.ReadCertificate(a.config.IntermediateCert)
if err != nil {
return err
}
} else {
a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(a.config.IntermediateCert, a.config.IntermediateKey)
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
SigningKey: a.config.IntermediateKey,
Password: a.config.Password,
})
if err != nil {
return err
}
a.x509Signer = signer
a.x509Issuer = crt
// Decrypt and load intermediate public / private key pair.
// if len(a.config.Password) > 0 {
// a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(
// a.config.IntermediateCert,
// a.config.IntermediateKey,
// pemutil.WithPassword([]byte(a.config.Password)),
// )
// if err != nil {
// return err
// }
// } else {
// a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(a.config.IntermediateCert, a.config.IntermediateKey)
// if err != nil {
// return err
// }
// }
}
// Decrypt and load SSH keys
if a.config.SSH != nil {
if a.config.SSH.HostKey != "" {
signer, err := parseCryptoSigner(a.config.SSH.HostKey, a.config.Password)
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
SigningKey: a.config.SSH.HostKey,
Password: a.config.Password,
})
// signer, err := parseCryptoSigner(a.config.SSH.HostKey, a.config.Password)
if err != nil {
return err
}
@ -140,7 +173,11 @@ func (a *Authority) init() error {
a.sshCAHostFederatedCerts = append(a.sshCAHostFederatedCerts, a.sshCAHostCertSignKey.PublicKey())
}
if a.config.SSH.UserKey != "" {
signer, err := parseCryptoSigner(a.config.SSH.UserKey, a.config.Password)
signer, err := a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
SigningKey: a.config.SSH.UserKey,
Password: a.config.Password,
})
// signer, err := parseCryptoSigner(a.config.SSH.UserKey, a.config.Password)
if err != nil {
return err
}

View file

@ -10,6 +10,7 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
kms "github.com/smallstep/certificates/kms/apiv1"
"github.com/smallstep/certificates/templates"
"github.com/smallstep/cli/crypto/tlsutil"
"github.com/smallstep/cli/crypto/x509util"
@ -54,6 +55,7 @@ type Config struct {
IntermediateKey string `json:"key"`
Address string `json:"address"`
DNSNames []string `json:"dnsNames"`
KMS *kms.Options `json:"kms,omitempty"`
SSH *SSHConfig `json:"ssh,omitempty"`
Logger json.RawMessage `json:"logger,omitempty"`
DB *db.Config `json:"db,omitempty"`
@ -179,6 +181,11 @@ func (c *Config) Validate() error {
c.TLS.Renegotiation = c.TLS.Renegotiation || DefaultTLSOptions.Renegotiation
}
// Validate KMS options, nil is ok.
if err := c.KMS.Validate(); err != nil {
return err
}
// Validate ssh: nil is ok
if err := c.SSH.Validate(); err != nil {
return err

View file

@ -2,11 +2,14 @@ package authority
import (
"context"
"crypto"
"crypto/x509"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/kms"
"github.com/smallstep/certificates/sshutil"
"golang.org/x/crypto/ssh"
)
// Option sets options to the Authority.
@ -52,3 +55,33 @@ func WithSSHCheckHost(fn func(ctx context.Context, principal string, tok string,
a.sshCheckHostFunc = fn
}
}
// WithKeyManager defines the key manager used to get and create keys, and sign
// certificates.
func WithKeyManager(k kms.KeyManager) Option {
return func(a *Authority) {
a.keyManager = k
}
}
// WithX509Signer defines the signer used to sign X509 certificates.
func WithX509Signer(crt *x509.Certificate, s crypto.Signer) Option {
return func(a *Authority) {
a.x509Issuer = crt
a.x509Signer = s
}
}
// WithSSHUserSigner defines the signer used to sign SSH user certificates.
func WithSSHUserSigner(s ssh.Signer) Option {
return func(a *Authority) {
a.sshCAUserCertSignKey = s
}
}
// WithSSHHostSigner defines the signer used to sign SSH host certificates.
func WithSSHHostSigner(s ssh.Signer) Option {
return func(a *Authority) {
a.sshCAHostCertSignKey = s
}
}

View file

@ -63,7 +63,7 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
errContext = apiCtx{"csr": csr, "signOptions": signOpts}
mods = []x509util.WithOption{withDefaultASN1DN(a.config.AuthorityConfig.Template)}
certValidators = []provisioner.CertificateValidator{}
issIdentity = a.intermediateIdentity
// issIdentity = a.intermediateIdentity
)
// Set backdate with the configured value
@ -90,7 +90,7 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
http.StatusBadRequest, errContext}
}
leaf, err := x509util.NewLeafProfileWithCSR(csr, issIdentity.Crt, issIdentity.Key, mods...)
leaf, err := x509util.NewLeafProfileWithCSR(csr, a.x509Issuer, a.x509Signer, mods...)
if err != nil {
return nil, &apiError{errors.Wrapf(err, "sign"), http.StatusInternalServerError, errContext}
}
@ -113,11 +113,11 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
http.StatusInternalServerError, errContext}
}
caCert, err := x509.ParseCertificate(issIdentity.Crt.Raw)
if err != nil {
return nil, &apiError{errors.Wrap(err, "sign: error parsing intermediate certificate"),
http.StatusInternalServerError, errContext}
}
// caCert, err := x509.ParseCertificate(a.x509SignerCert.Raw)
// if err != nil {
// return nil, &apiError{errors.Wrap(err, "sign: error parsing intermediate certificate"),
// http.StatusInternalServerError, errContext}
// }
if err = a.db.StoreCertificate(serverCert); err != nil {
if err != db.ErrNotImplemented {
@ -126,7 +126,7 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
}
}
return []*x509.Certificate{serverCert, caCert}, nil
return []*x509.Certificate{serverCert, a.x509Issuer}, nil
}
// Renew creates a new Certificate identical to the old certificate, except
@ -138,7 +138,7 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
}
// Issuer
issIdentity := a.intermediateIdentity
// issIdentity := a.intermediateIdentity
// Durations
backdate := a.config.AuthorityConfig.Backdate.Duration
@ -147,7 +147,7 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
newCert := &x509.Certificate{
PublicKey: oldCert.PublicKey,
Issuer: issIdentity.Crt.Subject,
Issuer: a.x509Issuer.Subject,
Subject: oldCert.Subject,
NotBefore: now.Add(-1 * backdate),
NotAfter: now.Add(duration - backdate),
@ -187,8 +187,7 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
}
}
leaf, err := x509util.NewLeafProfileWithTemplate(newCert,
issIdentity.Crt, issIdentity.Key)
leaf, err := x509util.NewLeafProfileWithTemplate(newCert, a.x509Issuer, a.x509Signer)
if err != nil {
return nil, &apiError{err, http.StatusInternalServerError, apiCtx{}}
}
@ -203,7 +202,7 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
return nil, &apiError{errors.Wrap(err, "error parsing new server certificate"),
http.StatusInternalServerError, apiCtx{}}
}
caCert, err := x509.ParseCertificate(issIdentity.Crt.Raw)
caCert, err := x509.ParseCertificate(a.x509Issuer.Raw)
if err != nil {
return nil, &apiError{errors.Wrap(err, "error parsing intermediate certificate"),
http.StatusInternalServerError, apiCtx{}}
@ -327,7 +326,7 @@ func (a *Authority) Revoke(ctx context.Context, opts *RevokeOptions) error {
// GetTLSCertificate creates a new leaf certificate to be used by the CA HTTPS server.
func (a *Authority) GetTLSCertificate() (*tls.Certificate, error) {
profile, err := x509util.NewLeafProfile("Step Online CA",
a.intermediateIdentity.Crt, a.intermediateIdentity.Key,
a.x509Issuer, a.x509Signer,
x509util.WithHosts(strings.Join(a.config.DNSNames, ",")))
if err != nil {
return nil, err
@ -350,7 +349,7 @@ func (a *Authority) GetTLSCertificate() (*tls.Certificate, error) {
// Load the x509 key pair (combining server and intermediate blocks)
// to a tls.Certificate.
intermediatePEM, err := pemutil.Serialize(a.intermediateIdentity.Crt)
intermediatePEM, err := pemutil.Serialize(a.x509Issuer)
if err != nil {
return nil, err
}