This commit is contained in:
max furman 2021-05-20 13:01:58 -07:00
parent 638766c615
commit 9bf9bf142d
8 changed files with 121 additions and 58 deletions

View file

@ -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.

37
authority/config.go Normal file
View file

@ -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

View file

@ -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.

View file

@ -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()
provs, err := h.db.GetProvisioners(ctx)
cursor, limit, err := api.ParseCursor(r)
if err != nil {
api.WriteError(w, err)
api.WriteError(w, mgmt.WrapError(mgmt.ErrorBadRequestType, err,
"error parsing cursor / limt query params"))
return
}
api.JSON(w, provs)
p, next, err := h.auth.GetProvisioners(cursor, limit)
if err != nil {
api.WriteError(w, errs.InternalServerErr(err))
return
}
api.JSON(w, &GetProvisionersResponse{
Provisioners: p,
NextCursor: next,
})
}
// CreateProvisioner creates a new prov.

View file

@ -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

View file

@ -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

View file

@ -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)
})
}

View file

@ -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 {