From 9bf9bf142d250f580a125bf83f0f2a45c2eb5786 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 20 May 2021 13:01:58 -0700 Subject: [PATCH] wip --- authority/authority.go | 16 ++++++------ authority/config.go | 37 +++++++++++++++++++++++++++ authority/mgmt/api/handler.go | 4 +-- authority/mgmt/api/provisioner.go | 23 ++++++++++++++--- authority/mgmt/provisioner.go | 36 +++++++++++++------------- authority/options.go | 9 +++++++ ca/ca.go | 10 ++++---- ca/mgmtClient.go | 42 +++++++++++++++---------------- 8 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 authority/config.go diff --git a/authority/authority.go b/authority/authority.go index 2772c444..e26ff22d 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -32,7 +32,7 @@ import ( // Authority implements the Certificate Authority internal interface. type Authority struct { config *config.Config - mgmtDB mgmt.DB + adminDB mgmt.DB keyManager kms.KeyManager provisioners *provisioner.Collection admins *admin.Collection @@ -130,7 +130,7 @@ func NewEmbedded(opts ...Option) (*Authority, error) { } func (a *Authority) ReloadAuthConfig() error { - mgmtAuthConfig, err := a.mgmtDB.GetAuthConfig(context.Background(), mgmt.DefaultAuthorityID) + mgmtAuthConfig, err := a.adminDB.GetAuthConfig(context.Background(), mgmt.DefaultAuthorityID) if err != nil { return mgmt.WrapErrorISE(err, "error getting authConfig from db") } @@ -204,14 +204,14 @@ func (a *Authority) init() error { // Pull AuthConfig from DB. if true { // Check if AuthConfig already exists - a.mgmtDB, err = authMgmtNosql.New(a.db.(nosql.DB), mgmt.DefaultAuthorityID) + a.adminDB, err = authMgmtNosql.New(a.db.(nosql.DB), mgmt.DefaultAuthorityID) if err != nil { return err } - mgmtAuthConfig, err := a.mgmtDB.GetAuthConfig(context.Background(), mgmt.DefaultAuthorityID) + mgmtAuthConfig, err := a.adminDB.GetAuthConfig(context.Background(), mgmt.DefaultAuthorityID) if err != nil { if k, ok := err.(*mgmt.Error); ok && k.IsType(mgmt.ErrorNotFoundType) { - mgmtAuthConfig, err = mgmt.CreateAuthority(context.Background(), a.mgmtDB, mgmt.WithDefaultAuthorityID) + mgmtAuthConfig, err = mgmt.CreateAuthority(context.Background(), a.adminDB, mgmt.WithDefaultAuthorityID) if err != nil { return mgmt.WrapErrorISE(err, "error creating authConfig") } @@ -465,9 +465,9 @@ func (a *Authority) GetDatabase() db.AuthDB { return a.db } -// GetMgmtDatabase returns the mgmt database, if one exists. -func (a *Authority) GetMgmtDatabase() mgmt.DB { - return a.mgmtDB +// GetAdminDatabase returns the mgmt database, if one exists. +func (a *Authority) GetAdminDatabase() mgmt.DB { + return a.adminDB } // GetAdminCollection returns the admin collection. diff --git a/authority/config.go b/authority/config.go new file mode 100644 index 00000000..79bdc7ff --- /dev/null +++ b/authority/config.go @@ -0,0 +1,37 @@ +package authority + +import "github.com/smallstep/certificates/authority/config" + +// Config is an alias to support older APIs. +type Config = config.Config + +// AuthConfig is an alias to support older APIs. +type AuthConfig = config.AuthConfig + +// ASN1DN is an alias to support older APIs. +type ASN1DN = config.ASN1DN + +// TLS + +// TLSOptions is an alias to support older APIs. +type TLSOptions = config.TLSOptions + +// SSH + +// SSHConfig is an alias to support older APIs. +type SSHConfig = config.SSHConfig + +// Bastion is an alias to support older APIs. +type Bastion = config.Bastion + +// HostTag is an alias to support older APIs. +type HostTag = config.HostTag + +// Host is an alias to support older APIs. +type Host = config.Host + +// SSHPublicKey is an alias to support older APIs. +type SSHPublicKey = config.SSHPublicKey + +// SSHKeys is an alias to support older APIs. +type SSHKeys = config.SSHKeys diff --git a/authority/mgmt/api/handler.go b/authority/mgmt/api/handler.go index cb52736f..11dcbd86 100644 --- a/authority/mgmt/api/handler.go +++ b/authority/mgmt/api/handler.go @@ -25,8 +25,8 @@ type Handler struct { } // NewHandler returns a new Authority Config Handler. -func NewHandler(db mgmt.DB, auth *authority.Authority) api.RouterHandler { - return &Handler{db, auth} +func NewHandler(auth *authority.Authority) api.RouterHandler { + return &Handler{auth.GetAdminDatabase(), auth} } // Route traffic and implement the Router interface. diff --git a/authority/mgmt/api/provisioner.go b/authority/mgmt/api/provisioner.go index 79ef5f74..d383a27f 100644 --- a/authority/mgmt/api/provisioner.go +++ b/authority/mgmt/api/provisioner.go @@ -9,6 +9,7 @@ import ( "github.com/smallstep/certificates/authority/mgmt" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/status" + "github.com/smallstep/certificates/errs" ) // CreateProvisionerRequest represents the body for a CreateProvisioner request. @@ -31,6 +32,12 @@ func (cpr *CreateProvisionerRequest) Validate(c *provisioner.Collection) error { return nil } +// GetProvisionersResponse is the type for GET /admin/provisioners responses. +type GetProvisionersResponse struct { + Provisioners provisioner.List `json:"provisioners"` + NextCursor string `json:"nextCursor"` +} + // UpdateProvisionerRequest represents the body for a UpdateProvisioner request. type UpdateProvisionerRequest struct { Type string `json:"type"` @@ -72,14 +79,22 @@ func (h *Handler) GetProvisioner(w http.ResponseWriter, r *http.Request) { // GetProvisioners returns all provisioners associated with the authority. func (h *Handler) GetProvisioners(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() + cursor, limit, err := api.ParseCursor(r) + if err != nil { + api.WriteError(w, mgmt.WrapError(mgmt.ErrorBadRequestType, err, + "error parsing cursor / limt query params")) + return + } - provs, err := h.db.GetProvisioners(ctx) + p, next, err := h.auth.GetProvisioners(cursor, limit) if err != nil { - api.WriteError(w, err) + api.WriteError(w, errs.InternalServerErr(err)) return } - api.JSON(w, provs) + api.JSON(w, &GetProvisionersResponse{ + Provisioners: p, + NextCursor: next, + }) } // CreateProvisioner creates a new prov. diff --git a/authority/mgmt/provisioner.go b/authority/mgmt/provisioner.go index 10f472de..ea9d0da5 100644 --- a/authority/mgmt/provisioner.go +++ b/authority/mgmt/provisioner.go @@ -60,17 +60,17 @@ func WithPassword(pass string) func(*ProvisionerCtx) { // Provisioner type. type Provisioner struct { - ID string `json:"-"` - AuthorityID string `json:"-"` - Type string `json:"type"` - Name string `json:"name"` - Claims *Claims `json:"claims"` - Details interface{} `json:"details"` - X509Template string `json:"x509Template"` - X509TemplateData []byte `json:"x509TemplateData"` - SSHTemplate string `json:"sshTemplate"` - SSHTemplateData []byte `json:"sshTemplateData"` - Status status.Type `json:"status"` + ID string `json:"-"` + AuthorityID string `json:"-"` + Type string `json:"type"` + Name string `json:"name"` + Claims *Claims `json:"claims"` + Details ProvisionerDetails `json:"details"` + X509Template string `json:"x509Template"` + X509TemplateData []byte `json:"x509TemplateData"` + SSHTemplate string `json:"sshTemplate"` + SSHTemplateData []byte `json:"sshTemplateData"` + Status status.Type `json:"status"` } func (p *Provisioner) GetOptions() *provisioner.Options { @@ -111,6 +111,8 @@ func CreateProvisioner(ctx context.Context, db DB, typ, name string, opts ...Pro return p, nil } +// ProvisionerDetails is the interface implemented by all provisioner details +// attributes. type ProvisionerDetails interface { isProvisionerDetails() } @@ -118,8 +120,8 @@ type ProvisionerDetails interface { // ProvisionerDetailsJWK represents the values required by a JWK provisioner. type ProvisionerDetailsJWK struct { Type ProvisionerType `json:"type"` - PubKey []byte `json:"pubKey"` - EncPrivKey string `json:"privKey"` + PublicKey []byte `json:"publicKey"` + PrivateKey string `json:"PrivateKey"` } // ProvisionerDetailsOIDC represents the values required by a OIDC provisioner. @@ -232,8 +234,8 @@ func createJWKDetails(pc *ProvisionerCtx) (*ProvisionerDetailsJWK, error) { return &ProvisionerDetailsJWK{ Type: ProvisionerTypeJWK, - PubKey: jwkPubBytes, - EncPrivKey: jwePrivStr, + PublicKey: jwkPubBytes, + PrivateKey: jwePrivStr, }, nil } @@ -248,7 +250,7 @@ func (p *Provisioner) ToCertificates() (provisioner.Interface, error) { switch details := p.Details.(type) { case *ProvisionerDetailsJWK: jwk := new(jose.JSONWebKey) - if err := json.Unmarshal(details.PubKey, &jwk); err != nil { + if err := json.Unmarshal(details.PublicKey, &jwk); err != nil { return nil, err } return &provisioner.JWK{ @@ -256,7 +258,7 @@ func (p *Provisioner) ToCertificates() (provisioner.Interface, error) { Type: p.Type, Name: p.Name, Key: jwk, - EncryptedKey: details.EncPrivKey, + EncryptedKey: details.PrivateKey, Claims: claims, Options: p.GetOptions(), }, nil diff --git a/authority/options.go b/authority/options.go index aaf8ffb3..cc2f64af 100644 --- a/authority/options.go +++ b/authority/options.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/mgmt" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/cas" casapi "github.com/smallstep/certificates/cas/apiv1" @@ -187,6 +188,14 @@ func WithX509FederatedBundle(pemCerts []byte) Option { } } +// WithAdminDB is an option to set the database backing the admin APIs. +func WithAdminDB(db mgmt.DB) Option { + return func(a *Authority) error { + a.adminDB = db + return nil + } +} + func readCertificateBundle(pemCerts []byte) ([]*x509.Certificate, error) { var block *pem.Block var certs []*x509.Certificate diff --git a/ca/ca.go b/ca/ca.go index ecbc55e2..d97e0ab2 100644 --- a/ca/ca.go +++ b/ca/ca.go @@ -171,11 +171,11 @@ func (ca *CA) Init(config *config.Config) (*CA, error) { acmeHandler.Route(r) }) - // MGMT Router - mgmtDB := auth.GetMgmtDatabase() - if mgmtDB != nil { - mgmtHandler := mgmtAPI.NewHandler(mgmtDB, auth) - mux.Route("/mgmt", func(r chi.Router) { + // Admin API Router + adminDB := auth.GetAdminDatabase() + if adminDB != nil { + mgmtHandler := mgmtAPI.NewHandler(auth) + mux.Route("/admin", func(r chi.Router) { mgmtHandler.Route(r) }) } diff --git a/ca/mgmtClient.go b/ca/mgmtClient.go index 7a50e369..7c4207aa 100644 --- a/ca/mgmtClient.go +++ b/ca/mgmtClient.go @@ -134,7 +134,7 @@ func WithAdminLimit(limit int) AdminOption { } } -// GetAdmins performs the GET /mgmt/admins request to the CA. +// GetAdmins performs the GET /admin/admins request to the CA. func (c *MgmtClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, error) { var retried bool o := new(adminOptions) @@ -142,7 +142,7 @@ func (c *MgmtClient) GetAdmins(opts ...AdminOption) (*mgmtAPI.GetAdminsResponse, return nil, err } u := c.endpoint.ResolveReference(&url.URL{ - Path: "/mgmt/admins", + Path: "/admin/admins", RawQuery: o.rawQuery(), }) retry: @@ -164,14 +164,14 @@ retry: return body, nil } -// CreateAdmin performs the POST /mgmt/admin request to the CA. +// CreateAdmin performs the POST /admin/admin request to the CA. func (c *MgmtClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*mgmt.Admin, error) { var retried bool body, err := json.Marshal(req) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") } - u := c.endpoint.ResolveReference(&url.URL{Path: "/mgmt/admin"}) + u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/admin"}) retry: resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body)) if err != nil { @@ -191,10 +191,10 @@ retry: return adm, nil } -// RemoveAdmin performs the DELETE /mgmt/admin/{id} request to the CA. +// RemoveAdmin performs the DELETE /admin/admin/{id} request to the CA. func (c *MgmtClient) RemoveAdmin(id string) error { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/admin", id)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)}) req, err := http.NewRequest("DELETE", u.String(), nil) if err != nil { return errors.Wrapf(err, "create DELETE %s request failed", u) @@ -214,14 +214,14 @@ retry: return nil } -// UpdateAdmin performs the PUT /mgmt/admin/{id} request to the CA. +// UpdateAdmin performs the PUT /admin/admin/{id} request to the CA. func (c *MgmtClient) UpdateAdmin(id string, uar *mgmtAPI.UpdateAdminRequest) (*admin.Admin, error) { var retried bool body, err := json.Marshal(uar) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") } - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/admin", id)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)}) req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(body)) if err != nil { return nil, errors.Wrapf(err, "create PUT %s request failed", u) @@ -245,10 +245,10 @@ retry: return adm, nil } -// GetProvisioner performs the GET /mgmt/provisioner/{id} request to the CA. -func (c *MgmtClient) GetProvisioner(id string) (*mgmt.Provisioner, error) { +// GetProvisioner performs the GET /admin/provisioner/{name} request to the CA. +func (c *MgmtClient) GetProvisioner(name string) (*mgmt.Provisioner, error) { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/provisioner", id)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", name)}) retry: resp, err := c.client.Get(u.String()) if err != nil { @@ -268,10 +268,10 @@ retry: return prov, nil } -// GetProvisioners performs the GET /mgmt/provisioners request to the CA. +// GetProvisioners performs the GET /admin/provisioners request to the CA. func (c *MgmtClient) GetProvisioners() ([]*mgmt.Provisioner, error) { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: "/mgmt/provisioners"}) + u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"}) retry: resp, err := c.client.Get(u.String()) if err != nil { @@ -291,10 +291,10 @@ retry: return *provs, nil } -// RemoveProvisioner performs the DELETE /mgmt/provisioner/{name} request to the CA. +// RemoveProvisioner performs the DELETE /admin/provisioner/{name} request to the CA. func (c *MgmtClient) RemoveProvisioner(name string) error { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/provisioner", name)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", name)}) req, err := http.NewRequest("DELETE", u.String(), nil) if err != nil { return errors.Wrapf(err, "create DELETE %s request failed", u) @@ -314,14 +314,14 @@ retry: return nil } -// CreateProvisioner performs the POST /mgmt/provisioner request to the CA. +// CreateProvisioner performs the POST /admin/provisioner request to the CA. func (c *MgmtClient) CreateProvisioner(req *mgmtAPI.CreateProvisionerRequest) (*mgmt.Provisioner, error) { var retried bool body, err := json.Marshal(req) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") } - u := c.endpoint.ResolveReference(&url.URL{Path: "/mgmt/provisioner"}) + u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioner"}) retry: resp, err := c.client.Post(u.String(), "application/json", bytes.NewReader(body)) if err != nil { @@ -341,14 +341,14 @@ retry: return prov, nil } -// UpdateProvisioner performs the PUT /mgmt/provisioner/{id} request to the CA. +// UpdateProvisioner performs the PUT /admin/provisioner/{id} request to the CA. func (c *MgmtClient) UpdateProvisioner(id string, upr *mgmtAPI.UpdateProvisionerRequest) (*mgmt.Provisioner, error) { var retried bool body, err := json.Marshal(upr) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request") } - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/provisioner", id)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioner", id)}) req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(body)) if err != nil { return nil, errors.Wrapf(err, "create PUT %s request failed", u) @@ -372,10 +372,10 @@ retry: return prov, nil } -// GetAuthConfig performs the GET /mgmt/authconfig/{id} request to the CA. +// GetAuthConfig performs the GET /admin/authconfig/{id} request to the CA. func (c *MgmtClient) GetAuthConfig(id string) (*mgmt.AuthConfig, error) { var retried bool - u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/mgmt/authconfig", id)}) + u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/authconfig", id)}) retry: resp, err := c.client.Get(u.String()) if err != nil {