certificates/authority/admin/api/acme.go

153 lines
4.9 KiB
Go
Raw Permalink Normal View History

2021-07-23 13:41:24 +00:00
package api
import (
"fmt"
2021-07-23 13:41:24 +00:00
"net/http"
"go.step.sm/linkedca"
2022-04-11 13:25:55 +00:00
"google.golang.org/protobuf/types/known/timestamppb"
2022-04-11 13:25:55 +00:00
"github.com/smallstep/certificates/acme"
"github.com/smallstep/certificates/api/render"
2021-07-23 13:41:24 +00:00
"github.com/smallstep/certificates/authority/admin"
)
2021-07-23 13:41:24 +00:00
// CreateExternalAccountKeyRequest is the type for POST /admin/acme/eab requests
type CreateExternalAccountKeyRequest struct {
Reference string `json:"reference"`
2021-07-23 13:41:24 +00:00
}
2021-09-16 21:09:24 +00:00
// Validate validates a new ACME EAB Key request body.
func (r *CreateExternalAccountKeyRequest) Validate() error {
if len(r.Reference) > 256 { // an arbitrary, but sensible (IMO), limit
return fmt.Errorf("reference length %d exceeds the maximum (256)", len(r.Reference))
}
return nil
2021-07-23 13:41:24 +00:00
}
// GetExternalAccountKeysResponse is the type for GET /admin/acme/eab responses
type GetExternalAccountKeysResponse struct {
EAKs []*linkedca.EABKey `json:"eaks"`
NextCursor string `json:"nextCursor"`
2021-07-23 13:41:24 +00:00
}
// requireEABEnabled is a middleware that ensures ACME EAB is enabled
// before serving requests that act on ACME EAB credentials.
func requireEABEnabled(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
prov := linkedca.MustProvisionerFromContext(ctx)
2022-03-30 16:21:25 +00:00
2022-04-21 11:21:06 +00:00
acmeProvisioner := prov.GetDetails().GetACME()
2022-03-30 16:21:25 +00:00
if acmeProvisioner == nil {
render.Error(w, admin.NewErrorISE("error getting ACME details for provisioner '%s'", prov.GetName()))
return
}
2021-09-16 21:09:24 +00:00
2022-03-30 16:21:25 +00:00
if !acmeProvisioner.RequireEab {
render.Error(w, admin.NewError(admin.ErrorBadRequestType, "ACME EAB not enabled for provisioner '%s'", prov.GetName()))
return
}
2022-04-27 18:59:32 +00:00
2022-03-31 14:12:29 +00:00
next(w, r)
2021-09-16 21:09:24 +00:00
}
}
2022-05-06 21:11:10 +00:00
// ACMEAdminResponder is responsible for writing ACME admin responses
type ACMEAdminResponder interface {
2022-02-08 12:26:30 +00:00
GetExternalAccountKeys(w http.ResponseWriter, r *http.Request)
CreateExternalAccountKey(w http.ResponseWriter, r *http.Request)
DeleteExternalAccountKey(w http.ResponseWriter, r *http.Request)
2021-09-16 21:09:24 +00:00
}
2022-05-06 21:11:10 +00:00
// acmeAdminResponder implements ACMEAdminResponder.
type acmeAdminResponder struct{}
2021-07-23 13:41:24 +00:00
2022-02-08 12:26:30 +00:00
// NewACMEAdminResponder returns a new ACMEAdminResponder
2022-05-06 21:11:10 +00:00
func NewACMEAdminResponder() ACMEAdminResponder {
return &acmeAdminResponder{}
2021-07-23 13:41:24 +00:00
}
2022-02-08 12:26:30 +00:00
// GetExternalAccountKeys writes the response for the EAB keys GET endpoint
2023-05-10 06:47:28 +00:00
func (h *acmeAdminResponder) GetExternalAccountKeys(w http.ResponseWriter, _ *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2021-08-27 12:10:00 +00:00
}
2022-02-08 12:26:30 +00:00
// CreateExternalAccountKey writes the response for the EAB key POST endpoint
2023-05-10 06:47:28 +00:00
func (h *acmeAdminResponder) CreateExternalAccountKey(w http.ResponseWriter, _ *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2022-02-08 12:26:30 +00:00
}
2021-08-27 14:58:04 +00:00
2022-02-08 12:26:30 +00:00
// DeleteExternalAccountKey writes the response for the EAB key DELETE endpoint
2023-05-10 06:47:28 +00:00
func (h *acmeAdminResponder) DeleteExternalAccountKey(w http.ResponseWriter, _ *http.Request) {
render.Error(w, admin.NewError(admin.ErrorNotImplementedType, "this functionality is currently only available in Certificate Manager: https://u.step.sm/cm"))
2021-07-23 13:41:24 +00:00
}
2022-04-11 13:25:55 +00:00
func eakToLinked(k *acme.ExternalAccountKey) *linkedca.EABKey {
if k == nil {
return nil
}
eak := &linkedca.EABKey{
Id: k.ID,
2022-04-26 08:15:17 +00:00
HmacKey: k.HmacKey,
2022-04-11 13:25:55 +00:00
Provisioner: k.ProvisionerID,
Reference: k.Reference,
Account: k.AccountID,
CreatedAt: timestamppb.New(k.CreatedAt),
BoundAt: timestamppb.New(k.BoundAt),
}
if k.Policy != nil {
eak.Policy = &linkedca.Policy{
X509: &linkedca.X509Policy{
Allow: &linkedca.X509Names{},
Deny: &linkedca.X509Names{},
},
}
eak.Policy.X509.Allow.Dns = k.Policy.X509.Allowed.DNSNames
eak.Policy.X509.Allow.Ips = k.Policy.X509.Allowed.IPRanges
eak.Policy.X509.Deny.Dns = k.Policy.X509.Denied.DNSNames
eak.Policy.X509.Deny.Ips = k.Policy.X509.Denied.IPRanges
eak.Policy.X509.AllowWildcardNames = k.Policy.X509.AllowWildcardNames
2022-04-11 13:25:55 +00:00
}
return eak
}
func linkedEAKToCertificates(k *linkedca.EABKey) *acme.ExternalAccountKey {
if k == nil {
return nil
}
eak := &acme.ExternalAccountKey{
ID: k.Id,
ProvisionerID: k.Provisioner,
Reference: k.Reference,
AccountID: k.Account,
2022-04-26 08:15:17 +00:00
HmacKey: k.HmacKey,
2022-04-11 13:25:55 +00:00
CreatedAt: k.CreatedAt.AsTime(),
BoundAt: k.BoundAt.AsTime(),
}
if policy := k.GetPolicy(); policy != nil {
eak.Policy = &acme.Policy{}
if x509 := policy.GetX509(); x509 != nil {
eak.Policy.X509 = acme.X509Policy{}
if allow := x509.GetAllow(); allow != nil {
eak.Policy.X509.Allowed = acme.PolicyNames{}
eak.Policy.X509.Allowed.DNSNames = allow.Dns
eak.Policy.X509.Allowed.IPRanges = allow.Ips
}
if deny := x509.GetDeny(); deny != nil {
eak.Policy.X509.Denied = acme.PolicyNames{}
eak.Policy.X509.Denied.DNSNames = deny.Dns
eak.Policy.X509.Denied.IPRanges = deny.Ips
}
eak.Policy.X509.AllowWildcardNames = x509.AllowWildcardNames
}
2022-04-11 13:25:55 +00:00
}
return eak
}