forked from TrueCloudLab/certificates
Merge pull request #863 from smallstep/feat/linkedra
Linked RA improvements
This commit is contained in:
commit
67abe6607e
26 changed files with 124 additions and 52 deletions
|
@ -261,6 +261,21 @@ func (a *Authority) init() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize linkedca client if necessary. On a linked RA, the issuer
|
||||||
|
// configuration might come from majordomo.
|
||||||
|
var linkedcaClient *linkedCaClient
|
||||||
|
if a.config.AuthorityConfig.EnableAdmin && a.linkedCAToken != "" && a.adminDB == nil {
|
||||||
|
linkedcaClient, err = newLinkedCAClient(a.linkedCAToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// If authorityId is configured make sure it matches the one in the token
|
||||||
|
if id := a.config.AuthorityConfig.AuthorityID; id != "" && !strings.EqualFold(id, linkedcaClient.authorityID) {
|
||||||
|
return errors.New("error initializing linkedca: token authority and configured authority do not match")
|
||||||
|
}
|
||||||
|
linkedcaClient.Run()
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the X.509 CA Service if it has not been set in the options.
|
// Initialize the X.509 CA Service if it has not been set in the options.
|
||||||
if a.x509CAService == nil {
|
if a.x509CAService == nil {
|
||||||
var options casapi.Options
|
var options casapi.Options
|
||||||
|
@ -268,6 +283,22 @@ func (a *Authority) init() error {
|
||||||
options = *a.config.AuthorityConfig.Options
|
options = *a.config.AuthorityConfig.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure linked RA
|
||||||
|
if linkedcaClient != nil && options.CertificateAuthority == "" {
|
||||||
|
conf, err := linkedcaClient.GetConfiguration(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if conf.RaConfig != nil {
|
||||||
|
options.CertificateAuthority = conf.RaConfig.CaUrl
|
||||||
|
options.CertificateAuthorityFingerprint = conf.RaConfig.Fingerprint
|
||||||
|
options.CertificateIssuer = &casapi.CertificateIssuer{
|
||||||
|
Type: conf.RaConfig.Provisioner.Type.String(),
|
||||||
|
Provisioner: conf.RaConfig.Provisioner.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the issuer password if passed in the flags.
|
// Set the issuer password if passed in the flags.
|
||||||
if options.CertificateIssuer != nil && a.issuerPassword != nil {
|
if options.CertificateIssuer != nil && a.issuerPassword != nil {
|
||||||
options.CertificateIssuer.Password = string(a.issuerPassword)
|
options.CertificateIssuer.Password = string(a.issuerPassword)
|
||||||
|
@ -487,24 +518,13 @@ func (a *Authority) init() error {
|
||||||
// Initialize step-ca Admin Database if it's not already initialized using
|
// Initialize step-ca Admin Database if it's not already initialized using
|
||||||
// WithAdminDB.
|
// WithAdminDB.
|
||||||
if a.adminDB == nil {
|
if a.adminDB == nil {
|
||||||
if a.linkedCAToken == "" {
|
if linkedcaClient != nil {
|
||||||
// Check if AuthConfig already exists
|
a.adminDB = linkedcaClient
|
||||||
|
} else {
|
||||||
a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID)
|
a.adminDB, err = adminDBNosql.New(a.db.(nosql.DB), admin.DefaultAuthorityID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Use the linkedca client as the admindb.
|
|
||||||
client, err := newLinkedCAClient(a.linkedCAToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// If authorityId is configured make sure it matches the one in the token
|
|
||||||
if id := a.config.AuthorityConfig.AuthorityID; id != "" && !strings.EqualFold(id, client.authorityID) {
|
|
||||||
return errors.New("error initializing linkedca: token authority and configured authority do not match")
|
|
||||||
}
|
|
||||||
client.Run()
|
|
||||||
a.adminDB = client
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,7 +491,7 @@ func TestAuthority_authorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
if assert.Nil(t, tc.err) {
|
||||||
assert.Len(t, 7, got)
|
assert.Len(t, 8, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/db"
|
"github.com/smallstep/certificates/db"
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
"go.step.sm/crypto/keyutil"
|
"go.step.sm/crypto/keyutil"
|
||||||
|
@ -151,13 +152,21 @@ func (c *linkedCaClient) GetProvisioner(ctx context.Context, id string) (*linked
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linkedCaClient) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
|
func (c *linkedCaClient) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
|
||||||
|
resp, err := c.GetConfiguration(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Provisioners, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *linkedCaClient) GetConfiguration(ctx context.Context) (*linkedca.ConfigurationResponse, error) {
|
||||||
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
|
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
|
||||||
AuthorityId: c.authorityID,
|
AuthorityId: c.authorityID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "error getting provisioners")
|
return nil, errors.Wrap(err, "error getting configuration")
|
||||||
}
|
}
|
||||||
return resp.Provisioners, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linkedCaClient) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
|
func (c *linkedCaClient) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
|
||||||
|
@ -204,11 +213,9 @@ func (c *linkedCaClient) GetAdmin(ctx context.Context, id string) (*linkedca.Adm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linkedCaClient) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
|
func (c *linkedCaClient) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
|
||||||
resp, err := c.client.GetConfiguration(ctx, &linkedca.ConfigurationRequest{
|
resp, err := c.GetConfiguration(ctx)
|
||||||
AuthorityId: c.authorityID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "error getting admins")
|
return nil, err
|
||||||
}
|
}
|
||||||
return resp.Admins, nil
|
return resp.Admins, nil
|
||||||
}
|
}
|
||||||
|
@ -228,12 +235,13 @@ func (c *linkedCaClient) DeleteAdmin(ctx context.Context, id string) error {
|
||||||
return errors.Wrap(err, "error deleting admin")
|
return errors.Wrap(err, "error deleting admin")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *linkedCaClient) StoreCertificateChain(fullchain ...*x509.Certificate) error {
|
func (c *linkedCaClient) StoreCertificateChain(prov provisioner.Interface, fullchain ...*x509.Certificate) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
_, err := c.client.PostCertificate(ctx, &linkedca.CertificateRequest{
|
_, err := c.client.PostCertificate(ctx, &linkedca.CertificateRequest{
|
||||||
PemCertificate: serializeCertificateChain(fullchain[0]),
|
PemCertificate: serializeCertificateChain(fullchain[0]),
|
||||||
PemCertificateChain: serializeCertificateChain(fullchain[1:]...),
|
PemCertificateChain: serializeCertificateChain(fullchain[1:]...),
|
||||||
|
Provisioner: createProvisionerIdentity(prov),
|
||||||
})
|
})
|
||||||
return errors.Wrap(err, "error posting certificate")
|
return errors.Wrap(err, "error posting certificate")
|
||||||
}
|
}
|
||||||
|
@ -310,6 +318,17 @@ func (c *linkedCaClient) IsSSHRevoked(serial string) (bool, error) {
|
||||||
return resp.Status != linkedca.RevocationStatus_ACTIVE, nil
|
return resp.Status != linkedca.RevocationStatus_ACTIVE, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createProvisionerIdentity(prov provisioner.Interface) *linkedca.ProvisionerIdentity {
|
||||||
|
if prov == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &linkedca.ProvisionerIdentity{
|
||||||
|
Id: prov.GetID(),
|
||||||
|
Type: linkedca.Provisioner_Type(prov.GetType()),
|
||||||
|
Name: prov.GetName(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func serializeCertificate(crt *x509.Certificate) string {
|
func serializeCertificate(crt *x509.Certificate) string {
|
||||||
if crt == nil {
|
if crt == nil {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -89,6 +89,7 @@ func (p *ACME) Init(config Config) (err error) {
|
||||||
// on the resulting certificate.
|
// on the resulting certificate.
|
||||||
func (p *ACME) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
func (p *ACME) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
p,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeACME, p.Name, ""),
|
newProvisionerExtensionOption(TypeACME, p.Name, ""),
|
||||||
newForceCNOption(p.ForceCN),
|
newForceCNOption(p.ForceCN),
|
||||||
|
|
|
@ -176,9 +176,10 @@ func TestACME_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) && assert.NotNil(t, opts) {
|
if assert.Nil(t, tc.err) && assert.NotNil(t, opts) {
|
||||||
assert.Len(t, 5, opts)
|
assert.Len(t, 6, opts)
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *ACME:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeACME)
|
assert.Equals(t, v.Type, TypeACME)
|
||||||
assert.Equals(t, v.Name, tc.p.GetName())
|
assert.Equals(t, v.Name, tc.p.GetName())
|
||||||
|
|
|
@ -467,6 +467,7 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID),
|
||||||
|
|
|
@ -642,11 +642,11 @@ func TestAWS_AuthorizeSign(t *testing.T) {
|
||||||
code int
|
code int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1, "foo.local"}, 6, http.StatusOK, false},
|
{"ok", p1, args{t1, "foo.local"}, 7, http.StatusOK, false},
|
||||||
{"ok", p2, args{t2, "instance-id"}, 10, http.StatusOK, false},
|
{"ok", p2, args{t2, "instance-id"}, 11, http.StatusOK, false},
|
||||||
{"ok", p2, args{t2Hostname, "ip-127-0-0-1.us-west-1.compute.internal"}, 10, http.StatusOK, false},
|
{"ok", p2, args{t2Hostname, "ip-127-0-0-1.us-west-1.compute.internal"}, 11, http.StatusOK, false},
|
||||||
{"ok", p2, args{t2PrivateIP, "127.0.0.1"}, 10, http.StatusOK, false},
|
{"ok", p2, args{t2PrivateIP, "127.0.0.1"}, 11, http.StatusOK, false},
|
||||||
{"ok", p1, args{t4, "instance-id"}, 6, http.StatusOK, false},
|
{"ok", p1, args{t4, "instance-id"}, 7, http.StatusOK, false},
|
||||||
{"fail account", p3, args{token: t3}, 0, http.StatusUnauthorized, true},
|
{"fail account", p3, args{token: t3}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail token", p1, args{token: "token"}, 0, http.StatusUnauthorized, true},
|
{"fail token", p1, args{token: "token"}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail subject", p1, args{token: failSubject}, 0, http.StatusUnauthorized, true},
|
{"fail subject", p1, args{token: failSubject}, 0, http.StatusUnauthorized, true},
|
||||||
|
@ -676,6 +676,7 @@ func TestAWS_AuthorizeSign(t *testing.T) {
|
||||||
assert.Len(t, tt.wantLen, got)
|
assert.Len(t, tt.wantLen, got)
|
||||||
for _, o := range got {
|
for _, o := range got {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *AWS:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeAWS)
|
assert.Equals(t, v.Type, TypeAWS)
|
||||||
|
|
|
@ -352,6 +352,7 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID),
|
||||||
|
|
|
@ -474,11 +474,11 @@ func TestAzure_AuthorizeSign(t *testing.T) {
|
||||||
code int
|
code int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 5, http.StatusOK, false},
|
{"ok", p1, args{t1}, 6, http.StatusOK, false},
|
||||||
{"ok", p2, args{t2}, 10, http.StatusOK, false},
|
{"ok", p2, args{t2}, 11, http.StatusOK, false},
|
||||||
{"ok", p1, args{t11}, 5, http.StatusOK, false},
|
{"ok", p1, args{t11}, 6, http.StatusOK, false},
|
||||||
{"ok", p5, args{t5}, 5, http.StatusOK, false},
|
{"ok", p5, args{t5}, 6, http.StatusOK, false},
|
||||||
{"ok", p7, args{t7}, 5, http.StatusOK, false},
|
{"ok", p7, args{t7}, 6, http.StatusOK, false},
|
||||||
{"fail tenant", p3, args{t3}, 0, http.StatusUnauthorized, true},
|
{"fail tenant", p3, args{t3}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail resource group", p4, args{t4}, 0, http.StatusUnauthorized, true},
|
{"fail resource group", p4, args{t4}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail subscription", p6, args{t6}, 0, http.StatusUnauthorized, true},
|
{"fail subscription", p6, args{t6}, 0, http.StatusUnauthorized, true},
|
||||||
|
@ -505,6 +505,7 @@ func TestAzure_AuthorizeSign(t *testing.T) {
|
||||||
assert.Len(t, tt.wantLen, got)
|
assert.Len(t, tt.wantLen, got)
|
||||||
for _, o := range got {
|
for _, o := range got {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *Azure:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeAzure)
|
assert.Equals(t, v.Type, TypeAzure)
|
||||||
|
|
|
@ -262,6 +262,7 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(so,
|
return append(so,
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName),
|
||||||
|
|
|
@ -516,9 +516,9 @@ func TestGCP_AuthorizeSign(t *testing.T) {
|
||||||
code int
|
code int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", p1, args{t1}, 5, http.StatusOK, false},
|
{"ok", p1, args{t1}, 6, http.StatusOK, false},
|
||||||
{"ok", p2, args{t2}, 10, http.StatusOK, false},
|
{"ok", p2, args{t2}, 11, http.StatusOK, false},
|
||||||
{"ok", p3, args{t3}, 5, http.StatusOK, false},
|
{"ok", p3, args{t3}, 6, http.StatusOK, false},
|
||||||
{"fail token", p1, args{"token"}, 0, http.StatusUnauthorized, true},
|
{"fail token", p1, args{"token"}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail key", p1, args{failKey}, 0, http.StatusUnauthorized, true},
|
{"fail key", p1, args{failKey}, 0, http.StatusUnauthorized, true},
|
||||||
{"fail iss", p1, args{failIss}, 0, http.StatusUnauthorized, true},
|
{"fail iss", p1, args{failIss}, 0, http.StatusUnauthorized, true},
|
||||||
|
@ -548,6 +548,7 @@ func TestGCP_AuthorizeSign(t *testing.T) {
|
||||||
assert.Len(t, tt.wantLen, got)
|
assert.Len(t, tt.wantLen, got)
|
||||||
for _, o := range got {
|
for _, o := range got {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *GCP:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeGCP)
|
assert.Equals(t, v.Type, TypeGCP)
|
||||||
|
|
|
@ -170,6 +170,7 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
|
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID),
|
||||||
|
|
|
@ -297,9 +297,10 @@ func TestJWK_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if assert.NotNil(t, got) {
|
if assert.NotNil(t, got) {
|
||||||
assert.Len(t, 7, got)
|
assert.Len(t, 8, got)
|
||||||
for _, o := range got {
|
for _, o := range got {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *JWK:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeJWK)
|
assert.Equals(t, v.Type, TypeJWK)
|
||||||
|
|
|
@ -231,6 +231,7 @@ func (p *K8sSA) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeK8sSA, p.Name, ""),
|
newProvisionerExtensionOption(TypeK8sSA, p.Name, ""),
|
||||||
|
|
|
@ -283,6 +283,7 @@ func TestK8sSA_AuthorizeSign(t *testing.T) {
|
||||||
tot := 0
|
tot := 0
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *K8sSA:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeK8sSA)
|
assert.Equals(t, v.Type, TypeK8sSA)
|
||||||
|
@ -300,7 +301,7 @@ func TestK8sSA_AuthorizeSign(t *testing.T) {
|
||||||
}
|
}
|
||||||
tot++
|
tot++
|
||||||
}
|
}
|
||||||
assert.Equals(t, tot, 5)
|
assert.Equals(t, tot, 6)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,7 @@ func (p *Nebula) AuthorizeSign(ctx context.Context, token string) ([]SignOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeNebula, p.Name, ""),
|
newProvisionerExtensionOption(TypeNebula, p.Name, ""),
|
||||||
|
|
|
@ -38,7 +38,7 @@ func (p *noop) Init(config Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noop) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
func (p *noop) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
||||||
return []SignOption{}, nil
|
return []SignOption{p}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noop) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error {
|
func (p *noop) AuthorizeRenew(ctx context.Context, cert *x509.Certificate) error {
|
||||||
|
|
|
@ -24,6 +24,6 @@ func Test_noop(t *testing.T) {
|
||||||
|
|
||||||
ctx := NewContextWithMethod(context.Background(), SignMethod)
|
ctx := NewContextWithMethod(context.Background(), SignMethod)
|
||||||
sigOptions, err := p.AuthorizeSign(ctx, "foo")
|
sigOptions, err := p.AuthorizeSign(ctx, "foo")
|
||||||
assert.Equals(t, []SignOption{}, sigOptions)
|
assert.Equals(t, []SignOption{&p}, sigOptions)
|
||||||
assert.Equals(t, nil, err)
|
assert.Equals(t, nil, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,6 +345,7 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
o,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID),
|
||||||
|
|
|
@ -323,9 +323,10 @@ func TestOIDC_AuthorizeSign(t *testing.T) {
|
||||||
assert.Equals(t, sc.StatusCode(), tt.code)
|
assert.Equals(t, sc.StatusCode(), tt.code)
|
||||||
assert.Nil(t, got)
|
assert.Nil(t, got)
|
||||||
} else if assert.NotNil(t, got) {
|
} else if assert.NotNil(t, got) {
|
||||||
assert.Len(t, 5, got)
|
assert.Len(t, 6, got)
|
||||||
for _, o := range got {
|
for _, o := range got {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *OIDC:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeOIDC)
|
assert.Equals(t, v.Type, TypeOIDC)
|
||||||
|
|
|
@ -121,6 +121,7 @@ func (s *SCEP) Init(config Config) (err error) {
|
||||||
// on the resulting certificate.
|
// on the resulting certificate.
|
||||||
func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
s,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeSCEP, s.Name, ""),
|
newProvisionerExtensionOption(TypeSCEP, s.Name, ""),
|
||||||
newForceCNOption(s.ForceCN),
|
newForceCNOption(s.ForceCN),
|
||||||
|
|
|
@ -220,6 +220,7 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
|
||||||
}
|
}
|
||||||
|
|
||||||
return []SignOption{
|
return []SignOption{
|
||||||
|
p,
|
||||||
templateOptions,
|
templateOptions,
|
||||||
// modifiers / withOptions
|
// modifiers / withOptions
|
||||||
newProvisionerExtensionOption(TypeX5C, p.Name, ""),
|
newProvisionerExtensionOption(TypeX5C, p.Name, ""),
|
||||||
|
|
|
@ -468,9 +468,10 @@ func TestX5C_AuthorizeSign(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
if assert.Nil(t, tc.err) {
|
if assert.Nil(t, tc.err) {
|
||||||
if assert.NotNil(t, opts) {
|
if assert.NotNil(t, opts) {
|
||||||
assert.Equals(t, len(opts), 7)
|
assert.Equals(t, len(opts), 8)
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
switch v := o.(type) {
|
switch v := o.(type) {
|
||||||
|
case *X5C:
|
||||||
case certificateOptionsFunc:
|
case certificateOptionsFunc:
|
||||||
case *provisionerExtensionOption:
|
case *provisionerExtensionOption:
|
||||||
assert.Equals(t, v.Type, TypeX5C)
|
assert.Equals(t, v.Type, TypeX5C)
|
||||||
|
|
|
@ -89,8 +89,13 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Sign
|
||||||
// Set backdate with the configured value
|
// Set backdate with the configured value
|
||||||
signOpts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
signOpts.Backdate = a.config.AuthorityConfig.Backdate.Duration
|
||||||
|
|
||||||
|
var prov provisioner.Interface
|
||||||
for _, op := range extraOpts {
|
for _, op := range extraOpts {
|
||||||
switch k := op.(type) {
|
switch k := op.(type) {
|
||||||
|
// Capture current provisioner
|
||||||
|
case provisioner.Interface:
|
||||||
|
prov = k
|
||||||
|
|
||||||
// Adds new options to NewCertificate
|
// Adds new options to NewCertificate
|
||||||
case provisioner.CertificateOptions:
|
case provisioner.CertificateOptions:
|
||||||
certOptions = append(certOptions, k.Options(signOpts)...)
|
certOptions = append(certOptions, k.Options(signOpts)...)
|
||||||
|
@ -204,7 +209,7 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Sign
|
||||||
}
|
}
|
||||||
|
|
||||||
fullchain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...)
|
fullchain := append([]*x509.Certificate{resp.Certificate}, resp.CertificateChain...)
|
||||||
if err = a.storeCertificate(fullchain); err != nil {
|
if err = a.storeCertificate(prov, fullchain); err != nil {
|
||||||
if err != db.ErrNotImplemented {
|
if err != db.ErrNotImplemented {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err,
|
return nil, errs.Wrap(http.StatusInternalServerError, err,
|
||||||
"authority.Sign; error storing certificate in db", opts...)
|
"authority.Sign; error storing certificate in db", opts...)
|
||||||
|
@ -325,19 +330,28 @@ func (a *Authority) Rekey(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x5
|
||||||
// TODO: at some point we should replace the db.AuthDB interface to implement
|
// TODO: at some point we should replace the db.AuthDB interface to implement
|
||||||
// `StoreCertificate(...*x509.Certificate) error` instead of just
|
// `StoreCertificate(...*x509.Certificate) error` instead of just
|
||||||
// `StoreCertificate(*x509.Certificate) error`.
|
// `StoreCertificate(*x509.Certificate) error`.
|
||||||
func (a *Authority) storeCertificate(fullchain []*x509.Certificate) error {
|
func (a *Authority) storeCertificate(prov provisioner.Interface, fullchain []*x509.Certificate) error {
|
||||||
|
type linkedChainStorer interface {
|
||||||
|
StoreCertificateChain(provisioner.Interface, ...*x509.Certificate) error
|
||||||
|
}
|
||||||
type certificateChainStorer interface {
|
type certificateChainStorer interface {
|
||||||
StoreCertificateChain(...*x509.Certificate) error
|
StoreCertificateChain(...*x509.Certificate) error
|
||||||
}
|
}
|
||||||
// Store certificate in linkedca
|
// Store certificate in linkedca
|
||||||
if s, ok := a.adminDB.(certificateChainStorer); ok {
|
switch s := a.adminDB.(type) {
|
||||||
|
case linkedChainStorer:
|
||||||
|
return s.StoreCertificateChain(prov, fullchain...)
|
||||||
|
case certificateChainStorer:
|
||||||
return s.StoreCertificateChain(fullchain...)
|
return s.StoreCertificateChain(fullchain...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store certificate in local db
|
// Store certificate in local db
|
||||||
if s, ok := a.db.(certificateChainStorer); ok {
|
switch s := a.db.(type) {
|
||||||
|
case certificateChainStorer:
|
||||||
return s.StoreCertificateChain(fullchain...)
|
return s.StoreCertificateChain(fullchain...)
|
||||||
|
default:
|
||||||
|
return a.db.StoreCertificate(fullchain[0])
|
||||||
}
|
}
|
||||||
return a.db.StoreCertificate(fullchain[0])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// storeRenewedCertificate allows to use an extension of the db.AuthDB interface
|
// storeRenewedCertificate allows to use an extension of the db.AuthDB interface
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -33,12 +33,12 @@ require (
|
||||||
github.com/slackhq/nebula v1.5.2
|
github.com/slackhq/nebula v1.5.2
|
||||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
|
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
|
||||||
github.com/smallstep/nosql v0.4.0
|
github.com/smallstep/nosql v0.4.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.1
|
||||||
github.com/urfave/cli v1.22.4
|
github.com/urfave/cli v1.22.4
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
||||||
go.step.sm/cli-utils v0.7.0
|
go.step.sm/cli-utils v0.7.0
|
||||||
go.step.sm/crypto v0.16.1
|
go.step.sm/crypto v0.16.1
|
||||||
go.step.sm/linkedca v0.11.0
|
go.step.sm/linkedca v0.12.0
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||||
google.golang.org/api v0.70.0
|
google.golang.org/api v0.70.0
|
||||||
|
|
7
go.sum
7
go.sum
|
@ -664,8 +664,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
|
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
|
||||||
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
@ -710,8 +711,8 @@ go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/
|
||||||
go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0=
|
||||||
go.step.sm/crypto v0.16.1 h1:4mnZk21cSxyMGxsEpJwZKKvJvDu1PN09UVrWWFNUBdk=
|
go.step.sm/crypto v0.16.1 h1:4mnZk21cSxyMGxsEpJwZKKvJvDu1PN09UVrWWFNUBdk=
|
||||||
go.step.sm/crypto v0.16.1/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g=
|
go.step.sm/crypto v0.16.1/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g=
|
||||||
go.step.sm/linkedca v0.11.0 h1:jkG5XDQz9VSz2PH+cGjDvJTwiIziN0SWExTnicWpb8o=
|
go.step.sm/linkedca v0.12.0 h1:FA18uJO5P6W2pklcezMs+w+N3dVbpKEE1LP9HLsJgg4=
|
||||||
go.step.sm/linkedca v0.11.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo=
|
go.step.sm/linkedca v0.12.0/go.mod h1:W59ucS4vFpuR0g4PtkGbbtXAwxbDEnNCg+ovkej1ANM=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
|
|
Loading…
Reference in a new issue