This commit is contained in:
max furman 2021-05-26 14:55:31 -07:00
parent 01a4460812
commit 94ba057f01
5 changed files with 77 additions and 21 deletions

View file

@ -130,6 +130,7 @@ func NewEmbedded(opts ...Option) (*Authority, error) {
return a, nil return a, nil
} }
// ReloadAuthConfig reloads dynamic fields of the AuthConfig.
func (a *Authority) ReloadAuthConfig(ctx context.Context) error { func (a *Authority) ReloadAuthConfig(ctx context.Context) error {
provs, err := a.adminDB.GetProvisioners(ctx) provs, err := a.adminDB.GetProvisioners(ctx)
if err != nil { if err != nil {
@ -218,14 +219,20 @@ func (a *Authority) init() error {
provs, err := a.adminDB.GetProvisioners(context.Background()) provs, err := a.adminDB.GetProvisioners(context.Background())
if err != nil { if err != nil {
return err return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority")
} }
if len(provs) == 0 { if len(provs) == 0 {
// Create First Provisioner // Create First Provisioner
prov, err := mgmt.CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password) prov, err := mgmt.CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password)
if err != nil { if err != nil {
return err return mgmt.WrapErrorISE(err, "error creating first provisioner")
} }
certProv, err := provisionerToCertificates(prov)
if err != nil {
return mgmt.WrapErrorISE(err, "error converting provisioner to certificates type")
}
a.config.AuthorityConfig.Provisioners = []provisioner.Interface{certProv}
// Create First Admin // Create First Admin
adm := &linkedca.Admin{ adm := &linkedca.Admin{
ProvisionerId: prov.Id, ProvisionerId: prov.Id,
@ -238,13 +245,9 @@ func (a *Authority) init() error {
} }
a.config.AuthorityConfig.Admins = []*linkedca.Admin{adm} a.config.AuthorityConfig.Admins = []*linkedca.Admin{adm}
} else { } else {
provs, err := a.adminDB.GetProvisioners(context.Background())
if err != nil {
return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority")
}
a.config.AuthorityConfig.Provisioners, err = provisionerListToCertificates(provs) a.config.AuthorityConfig.Provisioners, err = provisionerListToCertificates(provs)
if err != nil { if err != nil {
return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates") return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates type")
} }
a.config.AuthorityConfig.Admins, err = a.adminDB.GetAdmins(context.Background()) a.config.AuthorityConfig.Admins, err = a.adminDB.GetAdmins(context.Background())
if err != nil { if err != nil {

View file

@ -151,7 +151,7 @@ func (db *DB) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner)
return errors.Wrap(err, "error generating random id for provisioner") return errors.Wrap(err, "error generating random id for provisioner")
} }
details, err := json.Marshal(prov.Details) details, err := json.Marshal(prov.Details.GetData())
if err != nil { if err != nil {
return mgmt.WrapErrorISE(err, "error marshaling details when creating provisioner %s", prov.Name) return mgmt.WrapErrorISE(err, "error marshaling details when creating provisioner %s", prov.Name)
} }

View file

@ -96,7 +96,7 @@ func CreateFirstProvisioner(ctx context.Context, db DB, password string) (*linke
return nil, WrapErrorISE(err, "error serializing JWE") return nil, WrapErrorISE(err, "error serializing JWE")
} }
return &linkedca.Provisioner{ p := &linkedca.Provisioner{
Name: "Admin JWK", Name: "Admin JWK",
Type: linkedca.Provisioner_JWK, Type: linkedca.Provisioner_JWK,
Claims: NewDefaultClaims(), Claims: NewDefaultClaims(),
@ -108,5 +108,9 @@ func CreateFirstProvisioner(ctx context.Context, db DB, password string) (*linke
}, },
}, },
}, },
}, nil }
if err := db.CreateProvisioner(ctx, p); err != nil {
return nil, WrapErrorISE(err, "error creating provisioner")
}
return p, nil
} }

View file

