forked from TrueCloudLab/certificates
Add wip support for kms.
This commit is contained in:
parent
d13754166a
commit
c62526b39f
4 changed files with 102 additions and 26 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue