forked from TrueCloudLab/certificates
wip
This commit is contained in:
parent
1726076ea2
commit
01a4460812
10 changed files with 377 additions and 429 deletions
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/cas"
|
"github.com/smallstep/certificates/cas"
|
||||||
|
"github.com/smallstep/certificates/linkedca"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
"github.com/smallstep/certificates/authority/admin"
|
||||||
|
@ -129,15 +130,18 @@ func NewEmbedded(opts ...Option) (*Authority, error) {
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Authority) ReloadAuthConfig() error {
|
func (a *Authority) ReloadAuthConfig(ctx context.Context) error {
|
||||||
mgmtAuthConfig, err := a.adminDB.GetAuthConfig(context.Background(), mgmt.DefaultAuthorityID)
|
provs, err := a.adminDB.GetProvisioners(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mgmt.WrapErrorISE(err, "error getting authConfig from db")
|
return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority")
|
||||||
}
|
}
|
||||||
|
a.config.AuthorityConfig.Provisioners, err = provisionerListToCertificates(provs)
|
||||||
a.config.AuthorityConfig, err = mgmtAuthConfig.ToCertificates()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mgmt.WrapErrorISE(err, "error converting mgmt authConfig to certificates authConfig")
|
return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates")
|
||||||
|
}
|
||||||
|
a.config.AuthorityConfig.Admins, err = a.adminDB.GetAdmins(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge global and configuration claims
|
// Merge global and configuration claims
|
||||||
|
@ -148,7 +152,7 @@ func (a *Authority) ReloadAuthConfig() error {
|
||||||
// TODO: should we also be combining the ssh federated roots here?
|
// TODO: should we also be combining the ssh federated roots here?
|
||||||
// If we rotate ssh roots keys, sshpop provisioner will lose ability to
|
// If we rotate ssh roots keys, sshpop provisioner will lose ability to
|
||||||
// validate old SSH certificates, unless they are added as federated certs.
|
// validate old SSH certificates, unless they are added as federated certs.
|
||||||
sshKeys, err := a.GetSSHRoots(context.Background())
|
sshKeys, err := a.GetSSHRoots(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -201,30 +205,52 @@ func (a *Authority) init() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize step-ca Admin Database if it's not already initialized using
|
if len(a.config.AuthorityConfig.Provisioners) == 0 {
|
||||||
// WithAdminDB.
|
// Initialize step-ca Admin Database if it's not already initialized using
|
||||||
if a.adminDB == nil {
|
// WithAdminDB.
|
||||||
// Check if AuthConfig already exists
|
if a.adminDB == nil {
|
||||||
a.adminDB, err = authMgmtNosql.New(a.db.(nosql.DB), mgmt.DefaultAuthorityID)
|
// Check if AuthConfig already exists
|
||||||
if err != nil {
|
a.adminDB, err = authMgmtNosql.New(a.db.(nosql.DB), mgmt.DefaultAuthorityID)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
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.adminDB, mgmt.WithDefaultAuthorityID)
|
|
||||||
if err != nil {
|
|
||||||
return mgmt.WrapErrorISE(err, "error creating authConfig")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return mgmt.WrapErrorISE(err, "error getting authConfig from db")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a.config.AuthorityConfig, err = mgmtAuthConfig.ToCertificates()
|
provs, err := a.adminDB.GetProvisioners(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if len(provs) == 0 {
|
||||||
|
// Create First Provisioner
|
||||||
|
prov, err := mgmt.CreateFirstProvisioner(context.Background(), a.adminDB, a.config.Password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Create First Admin
|
||||||
|
adm := &linkedca.Admin{
|
||||||
|
ProvisionerId: prov.Id,
|
||||||
|
Subject: "step",
|
||||||
|
Type: linkedca.Admin_SUPER_ADMIN,
|
||||||
|
}
|
||||||
|
if err := a.adminDB.CreateAdmin(context.Background(), adm); err != nil {
|
||||||
|
// TODO should we try to clean up?
|
||||||
|
return mgmt.WrapErrorISE(err, "error creating first admin")
|
||||||
|
}
|
||||||
|
a.config.AuthorityConfig.Admins = []*linkedca.Admin{adm}
|
||||||
|
} 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)
|
||||||
|
if err != nil {
|
||||||
|
return mgmt.WrapErrorISE(err, "error converting provisioner list to certificates")
|
||||||
|
}
|
||||||
|
a.config.AuthorityConfig.Admins, err = a.adminDB.GetAdmins(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return mgmt.WrapErrorISE(err, "error getting provisioners to initialize authority")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize key manager if it has not been set in the options.
|
// Initialize key manager if it has not been set in the options.
|
||||||
|
|
|
@ -8,14 +8,14 @@ import (
|
||||||
"github.com/smallstep/certificates/api"
|
"github.com/smallstep/certificates/api"
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
"github.com/smallstep/certificates/authority/admin"
|
||||||
"github.com/smallstep/certificates/authority/mgmt"
|
"github.com/smallstep/certificates/authority/mgmt"
|
||||||
"github.com/smallstep/certificates/authority/status"
|
"github.com/smallstep/certificates/linkedca"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateAdminRequest represents the body for a CreateAdmin request.
|
// CreateAdminRequest represents the body for a CreateAdmin request.
|
||||||
type CreateAdminRequest struct {
|
type CreateAdminRequest struct {
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Provisioner string `json:"provisioner"`
|
Provisioner string `json:"provisioner"`
|
||||||
Type admin.Type `json:"type"`
|
Type linkedca.Admin_Type `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a new-admin request body.
|
// Validate validates a new-admin request body.
|
||||||
|
@ -29,13 +29,13 @@ func (car *CreateAdminRequest) Validate(c *admin.Collection) error {
|
||||||
|
|
||||||
// GetAdminsResponse for returning a list of admins.
|
// GetAdminsResponse for returning a list of admins.
|
||||||
type GetAdminsResponse struct {
|
type GetAdminsResponse struct {
|
||||||
Admins []*admin.Admin `json:"admins"`
|
Admins []*linkedca.Admin `json:"admins"`
|
||||||
NextCursor string `json:"nextCursor"`
|
NextCursor string `json:"nextCursor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAdminRequest represents the body for a UpdateAdmin request.
|
// UpdateAdminRequest represents the body for a UpdateAdmin request.
|
||||||
type UpdateAdminRequest struct {
|
type UpdateAdminRequest struct {
|
||||||
Type admin.Type `json:"type"`
|
Type linkedca.Admin_Type `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a new-admin request body.
|
// Validate validates a new-admin request body.
|
||||||
|
@ -98,20 +98,17 @@ func (h *Handler) CreateAdmin(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
adm := &mgmt.Admin{
|
adm := &linkedca.Admin{
|
||||||
ProvisionerID: p.GetID(),
|
ProvisionerId: p.GetID(),
|
||||||
Subject: body.Subject,
|
Subject: body.Subject,
|
||||||
Type: body.Type,
|
Type: body.Type,
|
||||||
Status: status.Active,
|
|
||||||
}
|
}
|
||||||
if err := h.db.CreateAdmin(ctx, adm); err != nil {
|
if err := h.db.CreateAdmin(ctx, adm); err != nil {
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error creating admin"))
|
api.WriteError(w, mgmt.WrapErrorISE(err, "error creating admin"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
adm.ProvisionerName = p.GetName()
|
|
||||||
adm.ProvisionerType = p.GetType().String()
|
|
||||||
api.JSON(w, adm)
|
api.JSON(w, adm)
|
||||||
if err := h.auth.ReloadAuthConfig(); err != nil {
|
if err := h.auth.ReloadAuthConfig(ctx); err != nil {
|
||||||
fmt.Printf("err = %+v\n", err)
|
fmt.Printf("err = %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,18 +123,13 @@ func (h *Handler) DeleteAdmin(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
adm, err := h.db.GetAdmin(ctx, id)
|
if err := h.db.DeleteAdmin(ctx, id); err != nil {
|
||||||
if err != nil {
|
api.WriteError(w, mgmt.WrapErrorISE(err, "error deleting admin %s", id))
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error retrieiving admin %s", id))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
adm.Status = status.Deleted
|
|
||||||
if err := h.db.UpdateAdmin(ctx, adm); err != nil {
|
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error updating admin %s", id))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
api.JSON(w, &DeleteResponse{Status: "ok"})
|
api.JSON(w, &DeleteResponse{Status: "ok"})
|
||||||
if err := h.auth.ReloadAuthConfig(); err != nil {
|
|
||||||
|
if err := h.auth.ReloadAuthConfig(ctx); err != nil {
|
||||||
fmt.Printf("err = %+v\n", err)
|
fmt.Printf("err = %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,12 +158,12 @@ func (h *Handler) UpdateAdmin(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
adm.Type = body.Type
|
adm.Type = body.Type
|
||||||
|
|
||||||
if err := h.db.UpdateAdmin(ctx, (*mgmt.Admin)(adm)); err != nil {
|
if err := h.db.UpdateAdmin(ctx, (*linkedca.Admin)(adm)); err != nil {
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error updating admin %s", id))
|
api.WriteError(w, mgmt.WrapErrorISE(err, "error updating admin %s", id))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
api.JSON(w, adm)
|
api.JSON(w, adm)
|
||||||
if err := h.auth.ReloadAuthConfig(); err != nil {
|
if err := h.auth.ReloadAuthConfig(ctx); err != nil {
|
||||||
fmt.Printf("err = %+v\n", err)
|
fmt.Printf("err = %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
|
||||||
"github.com/smallstep/certificates/api"
|
|
||||||
"github.com/smallstep/certificates/authority/config"
|
|
||||||
"github.com/smallstep/certificates/authority/mgmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateAuthConfigRequest represents the body for a CreateAuthConfig request.
|
|
||||||
type CreateAuthConfigRequest struct {
|
|
||||||
ASN1DN *config.ASN1DN `json:"asn1dn,omitempty"`
|
|
||||||
Claims *mgmt.Claims `json:"claims,omitempty"`
|
|
||||||
Backdate string `json:"backdate,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates a CreateAuthConfig request body.
|
|
||||||
func (car *CreateAuthConfigRequest) Validate() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAuthConfigRequest represents the body for a UpdateAuthConfig request.
|
|
||||||
type UpdateAuthConfigRequest struct {
|
|
||||||
ASN1DN *config.ASN1DN `json:"asn1dn"`
|
|
||||||
Claims *mgmt.Claims `json:"claims"`
|
|
||||||
Backdate string `json:"backdate,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates a new-admin request body.
|
|
||||||
func (uar *UpdateAuthConfigRequest) Validate() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAuthConfig returns the requested admin, or an error.
|
|
||||||
func (h *Handler) GetAuthConfig(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ctx := r.Context()
|
|
||||||
id := chi.URLParam(r, "id")
|
|
||||||
|
|
||||||
ac, err := h.db.GetAuthConfig(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
api.JSON(w, ac)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAuthConfig updates an existing AuthConfig.
|
|
||||||
func (h *Handler) UpdateAuthConfig(w http.ResponseWriter, r *http.Request) {
|
|
||||||
/*
|
|
||||||
ctx := r.Context()
|
|
||||||
id := chi.URLParam(r, "id")
|
|
||||||
|
|
||||||
var body UpdateAuthConfigRequest
|
|
||||||
if err := api.ReadJSON(r.Body, &body); err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := body.Validate(); err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ac, err := h.db.GetAuthConfig(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ac.Status = body.Status
|
|
||||||
if body.ASN1DN != nil {
|
|
||||||
ac.ASN1DN = body.ASN1DN
|
|
||||||
}
|
|
||||||
if body.Claims != nil {
|
|
||||||
ac.Claims = body.Claims
|
|
||||||
}
|
|
||||||
if body.Backdate != "" {
|
|
||||||
ac.Backdate = body.Backdate
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.db.UpdateAuthConfig(ctx, ac); err != nil {
|
|
||||||
api.WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
api.JSON(w, ac)
|
|
||||||
*/
|
|
||||||
}
|
|
|
@ -44,8 +44,4 @@ func (h *Handler) Route(r api.Router) {
|
||||||
r.MethodFunc("POST", "/admins", h.CreateAdmin)
|
r.MethodFunc("POST", "/admins", h.CreateAdmin)
|
||||||
r.MethodFunc("PATCH", "/admins/{id}", h.UpdateAdmin)
|
r.MethodFunc("PATCH", "/admins/{id}", h.UpdateAdmin)
|
||||||
r.MethodFunc("DELETE", "/admins/{id}", h.DeleteAdmin)
|
r.MethodFunc("DELETE", "/admins/{id}", h.DeleteAdmin)
|
||||||
|
|
||||||
// AuthConfig
|
|
||||||
r.MethodFunc("GET", "/authconfigs/{id}", h.GetAuthConfig)
|
|
||||||
r.MethodFunc("PUT", "/authconfigs/{id}", h.UpdateAuthConfig)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,20 +8,20 @@ import (
|
||||||
"github.com/smallstep/certificates/api"
|
"github.com/smallstep/certificates/api"
|
||||||
"github.com/smallstep/certificates/authority/mgmt"
|
"github.com/smallstep/certificates/authority/mgmt"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/authority/status"
|
|
||||||
"github.com/smallstep/certificates/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
|
"github.com/smallstep/certificates/linkedca"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateProvisionerRequest represents the body for a CreateProvisioner request.
|
// CreateProvisionerRequest represents the body for a CreateProvisioner request.
|
||||||
type CreateProvisionerRequest struct {
|
type CreateProvisionerRequest struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Claims *mgmt.Claims `json:"claims"`
|
Claims *linkedca.Claims `json:"claims"`
|
||||||
Details []byte `json:"details"`
|
Details []byte `json:"details"`
|
||||||
X509Template string `json:"x509Template"`
|
X509Template string `json:"x509Template"`
|
||||||
X509TemplateData []byte `json:"x509TemplateData"`
|
X509TemplateData []byte `json:"x509TemplateData"`
|
||||||
SSHTemplate string `json:"sshTemplate"`
|
SSHTemplate string `json:"sshTemplate"`
|
||||||
SSHTemplateData []byte `json:"sshTemplateData"`
|
SSHTemplateData []byte `json:"sshTemplateData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a new-provisioner request body.
|
// Validate validates a new-provisioner request body.
|
||||||
|
@ -40,14 +40,14 @@ type GetProvisionersResponse struct {
|
||||||
|
|
||||||
// UpdateProvisionerRequest represents the body for a UpdateProvisioner request.
|
// UpdateProvisionerRequest represents the body for a UpdateProvisioner request.
|
||||||
type UpdateProvisionerRequest struct {
|
type UpdateProvisionerRequest struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Claims *mgmt.Claims `json:"claims"`
|
Claims *linkedca.Claims `json:"claims"`
|
||||||
Details []byte `json:"details"`
|
Details []byte `json:"details"`
|
||||||
X509Template string `json:"x509Template"`
|
X509Template string `json:"x509Template"`
|
||||||
X509TemplateData []byte `json:"x509TemplateData"`
|
X509TemplateData []byte `json:"x509TemplateData"`
|
||||||
SSHTemplate string `json:"sshTemplate"`
|
SSHTemplate string `json:"sshTemplate"`
|
||||||
SSHTemplateData []byte `json:"sshTemplateData"`
|
SSHTemplateData []byte `json:"sshTemplateData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a update-provisioner request body.
|
// Validate validates a update-provisioner request body.
|
||||||
|
@ -101,7 +101,7 @@ func (h *Handler) GetProvisioners(w http.ResponseWriter, r *http.Request) {
|
||||||
func (h *Handler) CreateProvisioner(w http.ResponseWriter, r *http.Request) {
|
func (h *Handler) CreateProvisioner(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
var prov = new(mgmt.Provisioner)
|
var prov = new(linkedca.Provisioner)
|
||||||
if err := api.ReadJSON(r.Body, prov); err != nil {
|
if err := api.ReadJSON(r.Body, prov); err != nil {
|
||||||
api.WriteError(w, err)
|
api.WriteError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -118,7 +118,7 @@ func (h *Handler) CreateProvisioner(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
api.JSONStatus(w, prov, http.StatusCreated)
|
api.JSONStatus(w, prov, http.StatusCreated)
|
||||||
|
|
||||||
if err := h.auth.ReloadAuthConfig(); err != nil {
|
if err := h.auth.ReloadAuthConfig(ctx); err != nil {
|
||||||
fmt.Printf("err = %+v\n", err)
|
fmt.Printf("err = %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,14 +141,8 @@ func (h *Handler) DeleteProvisioner(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
prov, err := h.db.GetProvisioner(ctx, p.GetID())
|
if err := h.db.DeleteProvisioner(ctx, p.GetID()); err != nil {
|
||||||
if err != nil {
|
api.WriteError(w, mgmt.WrapErrorISE(err, "error deleting provisioner %s", name))
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error loading provisioner %s from db", name))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
prov.Status = status.Deleted
|
|
||||||
if err := h.db.UpdateProvisioner(ctx, prov); err != nil {
|
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error updating provisioner %s", name))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,13 +150,7 @@ func (h *Handler) DeleteProvisioner(w http.ResponseWriter, r *http.Request) {
|
||||||
admins, ok := c.LoadByProvisioner(name)
|
admins, ok := c.LoadByProvisioner(name)
|
||||||
if ok {
|
if ok {
|
||||||
for _, adm := range admins {
|
for _, adm := range admins {
|
||||||
if err := h.db.UpdateAdmin(ctx, &mgmt.Admin{
|
if err := h.db.DeleteAdmin(ctx, adm.Id); err != nil {
|
||||||
ID: adm.ID,
|
|
||||||
ProvisionerID: adm.ProvisionerID,
|
|
||||||
Subject: adm.Subject,
|
|
||||||
Type: adm.Type,
|
|
||||||
Status: status.Deleted,
|
|
||||||
}); err != nil {
|
|
||||||
api.WriteError(w, mgmt.WrapErrorISE(err, "error deleting admin %s, as part of provisioner %s deletion", adm.Subject, name))
|
api.WriteError(w, mgmt.WrapErrorISE(err, "error deleting admin %s, as part of provisioner %s deletion", adm.Subject, name))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -171,7 +159,7 @@ func (h *Handler) DeleteProvisioner(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
api.JSON(w, &DeleteResponse{Status: "ok"})
|
api.JSON(w, &DeleteResponse{Status: "ok"})
|
||||||
|
|
||||||
if err := h.auth.ReloadAuthConfig(); err != nil {
|
if err := h.auth.ReloadAuthConfig(ctx); err != nil {
|
||||||
fmt.Printf("err = %+v\n", err)
|
fmt.Printf("err = %+v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
package mgmt
|
package mgmt
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/smallstep/certificates/authority/config"
|
|
||||||
"github.com/smallstep/certificates/linkedca"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultAuthorityID is the default AuthorityID. This will be the ID
|
// DefaultAuthorityID is the default AuthorityID. This will be the ID
|
||||||
// of the first Authority created, as well as the default AuthorityID
|
// of the first Authority created, as well as the default AuthorityID
|
||||||
|
@ -12,31 +7,6 @@ const (
|
||||||
DefaultAuthorityID = "00000000-0000-0000-0000-000000000000"
|
DefaultAuthorityID = "00000000-0000-0000-0000-000000000000"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDefaultClaims() *linkedca.Claims {
|
|
||||||
return &linkedca.Claims{
|
|
||||||
X509: &linkedca.X509Claims{
|
|
||||||
Durations: &linkedca.Durations{
|
|
||||||
Min: config.GlobalProvisionerClaims.MinTLSDur.String(),
|
|
||||||
Max: config.GlobalProvisionerClaims.MaxTLSDur.String(),
|
|
||||||
Default: config.GlobalProvisionerClaims.DefaultTLSDur.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Ssh: &linkedca.SSHClaims{
|
|
||||||
UserDurations: &linkedca.Durations{
|
|
||||||
Min: config.GlobalProvisionerClaims.MinUserSSHDur.String(),
|
|
||||||
Max: config.GlobalProvisionerClaims.MaxUserSSHDur.String(),
|
|
||||||
Default: config.GlobalProvisionerClaims.DefaultUserSSHDur.String(),
|
|
||||||
},
|
|
||||||
HostDurations: &linkedca.Durations{
|
|
||||||
Min: config.GlobalProvisionerClaims.MinHostSSHDur.String(),
|
|
||||||
Max: config.GlobalProvisionerClaims.MaxHostSSHDur.String(),
|
|
||||||
Default: config.GlobalProvisionerClaims.DefaultHostSSHDur.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
DisableRenewal: config.DefaultDisableRenewal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
func CreateAuthority(ctx context.Context, db DB, options ...AuthorityOption) (*AuthConfig, error) {
|
func CreateAuthority(ctx context.Context, db DB, options ...AuthorityOption) (*AuthConfig, error) {
|
||||||
ac := NewDefaultAuthConfig()
|
ac := NewDefaultAuthConfig()
|
||||||
|
|
|
@ -204,3 +204,16 @@ func (db *DB) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteProvisioner saves an updated admin to the database.
|
||||||
|
func (db *DB) DeleteProvisioner(ctx context.Context, id string) error {
|
||||||
|
old, err := db.getDBProvisioner(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nu := old.clone()
|
||||||
|
nu.DeletedAt = clock.Now()
|
||||||
|
|
||||||
|
return db.save(ctx, old.ID, nu, old, "provisioner", authorityProvisionersTable)
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package mgmt
|
package mgmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/config"
|
||||||
"github.com/smallstep/certificates/linkedca"
|
"github.com/smallstep/certificates/linkedca"
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
)
|
)
|
||||||
|
@ -57,192 +56,57 @@ func (p *Provisioner) UnmarshalJSON(b []byte) error {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func provisionerGetOptions(p *linkedca.Provisioner) *provisioner.Options {
|
func NewDefaultClaims() *linkedca.Claims {
|
||||||
return &provisioner.Options{
|
return &linkedca.Claims{
|
||||||
X509: &provisioner.X509Options{
|
X509: &linkedca.X509Claims{
|
||||||
Template: string(p.X509Template),
|
Durations: &linkedca.Durations{
|
||||||
TemplateData: p.X509TemplateData,
|
Min: config.GlobalProvisionerClaims.MinTLSDur.String(),
|
||||||
|
Max: config.GlobalProvisionerClaims.MaxTLSDur.String(),
|
||||||
|
Default: config.GlobalProvisionerClaims.DefaultTLSDur.String(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
SSH: &provisioner.SSHOptions{
|
Ssh: &linkedca.SSHClaims{
|
||||||
Template: string(p.SshTemplate),
|
UserDurations: &linkedca.Durations{
|
||||||
TemplateData: p.SshTemplateData,
|
Min: config.GlobalProvisionerClaims.MinUserSSHDur.String(),
|
||||||
|
Max: config.GlobalProvisionerClaims.MaxUserSSHDur.String(),
|
||||||
|
Default: config.GlobalProvisionerClaims.DefaultUserSSHDur.String(),
|
||||||
|
},
|
||||||
|
HostDurations: &linkedca.Durations{
|
||||||
|
Min: config.GlobalProvisionerClaims.MinHostSSHDur.String(),
|
||||||
|
Max: config.GlobalProvisionerClaims.MaxHostSSHDur.String(),
|
||||||
|
Default: config.GlobalProvisionerClaims.DefaultHostSSHDur.String(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
DisableRenewal: config.DefaultDisableRenewal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// provisionerToCertificates converts the landlord provisioner type to the open source
|
func CreateFirstProvisioner(ctx context.Context, db DB, password string) (*linkedca.Provisioner, error) {
|
||||||
// provisioner type.
|
jwk, jwe, err := jose.GenerateDefaultKeyPair([]byte(password))
|
||||||
func provisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, error) {
|
|
||||||
claims, err := claimsToCertificates(p.Claims)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, WrapErrorISE(err, "error generating JWK key pair")
|
||||||
}
|
}
|
||||||
|
|
||||||
details := p.Details.GetData()
|
jwkPubBytes, err := jwk.MarshalJSON()
|
||||||
if details == nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("provisioner does not have any details")
|
return nil, WrapErrorISE(err, "error marshaling JWK")
|
||||||
|
}
|
||||||
|
jwePrivStr, err := jwe.CompactSerialize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, WrapErrorISE(err, "error serializing JWE")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch d := details.(type) {
|
return &linkedca.Provisioner{
|
||||||
case *linkedca.ProvisionerDetails_JWK:
|
Name: "Admin JWK",
|
||||||
jwk := new(jose.JSONWebKey)
|
Type: linkedca.Provisioner_JWK,
|
||||||
if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil {
|
Claims: NewDefaultClaims(),
|
||||||
return nil, err
|
Details: &linkedca.ProvisionerDetails{
|
||||||
}
|
Data: &linkedca.ProvisionerDetails_JWK{
|
||||||
return &provisioner.JWK{
|
JWK: &linkedca.JWKProvisioner{
|
||||||
ID: p.Id,
|
PublicKey: jwkPubBytes,
|
||||||
Type: p.Type.String(),
|
EncryptedPrivateKey: []byte(jwePrivStr),
|
||||||
Name: p.Name,
|
},
|
||||||
Key: jwk,
|
},
|
||||||
EncryptedKey: string(d.JWK.EncryptedPrivateKey),
|
},
|
||||||
Claims: claims,
|
|
||||||
Options: provisionerGetOptions(p),
|
|
||||||
}, nil
|
|
||||||
/*
|
|
||||||
case *ProvisionerDetails_OIDC:
|
|
||||||
cfg := d.OIDC
|
|
||||||
return &provisioner.OIDC{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
TenantID: cfg.TenantId,
|
|
||||||
ClientID: cfg.ClientId,
|
|
||||||
ClientSecret: cfg.ClientSecret,
|
|
||||||
ConfigurationEndpoint: cfg.ConfigurationEndpoint,
|
|
||||||
Admins: cfg.Admins,
|
|
||||||
Domains: cfg.Domains,
|
|
||||||
Groups: cfg.Groups,
|
|
||||||
ListenAddress: cfg.ListenAddress,
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_GCP:
|
|
||||||
cfg := d.GCP
|
|
||||||
return &provisioner.GCP{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
ServiceAccounts: cfg.ServiceAccounts,
|
|
||||||
ProjectIDs: cfg.ProjectIds,
|
|
||||||
DisableCustomSANs: cfg.DisableCustomSans,
|
|
||||||
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
|
||||||
InstanceAge: durationValue(cfg.InstanceAge),
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_AWS:
|
|
||||||
cfg := d.AWS
|
|
||||||
return &provisioner.AWS{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
Accounts: cfg.Accounts,
|
|
||||||
DisableCustomSANs: cfg.DisableCustomSans,
|
|
||||||
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
|
||||||
InstanceAge: durationValue(cfg.InstanceAge),
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_Azure:
|
|
||||||
cfg := d.Azure
|
|
||||||
return &provisioner.Azure{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
TenantID: cfg.TenantId,
|
|
||||||
ResourceGroups: cfg.ResourceGroups,
|
|
||||||
Audience: cfg.Audience,
|
|
||||||
DisableCustomSANs: cfg.DisableCustomSans,
|
|
||||||
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_X5C:
|
|
||||||
var roots []byte
|
|
||||||
for i, k := range d.X5C.GetRoots() {
|
|
||||||
if b := k.GetKey().GetPublic(); b != nil {
|
|
||||||
if i > 0 {
|
|
||||||
roots = append(roots, '\n')
|
|
||||||
}
|
|
||||||
roots = append(roots, b...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &provisioner.X5C{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
Roots: roots,
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_K8SSA:
|
|
||||||
var publicKeys []byte
|
|
||||||
for i, k := range d.K8SSA.GetPublicKeys() {
|
|
||||||
if b := k.GetKey().GetPublic(); b != nil {
|
|
||||||
if i > 0 {
|
|
||||||
publicKeys = append(publicKeys, '\n')
|
|
||||||
}
|
|
||||||
publicKeys = append(publicKeys, k.Key.Public...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &provisioner.K8sSA{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
PubKeys: publicKeys,
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_SSHPOP:
|
|
||||||
return &provisioner.SSHPOP{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
Claims: claims,
|
|
||||||
}, nil
|
|
||||||
case *ProvisionerDetails_ACME:
|
|
||||||
cfg := d.ACME
|
|
||||||
return &provisioner.ACME{
|
|
||||||
Type: p.Type.String(),
|
|
||||||
Name: p.Name,
|
|
||||||
ForceCN: cfg.ForceCn,
|
|
||||||
Claims: claims,
|
|
||||||
Options: options,
|
|
||||||
}, nil
|
|
||||||
*/
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("provisioner %s not implemented", p.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// claimsToCertificates converts the landlord provisioner claims type to the open source
|
|
||||||
// (step-ca) claims type.
|
|
||||||
func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
|
|
||||||
var durs = map[string]struct {
|
|
||||||
durStr string
|
|
||||||
dur *provisioner.Duration
|
|
||||||
}{
|
|
||||||
"minTLSDur": {durStr: c.X509.Durations.Min},
|
|
||||||
"maxTLSDur": {durStr: c.X509.Durations.Max},
|
|
||||||
"defaultTLSDur": {durStr: c.X509.Durations.Default},
|
|
||||||
"minSSHUserDur": {durStr: c.Ssh.UserDurations.Min},
|
|
||||||
"maxSSHUserDur": {durStr: c.Ssh.UserDurations.Max},
|
|
||||||
"defaultSSHUserDur": {durStr: c.Ssh.UserDurations.Default},
|
|
||||||
"minSSHHostDur": {durStr: c.Ssh.HostDurations.Min},
|
|
||||||
"maxSSHHostDur": {durStr: c.Ssh.HostDurations.Max},
|
|
||||||
"defaultSSHHostDur": {durStr: c.Ssh.HostDurations.Default},
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
for k, v := range durs {
|
|
||||||
v.dur, err = provisioner.NewDuration(v.durStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, WrapErrorISE(err, "error parsing %s %s from claims", k, v.durStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &provisioner.Claims{
|
|
||||||
MinTLSDur: durs["minTLSDur"].dur,
|
|
||||||
MaxTLSDur: durs["maxTLSDur"].dur,
|
|
||||||
DefaultTLSDur: durs["defaultTLSDur"].dur,
|
|
||||||
DisableRenewal: &c.DisableRenewal,
|
|
||||||
MinUserSSHDur: durs["minSSHUserDur"].dur,
|
|
||||||
MaxUserSSHDur: durs["maxSSHUserDur"].dur,
|
|
||||||
DefaultUserSSHDur: durs["defaultSSHUserDur"].dur,
|
|
||||||
MinHostSSHDur: durs["minSSHHostDur"].dur,
|
|
||||||
MaxHostSSHDur: durs["maxSSHHostDur"].dur,
|
|
||||||
DefaultHostSSHDur: durs["defaultSSHHostDur"].dur,
|
|
||||||
EnableSSHCA: &c.Ssh.Enabled,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,14 @@ package authority
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/smallstep/certificates/authority/mgmt"
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
"github.com/smallstep/certificates/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
|
"github.com/smallstep/certificates/linkedca"
|
||||||
|
"go.step.sm/crypto/jose"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetEncryptedKey returns the JWE key corresponding to the given kid argument.
|
// GetEncryptedKey returns the JWE key corresponding to the given kid argument.
|
||||||
|
@ -41,3 +46,205 @@ func (a *Authority) LoadProvisionerByID(id string) (provisioner.Interface, error
|
||||||
}
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func provisionerGetOptions(p *linkedca.Provisioner) *provisioner.Options {
|
||||||
|
return &provisioner.Options{
|
||||||
|
X509: &provisioner.X509Options{
|
||||||
|
Template: string(p.X509Template),
|
||||||
|
TemplateData: p.X509TemplateData,
|
||||||
|
},
|
||||||
|
SSH: &provisioner.SSHOptions{
|
||||||
|
Template: string(p.SshTemplate),
|
||||||
|
TemplateData: p.SshTemplateData,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func provisionerListToCertificates(l []*linkedca.Provisioner) (provisioner.List, error) {
|
||||||
|
var nu provisioner.List
|
||||||
|
for _, p := range l {
|
||||||
|
certProv, err := provisionerToCertificates(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nu = append(nu, certProv)
|
||||||
|
}
|
||||||
|
return nu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// provisionerToCertificates converts the landlord provisioner type to the open source
|
||||||
|
// provisioner type.
|
||||||
|
func provisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, error) {
|
||||||
|
claims, err := claimsToCertificates(p.Claims)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
details := p.Details.GetData()
|
||||||
|
if details == nil {
|
||||||
|
return nil, fmt.Errorf("provisioner does not have any details")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch d := details.(type) {
|
||||||
|
case *linkedca.ProvisionerDetails_JWK:
|
||||||
|
jwk := new(jose.JSONWebKey)
|
||||||
|
if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &provisioner.JWK{
|
||||||
|
ID: p.Id,
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
Key: jwk,
|
||||||
|
EncryptedKey: string(d.JWK.EncryptedPrivateKey),
|
||||||
|
Claims: claims,
|
||||||
|
Options: provisionerGetOptions(p),
|
||||||
|
}, nil
|
||||||
|
/*
|
||||||
|
case *ProvisionerDetails_OIDC:
|
||||||
|
cfg := d.OIDC
|
||||||
|
return &provisioner.OIDC{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
TenantID: cfg.TenantId,
|
||||||
|
ClientID: cfg.ClientId,
|
||||||
|
ClientSecret: cfg.ClientSecret,
|
||||||
|
ConfigurationEndpoint: cfg.ConfigurationEndpoint,
|
||||||
|
Admins: cfg.Admins,
|
||||||
|
Domains: cfg.Domains,
|
||||||
|
Groups: cfg.Groups,
|
||||||
|
ListenAddress: cfg.ListenAddress,
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_GCP:
|
||||||
|
cfg := d.GCP
|
||||||
|
return &provisioner.GCP{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
ServiceAccounts: cfg.ServiceAccounts,
|
||||||
|
ProjectIDs: cfg.ProjectIds,
|
||||||
|
DisableCustomSANs: cfg.DisableCustomSans,
|
||||||
|
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
||||||
|
InstanceAge: durationValue(cfg.InstanceAge),
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_AWS:
|
||||||
|
cfg := d.AWS
|
||||||
|
return &provisioner.AWS{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
Accounts: cfg.Accounts,
|
||||||
|
DisableCustomSANs: cfg.DisableCustomSans,
|
||||||
|
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
||||||
|
InstanceAge: durationValue(cfg.InstanceAge),
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_Azure:
|
||||||
|
cfg := d.Azure
|
||||||
|
return &provisioner.Azure{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
TenantID: cfg.TenantId,
|
||||||
|
ResourceGroups: cfg.ResourceGroups,
|
||||||
|
Audience: cfg.Audience,
|
||||||
|
DisableCustomSANs: cfg.DisableCustomSans,
|
||||||
|
DisableTrustOnFirstUse: cfg.DisableTrustOnFirstUse,
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_X5C:
|
||||||
|
var roots []byte
|
||||||
|
for i, k := range d.X5C.GetRoots() {
|
||||||
|
if b := k.GetKey().GetPublic(); b != nil {
|
||||||
|
if i > 0 {
|
||||||
|
roots = append(roots, '\n')
|
||||||
|
}
|
||||||
|
roots = append(roots, b...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &provisioner.X5C{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
Roots: roots,
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_K8SSA:
|
||||||
|
var publicKeys []byte
|
||||||
|
for i, k := range d.K8SSA.GetPublicKeys() {
|
||||||
|
if b := k.GetKey().GetPublic(); b != nil {
|
||||||
|
if i > 0 {
|
||||||
|
publicKeys = append(publicKeys, '\n')
|
||||||
|
}
|
||||||
|
publicKeys = append(publicKeys, k.Key.Public...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &provisioner.K8sSA{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
PubKeys: publicKeys,
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_SSHPOP:
|
||||||
|
return &provisioner.SSHPOP{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
Claims: claims,
|
||||||
|
}, nil
|
||||||
|
case *ProvisionerDetails_ACME:
|
||||||
|
cfg := d.ACME
|
||||||
|
return &provisioner.ACME{
|
||||||
|
Type: p.Type.String(),
|
||||||
|
Name: p.Name,
|
||||||
|
ForceCN: cfg.ForceCn,
|
||||||
|
Claims: claims,
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("provisioner %s not implemented", p.Type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// claimsToCertificates converts the landlord provisioner claims type to the open source
|
||||||
|
// (step-ca) claims type.
|
||||||
|
func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
|
||||||
|
var durs = map[string]struct {
|
||||||
|
durStr string
|
||||||
|
dur *provisioner.Duration
|
||||||
|
}{
|
||||||
|
"minTLSDur": {durStr: c.X509.Durations.Min},
|
||||||
|
"maxTLSDur": {durStr: c.X509.Durations.Max},
|
||||||
|
"defaultTLSDur": {durStr: c.X509.Durations.Default},
|
||||||
|
"minSSHUserDur": {durStr: c.Ssh.UserDurations.Min},
|
||||||
|
"maxSSHUserDur": {durStr: c.Ssh.UserDurations.Max},
|
||||||
|
"defaultSSHUserDur": {durStr: c.Ssh.UserDurations.Default},
|
||||||
|
"minSSHHostDur": {durStr: c.Ssh.HostDurations.Min},
|
||||||
|
"maxSSHHostDur": {durStr: c.Ssh.HostDurations.Max},
|
||||||
|
"defaultSSHHostDur": {durStr: c.Ssh.HostDurations.Default},
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
for k, v := range durs {
|
||||||
|
v.dur, err = provisioner.NewDuration(v.durStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, mgmt.WrapErrorISE(err, "error parsing %s %s from claims", k, v.durStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &provisioner.Claims{
|
||||||
|
MinTLSDur: durs["minTLSDur"].dur,
|
||||||
|
MaxTLSDur: durs["maxTLSDur"].dur,
|
||||||
|
DefaultTLSDur: durs["defaultTLSDur"].dur,
|
||||||
|
DisableRenewal: &c.DisableRenewal,
|
||||||
|
MinUserSSHDur: durs["minSSHUserDur"].dur,
|
||||||
|
MaxUserSSHDur: durs["maxSSHUserDur"].dur,
|
||||||
|
DefaultUserSSHDur: durs["defaultSSHUserDur"].dur,
|
||||||
|
MinHostSSHDur: durs["minSSHHostDur"].dur,
|
||||||
|
MaxHostSSHDur: durs["maxSSHHostDur"].dur,
|
||||||
|
DefaultHostSSHDur: durs["defaultSSHHostDur"].dur,
|
||||||
|
EnableSSHCA: &c.Ssh.Enabled,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
|
||||||
"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/errs"
|
"github.com/smallstep/certificates/errs"
|
||||||
|
"github.com/smallstep/certificates/linkedca"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var adminURLPrefix = "admin"
|
||||||
|
|
||||||
// AdminClient implements an HTTP client for the CA server.
|
// AdminClient implements an HTTP client for the CA server.
|
||||||
type AdminClient struct {
|
type AdminClient struct {
|
||||||
client *uaClient
|
client *uaClient
|
||||||
|
@ -68,9 +70,9 @@ func (c *AdminClient) retryOnError(r *http.Response) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAdmin performs the GET /admin/admin/{id} request to the CA.
|
// GetAdmin performs the GET /admin/admin/{id} request to the CA.
|
||||||
func (c *AdminClient) GetAdmin(id string) (*mgmt.Admin, error) {
|
func (c *AdminClient) GetAdmin(id string) (*linkedca.Admin, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admin", id)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "admins", id)})
|
||||||
retry:
|
retry:
|
||||||
resp, err := c.client.Get(u.String())
|
resp, err := c.client.Get(u.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -83,7 +85,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var adm = new(mgmt.Admin)
|
var adm = new(linkedca.Admin)
|
||||||
if err := readJSON(resp.Body, adm); err != nil {
|
if err := readJSON(resp.Body, adm); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -165,7 +167,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) (*mgmt.Admin, error) {
|
func (c *AdminClient) CreateAdmin(req *mgmtAPI.CreateAdminRequest) (*linkedca.Admin, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
body, err := json.Marshal(req)
|
body, err := json.Marshal(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -184,7 +186,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var adm = new(mgmt.Admin)
|
var adm = new(linkedca.Admin)
|
||||||
if err := readJSON(resp.Body, adm); err != nil {
|
if err := readJSON(resp.Body, adm); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -194,7 +196,7 @@ retry:
|
||||||
// RemoveAdmin performs the DELETE /admin/admins/{id} request to the CA.
|
// RemoveAdmin performs the DELETE /admin/admins/{id} request to the CA.
|
||||||
func (c *AdminClient) RemoveAdmin(id string) error {
|
func (c *AdminClient) RemoveAdmin(id string) error {
|
||||||
var retried bool
|
var retried bool
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admins", id)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "admins", id)})
|
||||||
req, err := http.NewRequest("DELETE", u.String(), nil)
|
req, err := http.NewRequest("DELETE", u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "create DELETE %s request failed", u)
|
return errors.Wrapf(err, "create DELETE %s request failed", u)
|
||||||
|
@ -215,13 +217,13 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAdmin performs the PUT /admin/admins/{id} request to the CA.
|
// UpdateAdmin performs the PUT /admin/admins/{id} request to the CA.
|
||||||
func (c *AdminClient) UpdateAdmin(id string, uar *mgmtAPI.UpdateAdminRequest) (*admin.Admin, error) {
|
func (c *AdminClient) UpdateAdmin(id string, uar *mgmtAPI.UpdateAdminRequest) (*linkedca.Admin, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
body, err := json.Marshal(uar)
|
body, err := json.Marshal(uar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
|
||||||
}
|
}
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/admins", id)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "admins", id)})
|
||||||
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(body))
|
req, err := http.NewRequest("PATCH", u.String(), bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "create PUT %s request failed", u)
|
return nil, errors.Wrapf(err, "create PUT %s request failed", u)
|
||||||
|
@ -238,7 +240,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var adm = new(admin.Admin)
|
var adm = new(linkedca.Admin)
|
||||||
if err := readJSON(resp.Body, adm); err != nil {
|
if err := readJSON(resp.Body, adm); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -246,9 +248,9 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProvisioner performs the GET /admin/provisioners/{name} request to the CA.
|
// GetProvisioner performs the GET /admin/provisioners/{name} request to the CA.
|
||||||
func (c *AdminClient) GetProvisioner(name string) (*mgmt.Provisioner, error) {
|
func (c *AdminClient) GetProvisioner(name string) (*linkedca.Provisioner, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", name)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", name)})
|
||||||
retry:
|
retry:
|
||||||
resp, err := c.client.Get(u.String())
|
resp, err := c.client.Get(u.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -261,7 +263,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var prov = new(mgmt.Provisioner)
|
var prov = new(linkedca.Provisioner)
|
||||||
if err := readJSON(resp.Body, prov); err != nil {
|
if err := readJSON(resp.Body, prov); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -269,7 +271,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProvisioners performs the GET /admin/provisioners request to the CA.
|
// GetProvisioners performs the GET /admin/provisioners request to the CA.
|
||||||
func (c *AdminClient) GetProvisioners() ([]*mgmt.Provisioner, error) {
|
func (c *AdminClient) GetProvisioners() ([]*linkedca.Provisioner, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"})
|
u := c.endpoint.ResolveReference(&url.URL{Path: "/admin/provisioners"})
|
||||||
retry:
|
retry:
|
||||||
|
@ -284,7 +286,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var provs = new([]*mgmt.Provisioner)
|
var provs = new([]*linkedca.Provisioner)
|
||||||
if err := readJSON(resp.Body, provs); err != nil {
|
if err := readJSON(resp.Body, provs); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +296,7 @@ retry:
|
||||||
// RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA.
|
// RemoveProvisioner performs the DELETE /admin/provisioners/{name} request to the CA.
|
||||||
func (c *AdminClient) RemoveProvisioner(name string) error {
|
func (c *AdminClient) RemoveProvisioner(name string) error {
|
||||||
var retried bool
|
var retried bool
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", name)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", name)})
|
||||||
req, err := http.NewRequest("DELETE", u.String(), nil)
|
req, err := http.NewRequest("DELETE", u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "create DELETE %s request failed", u)
|
return errors.Wrapf(err, "create DELETE %s request failed", u)
|
||||||
|
@ -315,7 +317,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateProvisioner performs the POST /admin/provisioners request to the CA.
|
// CreateProvisioner performs the POST /admin/provisioners request to the CA.
|
||||||
func (c *AdminClient) CreateProvisioner(prov *mgmt.Provisioner) (*mgmt.Provisioner, error) {
|
func (c *AdminClient) CreateProvisioner(prov *linkedca.Provisioner) (*linkedca.Provisioner, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
body, err := json.Marshal(prov)
|
body, err := json.Marshal(prov)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -334,7 +336,7 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var nuProv = new(mgmt.Provisioner)
|
var nuProv = new(linkedca.Provisioner)
|
||||||
if err := readJSON(resp.Body, nuProv); err != nil {
|
if err := readJSON(resp.Body, nuProv); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
|
@ -342,13 +344,13 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProvisioner performs the PUT /admin/provisioners/{id} request to the CA.
|
// UpdateProvisioner performs the PUT /admin/provisioners/{id} request to the CA.
|
||||||
func (c *AdminClient) UpdateProvisioner(id string, upr *mgmtAPI.UpdateProvisionerRequest) (*mgmt.Provisioner, error) {
|
func (c *AdminClient) UpdateProvisioner(id string, upr *mgmtAPI.UpdateProvisionerRequest) (*linkedca.Provisioner, error) {
|
||||||
var retried bool
|
var retried bool
|
||||||
body, err := json.Marshal(upr)
|
body, err := json.Marshal(upr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
|
return nil, errs.Wrap(http.StatusInternalServerError, err, "error marshaling request")
|
||||||
}
|
}
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/provisioners", id)})
|
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join(adminURLPrefix, "provisioners", id)})
|
||||||
req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(body))
|
req, err := http.NewRequest("PUT", u.String(), bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "create PUT %s request failed", u)
|
return nil, errors.Wrapf(err, "create PUT %s request failed", u)
|
||||||
|
@ -365,36 +367,13 @@ retry:
|
||||||
}
|
}
|
||||||
return nil, readAdminError(resp.Body)
|
return nil, readAdminError(resp.Body)
|
||||||
}
|
}
|
||||||
var prov = new(mgmt.Provisioner)
|
var prov = new(linkedca.Provisioner)
|
||||||
if err := readJSON(resp.Body, prov); err != nil {
|
if err := readJSON(resp.Body, prov); err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
return nil, errors.Wrapf(err, "error reading %s", u)
|
||||||
}
|
}
|
||||||
return prov, nil
|
return prov, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthConfig performs the GET /admin/authconfig/{id} request to the CA.
|
|
||||||
func (c *AdminClient) GetAuthConfig(id string) (*mgmt.AuthConfig, error) {
|
|
||||||
var retried bool
|
|
||||||
u := c.endpoint.ResolveReference(&url.URL{Path: path.Join("/admin/authconfig", id)})
|
|
||||||
retry:
|
|
||||||
resp, err := c.client.Get(u.String())
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "client GET %s failed", u)
|
|
||||||
}
|
|
||||||
if resp.StatusCode >= 400 {
|
|
||||||
if !retried && c.retryOnError(resp) {
|
|
||||||
retried = true
|
|
||||||
goto retry
|
|
||||||
}
|
|
||||||
return nil, readAdminError(resp.Body)
|
|
||||||
}
|
|
||||||
var ac = new(mgmt.AuthConfig)
|
|
||||||
if err := readJSON(resp.Body, ac); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "error reading %s", u)
|
|
||||||
}
|
|
||||||
return ac, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readAdminError(r io.ReadCloser) error {
|
func readAdminError(r io.ReadCloser) error {
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
mgmtErr := new(mgmt.Error)
|
mgmtErr := new(mgmt.Error)
|
||||||
|
|
Loading…
Reference in a new issue