@ -87,6 +87,7 @@ func provisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
switch d := details.(type) { switch d := details.(type) {
case *linkedca.ProvisionerDetails_JWK: case *linkedca.ProvisionerDetails_JWK:
fmt.Printf("d = %+v\n", d)
jwk := new(jose.JSONWebKey) jwk := new(jose.JSONWebKey)
if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil { if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil {
return nil, err return nil, err

View file

@ -12,6 +12,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/mgmt" "github.com/smallstep/certificates/authority/mgmt"
mgmtAPI "github.com/smallstep/certificates/authority/mgmt/api" mgmtAPI "github.com/smallstep/certificates/authority/mgmt/api"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/errs" "github.com/smallstep/certificates/errs"
"github.com/smallstep/certificates/linkedca" "github.com/smallstep/certificates/linkedca"
) )
@ -92,7 +93,7 @@ retry:
return adm, nil return adm, nil
} }
// AdminOption is the type of options passed to the Provisioner method. // AdminOption is the type of options passed to the Admin method.
type AdminOption func(o *adminOptions) error type AdminOption func(o *adminOptions) error
type adminOptions struct { type adminOptions struct {
@ -136,8 +137,8 @@ func WithAdminLimit(limit int) AdminOption {
} }
} }
// GetAdmins performs the GET /admin/admins request to the CA. // GetAdminsPaginate returns a page from the the GET /admin/admins request to the CA.
func (c *AdminClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) { func (c *AdminClient) GetAdminsPaginate(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) {
var retried bool var retried bool
o := new(adminOptions) o := new(adminOptions)
if err := o.apply(opts); err != nil { if err := o.apply(opts); err != nil {
@ -166,6 +167,26 @@ retry:
return body, nil return body, nil
} }
// GetAdmins returns all admins from the GET /admin/admins request to the CA.
func (c *AdminClient) GetAdmins(opts ...AdminOption) ([]*linkedca.Admin, error) {
var (
cursor = ""
admins = []*linkedca.Admin{}
)
for {
resp, err := c.GetAdminsPaginate(WithAdminCursor(cursor), WithAdminLimit(100))
if err != nil {
return nil, err
}
admins = append(admins, resp.Admins...)
if resp.NextCursor == "" {
return admins, nil
}
cursor = resp.NextCursor
}
return admins, nil
}
// CreateAdmin performs the POST /admin/admins request to the CA. // CreateAdmin performs the POST /admin/admins request to the CA.
func (c *AdminClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*linkedca.Admin, error) { func (c *AdminClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*linkedca.Admin, error) {
var retried bool var retried bool
@ -247,8 +268,8 @@ retry:
return adm, nil return adm, nil
} }
// GetProvisioner performs the GET /admin/provisioners/{name} request to the CA. // GetProvisionerByName performs the GET /admin/provisioners/{name} request to the CA.
func (c *AdminClient) GetProvisioner(name string) (*linkedca.Provisioner, error) { func (c *AdminClient) GetProvisionerByName(name string) (*linkedca.Provisioner, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", name)}) u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", name)})
retry: retry:
@ -270,10 +291,17 @@ retry:
return prov, nil return prov, nil
} }
// GetProvisioners performs the GET /admin/provisioners request to the CA. // GetProvisionersPaginate performs the GET /admin/provisioners request to the CA.
func (c *AdminClient) GetProvisioners() ([]*linkedca.Provisioner, error) { func (c *AdminClient) GetProvisionersPaginate(opts ...ProvisionerOption) (*mgmtAPI.GetProvisionersResponse, error) {
var retried bool var retried bool
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"}) o := new(provisionerOptions)
if err := o.apply(opts); err != nil {
return nil, err
}
u := c.endpoint.ResolveReference(&url.URL{
Path: "/admin/provisioners",
RawQuery: o.rawQuery(),
})
retry: retry:
resp, err := c.client.Get(u.String()) resp, err := c.client.Get(u.String())
if err != nil { if err != nil {
@ -286,11 +314,31 @@ retry:
} }
return nil, readAdminError(resp.Body) return nil, readAdminError(resp.Body)
} }
var provs = new([]*linkedca.Provisioner) var body = new(mgmtAPI.GetProvisionersResponse)
if err := readJSON(resp.Body, provs); err != nil { if err := readJSON(resp.Body, body); err != nil {
return nil, errors.Wrapf(err, "error reading %s", u) return nil, errors.Wrapf(err, "error reading %s", u)
} }
return *provs, nil return body, nil
}
// GetProvisioners returns all admins from the GET /admin/admins request to the CA.
func (c *AdminClient) GetProvisioners(opts ...AdminOption) (provisioner.List, error) {
var (
cursor = ""
provs = provisioner.List{}
)
for {
resp, err := c.GetProvisionersPaginate(WithProvisionerCursor(cursor), WithProvisionerLimit(100))
if err != nil {
return nil, err
}
provs = append(provs, resp.Provisioners...)
if resp.NextCursor == "" {
return provs, nil
}
cursor = resp.NextCursor
}
return provs, nil
} }
// RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA. // RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA.