This commit is contained in:
max furman 2021-05-24 13:38:24 -07:00
parent 3f30552b60
commit 423942da44
7 changed files with 84 additions and 516 deletions

View file

@ -1,25 +0,0 @@
package admin
import "github.com/smallstep/certificates/authority/status"
// Type specifies the type of the admin. e.g. SUPER_ADMIN, REGULAR
type Type string
var (
// TypeSuper superadmin
TypeSuper = Type("SUPER_ADMIN")
// TypeRegular regular
TypeRegular = Type("REGULAR")
)
// Admin type.
type Admin struct {
ID string `json:"id"`
AuthorityID string `json:"-"`
Subject string `json:"subject"`
ProvisionerName string `json:"provisionerName"`
ProvisionerType string `json:"provisionerType"`
ProvisionerID string `json:"provisionerID"`
Type Type `json:"type"`
Status status.Type `json:"status"`
}

View file

@ -11,6 +11,7 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/linkedca"
)
// DefaultAdminLimit is the default limit for listing provisioners.
@ -20,7 +21,7 @@ const DefaultAdminLimit = 20
const DefaultAdminMax = 100
type uidAdmin struct {
admin *Admin
admin *linkedca.Admin
uid string
}
@ -54,7 +55,7 @@ func NewCollection(provisioners *provisioner.Collection) *Collection {
}
// LoadByID a admin by the ID.
func (c *Collection) LoadByID(id string) (*Admin, bool) {
func (c *Collection) LoadByID(id string) (*linkedca.Admin, bool) {
return loadAdmin(c.byID, id)
}
@ -66,17 +67,17 @@ func subProvNameHash(sub, provName string) string {
}
// LoadBySubProv a admin by the subject and provisioner name.
func (c *Collection) LoadBySubProv(sub, provName string) (*Admin, bool) {
func (c *Collection) LoadBySubProv(sub, provName string) (*linkedca.Admin, bool) {
return loadAdmin(c.bySubProv, subProvNameHash(sub, provName))
}
// LoadByProvisioner a admin by the subject and provisioner name.
func (c *Collection) LoadByProvisioner(provName string) ([]*Admin, bool) {
func (c *Collection) LoadByProvisioner(provName string) ([]*linkedca.Admin, bool) {
a, ok := c.byProv.Load(provName)
if !ok {
return nil, false
}
admins, ok := a.([]*Admin)
admins, ok := a.([]*linkedca.Admin)
if !ok {
return nil, false
}
@ -85,22 +86,20 @@ func (c *Collection) LoadByProvisioner(provName string) ([]*Admin, bool) {
// Store adds an admin to the collection and enforces the uniqueness of
// admin IDs and amdin subject <-> provisioner name combos.
func (c *Collection) Store(adm *Admin) error {
p, ok := c.provisioners.Load(adm.ProvisionerID)
func (c *Collection) Store(adm *linkedca.Admin) error {
p, ok := c.provisioners.Load(adm.ProvisionerId)
if !ok {
return fmt.Errorf("provisioner %s not found", adm.ProvisionerID)
return fmt.Errorf("provisioner %s not found", adm.ProvisionerId)
}
adm.ProvisionerName = p.GetName()
adm.ProvisionerType = p.GetType().String()
// Store admin always in byID. ID must be unique.
if _, loaded := c.byID.LoadOrStore(adm.ID, adm); loaded {
if _, loaded := c.byID.LoadOrStore(adm.Id, adm); loaded {
return errors.New("cannot add multiple admins with the same id")
}
provName := adm.ProvisionerName
// Store admin alwasy in bySubProv. Subject <-> ProvisionerName must be unique.
provName := p.GetName()
// Store admin always in bySubProv. Subject <-> ProvisionerName must be unique.
if _, loaded := c.bySubProv.LoadOrStore(subProvNameHash(adm.Subject, provName), adm); loaded {
c.byID.Delete(adm.ID)
c.byID.Delete(adm.Id)
return errors.New("cannot add multiple admins with the same subject and provisioner")
}
@ -108,7 +107,7 @@ func (c *Collection) Store(adm *Admin) error {
c.byProv.Store(provName, append(admins, adm))
c.superCountByProvisioner[provName]++
} else {
c.byProv.Store(provName, []*Admin{adm})
c.byProv.Store(provName, []*linkedca.Admin{adm})
c.superCountByProvisioner[provName] = 1
}
c.superCount++
@ -118,7 +117,7 @@ func (c *Collection) Store(adm *Admin) error {
// Using big endian format to get the strings sorted:
// 0x00000000, 0x00000001, 0x00000002, ...
bi := make([]byte, 4)
_sum := sha1.Sum([]byte(adm.ID))
_sum := sha1.Sum([]byte(adm.Id))
sum := _sum[:]
binary.BigEndian.PutUint32(bi, uint32(c.sorted.Len()))
sum[0], sum[1], sum[2], sum[3] = bi[0], bi[1], bi[2], bi[3]
@ -145,7 +144,7 @@ func (c *Collection) SuperCountByProvisioner(provName string) int {
}
// Find implements pagination on a list of sorted provisioners.
func (c *Collection) Find(cursor string, limit int) ([]*Admin, string) {
func (c *Collection) Find(cursor string, limit int) ([]*linkedca.Admin, string) {
switch {
case limit <= 0:
limit = DefaultAdminLimit
@ -157,7 +156,7 @@ func (c *Collection) Find(cursor string, limit int) ([]*Admin, string) {
cursor = fmt.Sprintf("%040s", cursor)
i := sort.Search(n, func(i int) bool { return c.sorted[i].uid >= cursor })
slice := []*Admin{}
slice := []*linkedca.Admin{}
for ; i < n && len(slice) < limit; i++ {
slice = append(slice, c.sorted[i].admin)
}
@ -168,12 +167,12 @@ func (c *Collection) Find(cursor string, limit int) ([]*Admin, string) {
return slice, ""
}
func loadAdmin(m *sync.Map, key string) (*Admin, bool) {
func loadAdmin(m *sync.Map, key string) (*linkedca.Admin, bool) {
a, ok := m.Load(key)
if !ok {
return nil, false
}
adm, ok := a.(*Admin)
adm, ok := a.(*linkedca.Admin)
if !ok {
return nil, false
}

View file

@ -1,23 +0,0 @@
package mgmt
import (
"github.com/smallstep/certificates/authority/admin"
)
// AdminType specifies the type of the admin. e.g. SUPER_ADMIN, REGULAR
type AdminType admin.Type
var (
// AdminTypeSuper superadmin
AdminTypeSuper = admin.TypeSuper
// AdminTypeRegular regular
AdminTypeRegular = admin.TypeRegular
)
// Admin type.
type Admin admin.Admin
// ToCertificates converts an Admin to the Admin type expected by the authority.
func (adm *Admin) ToCertificates() (*admin.Admin, error) {
return (*admin.Admin)(adm), nil
}

View file

@ -1,68 +0,0 @@
package mgmt
import (
"github.com/smallstep/certificates/authority/admin"
"github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/authority/status"
)
// AuthConfig represents the Authority Configuration.
type AuthConfig struct {
//*cas.Options `json:"cas"`
ID string `json:"id"`
ASN1DN *config.ASN1DN `json:"asn1dn,omitempty"`
Provisioners []*Provisioner `json:"-"`
Admins []*Admin `json:"-"`
Claims *Claims `json:"claims,omitempty"`
Backdate string `json:"backdate,omitempty"`
Status status.Type `json:"status,omitempty"`
}
func NewDefaultAuthConfig() *AuthConfig {
return &AuthConfig{
Claims: NewDefaultClaims(),
ASN1DN: &config.ASN1DN{},
Backdate: config.DefaultBackdate.String(),
Status: status.Active,
}
}
// ToCertificates converts a mgmt AuthConfig to configuration that can be
// directly used by the `step-ca` process. Resources are normalized and
// initialized.
func (ac *AuthConfig) ToCertificates() (*config.AuthConfig, error) {
claims, err := ac.Claims.ToCertificates()
if err != nil {
return nil, err
}
backdate, err := provisioner.NewDuration(ac.Backdate)
if err != nil {
return nil, WrapErrorISE(err, "error converting backdate %s to duration", ac.Backdate)
}
var provs []provisioner.Interface
for _, p := range ac.Provisioners {
authProv, err := p.ToCertificates()
if err != nil {
return nil, err
}
provs = append(provs, authProv)
}
var admins []*admin.Admin
for _, adm := range ac.Admins {
authAdmin, err := adm.ToCertificates()
if err != nil {
return nil, err
}
admins = append(admins, authAdmin)
}
return &config.AuthConfig{
AuthorityID: ac.ID,
Provisioners: provs,
Admins: admins,
Template: ac.ASN1DN,
Claims: claims,
DisableIssuedAtCheck: false,
Backdate: backdate,
}, nil
}

View file

@ -1,9 +1,6 @@
package mgmt
import (
"context"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/config"
)
@ -66,19 +63,7 @@ func NewDefaultClaims() *Claims {
}
}
type AuthorityOption func(*AuthConfig) error
func WithDefaultAuthorityID(ac *AuthConfig) error {
ac.ID = DefaultAuthorityID
return nil
}
func CreateDefaultAuthority(ctx context.Context, db DB) (*AuthConfig, error) {
options := []AuthorityOption{WithDefaultAuthorityID}
return CreateAuthority(ctx, db, options...)
}
/*
func CreateAuthority(ctx context.Context, db DB, options ...AuthorityOption) (*AuthConfig, error) {
ac := NewDefaultAuthConfig()
@ -116,3 +101,4 @@ func CreateAuthority(ctx context.Context, db DB, options ...AuthorityOption) (*A
return ac, nil
}
*/

View file

@ -4,6 +4,7 @@ import (
"context"
"github.com/pkg/errors"
"github.com/smallstep/certificates/linkedca"
)
// ErrNotFound is an error that should be used by the authority.DB interface to
@ -12,44 +13,36 @@ var ErrNotFound = errors.New("not found")
// DB is the DB interface expected by the step-ca ACME API.
type DB interface {
CreateProvisioner(ctx context.Context, prov *Provisioner) error
GetProvisioner(ctx context.Context, id string) (*Provisioner, error)
GetProvisioners(ctx context.Context) ([]*Provisioner, error)
UpdateProvisioner(ctx context.Context, prov *Provisioner) error
CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error
GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error)
GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error)
UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error
CreateAdmin(ctx context.Context, admin *Admin) error
GetAdmin(ctx context.Context, id string) (*Admin, error)
GetAdmins(ctx context.Context) ([]*Admin, error)
UpdateAdmin(ctx context.Context, admin *Admin) error
CreateAuthConfig(ctx context.Context, ac *AuthConfig) error
GetAuthConfig(ctx context.Context, id string) (*AuthConfig, error)
UpdateAuthConfig(ctx context.Context, ac *AuthConfig) error
CreateAdmin(ctx context.Context, admin *linkedca.Admin) error
GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error)
GetAdmins(ctx context.Context) ([]*linkedca.Admin, error)
UpdateAdmin(ctx context.Context, admin *linkedca.Admin) error
}
// MockDB is an implementation of the DB interface that should only be used as
// a mock in tests.
type MockDB struct {
MockCreateProvisioner func(ctx context.Context, prov *Provisioner) error
MockGetProvisioner func(ctx context.Context, id string) (*Provisioner, error)
MockGetProvisioners func(ctx context.Context) ([]*Provisioner, error)
MockUpdateProvisioner func(ctx context.Context, prov *Provisioner) error
MockCreateProvisioner func(ctx context.Context, prov *linkedca.Provisioner) error
MockGetProvisioner func(ctx context.Context, id string) (*linkedca.Provisioner, error)
MockGetProvisioners func(ctx context.Context) ([]*linkedca.Provisioner, error)
MockUpdateProvisioner func(ctx context.Context, prov *linkedca.Provisioner) error
MockCreateAdmin func(ctx context.Context, adm *Admin) error
MockGetAdmin func(ctx context.Context, id string) (*Admin, error)
MockGetAdmins func(ctx context.Context) ([]*Admin, error)
MockUpdateAdmin func(ctx context.Context, adm *Admin) error
MockCreateAuthConfig func(ctx context.Context, ac *AuthConfig) error
MockGetAuthConfig func(ctx context.Context, id string) (*AuthConfig, error)
MockUpdateAuthConfig func(ctx context.Context, ac *AuthConfig) error
MockCreateAdmin func(ctx context.Context, adm *linkedca.Admin) error
MockGetAdmin func(ctx context.Context, id string) (*linkedca.Admin, error)
MockGetAdmins func(ctx context.Context) ([]*linkedca.Admin, error)
MockUpdateAdmin func(ctx context.Context, adm *linkedca.Admin) error
MockError error
MockRet1 interface{}
}
// CreateProvisioner mock.
func (m *MockDB) CreateProvisioner(ctx context.Context, prov *Provisioner) error {
func (m *MockDB) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
if m.MockCreateProvisioner != nil {
return m.MockCreateProvisioner(ctx, prov)
} else if m.MockError != nil {
@ -59,27 +52,27 @@ func (m *MockDB) CreateProvisioner(ctx context.Context, prov *Provisioner) error
}
// GetProvisioner mock.
func (m *MockDB) GetProvisioner(ctx context.Context, id string) (*Provisioner, error) {
func (m *MockDB) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) {
if m.MockGetProvisioner != nil {
return m.MockGetProvisioner(ctx, id)
} else if m.MockError != nil {
return nil, m.MockError
}
return m.MockRet1.(*Provisioner), m.MockError
return m.MockRet1.(*linkedca.Provisioner), m.MockError
}
// GetProvisioners mock
func (m *MockDB) GetProvisioners(ctx context.Context) ([]*Provisioner, error) {
func (m *MockDB) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
if m.MockGetProvisioners != nil {
return m.MockGetProvisioners(ctx)
} else if m.MockError != nil {
return nil, m.MockError
}
return m.MockRet1.([]*Provisioner), m.MockError
return m.MockRet1.([]*linkedca.Provisioner), m.MockError
}
// UpdateProvisioner mock
func (m *MockDB) UpdateProvisioner(ctx context.Context, prov *Provisioner) error {
func (m *MockDB) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
if m.MockUpdateProvisioner != nil {
return m.MockUpdateProvisioner(ctx, prov)
}
@ -87,7 +80,7 @@ func (m *MockDB) UpdateProvisioner(ctx context.Context, prov *Provisioner) error
}
// CreateAdmin mock
func (m *MockDB) CreateAdmin(ctx context.Context, admin *Admin) error {
func (m *MockDB) CreateAdmin(ctx context.Context, admin *linkedca.Admin) error {
if m.MockCreateAdmin != nil {
return m.MockCreateAdmin(ctx, admin)
}
@ -95,55 +88,29 @@ func (m *MockDB) CreateAdmin(ctx context.Context, admin *Admin) error {
}
// GetAdmin mock.
func (m *MockDB) GetAdmin(ctx context.Context, id string) (*Admin, error) {
func (m *MockDB) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) {
if m.MockGetAdmin != nil {
return m.MockGetAdmin(ctx, id)
} else if m.MockError != nil {
return nil, m.MockError
}
return m.MockRet1.(*Admin), m.MockError
return m.MockRet1.(*linkedca.Admin), m.MockError
}
// GetAdmins mock
func (m *MockDB) GetAdmins(ctx context.Context) ([]*Admin, error) {
func (m *MockDB) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
if m.MockGetAdmins != nil {
return m.MockGetAdmins(ctx)
} else if m.MockError != nil {
return nil, m.MockError
}
return m.MockRet1.([]*Admin), m.MockError
return m.MockRet1.([]*linkedca.Admin), m.MockError
}
// UpdateAdmin mock
func (m *MockDB) UpdateAdmin(ctx context.Context, adm *Admin) error {
func (m *MockDB) UpdateAdmin(ctx context.Context, adm *linkedca.Admin) error {
if m.MockUpdateAdmin != nil {
return m.MockUpdateAdmin(ctx, adm)
}
return m.MockError
}
// CreateAuthConfig mock
func (m *MockDB) CreateAuthConfig(ctx context.Context, admin *AuthConfig) error {
if m.MockCreateAuthConfig != nil {
return m.MockCreateAuthConfig(ctx, admin)
}
return m.MockError
}
// GetAuthConfig mock.
func (m *MockDB) GetAuthConfig(ctx context.Context, id string) (*AuthConfig, error) {
if m.MockGetAuthConfig != nil {
return m.MockGetAuthConfig(ctx, id)
} else if m.MockError != nil {
return nil, m.MockError
}
return m.MockRet1.(*AuthConfig), m.MockError
}
// UpdateAuthConfig mock
func (m *MockDB) UpdateAuthConfig(ctx context.Context, adm *AuthConfig) error {
if m.MockUpdateAuthConfig != nil {
return m.MockUpdateAuthConfig(ctx, adm)
}
return m.MockError
}

View file

@ -1,31 +1,15 @@
package mgmt
import (
"context"
"encoding/json"
"fmt"
"github.com/smallstep/certificates/authority/provisioner"
"github.com/smallstep/certificates/authority/status"
"github.com/smallstep/certificates/linkedca"
"go.step.sm/crypto/jose"
)
type ProvisionerOption func(*ProvisionerCtx)
type ProvisionerType string
var (
ProvisionerTypeACME = ProvisionerType("ACME")
ProvisionerTypeAWS = ProvisionerType("AWS")
ProvisionerTypeAZURE = ProvisionerType("AZURE")
ProvisionerTypeGCP = ProvisionerType("GCP")
ProvisionerTypeJWK = ProvisionerType("JWK")
ProvisionerTypeK8SSA = ProvisionerType("K8SSA")
ProvisionerTypeOIDC = ProvisionerType("OIDC")
ProvisionerTypeSSHPOP = ProvisionerType("SSHPOP")
ProvisionerTypeX5C = ProvisionerType("X5C")
)
/*
type unmarshalProvisioner struct {
ID string `json:"-"`
AuthorityID string `json:"-"`
@ -40,23 +24,8 @@ type unmarshalProvisioner struct {
Status status.Type `json:"status"`
}
// Provisioner type.
type Provisioner struct {
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"`
}
type typ struct {
Type ProvisionerType `json:"type"`
Type linkedca.Provisioner_Type `json:"type"`
}
// UnmarshalJSON implements the Unmarshal interface.
@ -86,287 +55,48 @@ func (p *Provisioner) UnmarshalJSON(b []byte) error {
return nil
}
*/
func (p *Provisioner) GetOptions() *provisioner.Options {
func provisionerGetOptions(p *linkedca.Provisioner) *provisioner.Options {
return &provisioner.Options{
X509: &provisioner.X509Options{
Template: p.X509Template,
Template: string(p.X509Template),
TemplateData: p.X509TemplateData,
},
SSH: &provisioner.SSHOptions{
Template: p.SSHTemplate,
TemplateData: p.SSHTemplateData,
Template: string(p.SshTemplate),
TemplateData: p.SshTemplateData,
},
}
}
func CreateProvisioner(ctx context.Context, db DB, typ, name string, opts ...ProvisionerOption) (*Provisioner, error) {
pc := NewProvisionerCtx(opts...)
details, err := NewProvisionerDetails(ProvisionerType(typ), pc)
if err != nil {
return nil, err
}
p := &Provisioner{
Type: typ,
Name: name,
Claims: pc.Claims,
Details: details,
X509Template: pc.X509Template,
X509TemplateData: pc.X509TemplateData,
SSHTemplate: pc.SSHTemplate,
SSHTemplateData: pc.SSHTemplateData,
Status: status.Active,
}
if err := db.CreateProvisioner(ctx, p); err != nil {
return nil, WrapErrorISE(err, "error creating provisioner")
}
return p, nil
}
type ProvisionerCtx struct {
JWK *jose.JSONWebKey
JWE *jose.JSONWebEncryption
X509Template, SSHTemplate string
X509TemplateData, SSHTemplateData []byte
Claims *Claims
Password string
}
func NewProvisionerCtx(opts ...ProvisionerOption) *ProvisionerCtx {
pc := &ProvisionerCtx{
Claims: NewDefaultClaims(),
}
for _, o := range opts {
o(pc)
}
return pc
}
func WithJWK(jwk *jose.JSONWebKey, jwe *jose.JSONWebEncryption) func(*ProvisionerCtx) {
return func(ctx *ProvisionerCtx) {
ctx.JWK = jwk
ctx.JWE = jwe
}
}
func WithPassword(pass string) func(*ProvisionerCtx) {
return func(ctx *ProvisionerCtx) {
ctx.Password = pass
}
}
// ProvisionerDetails is the interface implemented by all provisioner details
// attributes.
type ProvisionerDetails interface {
isProvisionerDetails()
}
// ProvisionerDetailsJWK represents the values required by a JWK provisioner.
type ProvisionerDetailsJWK struct {
Type ProvisionerType `json:"type"`
PublicKey []byte `json:"publicKey"`
PrivateKey string `json:"PrivateKey"`
}
// ProvisionerDetailsOIDC represents the values required by a OIDC provisioner.
type ProvisionerDetailsOIDC struct {
Type ProvisionerType `json:"type"`
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
ConfigurationEndpoint string `json:"configurationEndpoint"`
Admins []string `json:"admins"`
Domains []string `json:"domains"`
Groups []string `json:"groups"`
ListenAddress string `json:"listenAddress"`
TenantID string `json:"tenantID"`
}
// ProvisionerDetailsGCP represents the values required by a GCP provisioner.
type ProvisionerDetailsGCP struct {
Type ProvisionerType `json:"type"`
ServiceAccounts []string `json:"serviceAccounts"`
ProjectIDs []string `json:"projectIDs"`
DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge string `json:"instanceAge"`
}
// ProvisionerDetailsAWS represents the values required by a AWS provisioner.
type ProvisionerDetailsAWS struct {
Type ProvisionerType `json:"type"`
Accounts []string `json:"accounts"`
DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
InstanceAge string `json:"instanceAge"`
}
// ProvisionerDetailsAzure represents the values required by a Azure provisioner.
type ProvisionerDetailsAzure struct {
Type ProvisionerType `json:"type"`
ResourceGroups []string `json:"resourceGroups"`
Audience string `json:"audience"`
DisableCustomSANs bool `json:"disableCustomSANs"`
DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"`
}
// ProvisionerDetailsACME represents the values required by a ACME provisioner.
type ProvisionerDetailsACME struct {
Type ProvisionerType `json:"type"`
ForceCN bool `json:"forceCN"`
}
// ProvisionerDetailsX5C represents the values required by a X5C provisioner.
type ProvisionerDetailsX5C struct {
Type ProvisionerType `json:"type"`
Roots []byte `json:"roots"`
}
// ProvisionerDetailsK8SSA represents the values required by a K8SSA provisioner.
type ProvisionerDetailsK8SSA struct {
Type ProvisionerType `json:"type"`
PublicKeys []byte `json:"publicKeys"`
}
// ProvisionerDetailsSSHPOP represents the values required by a SSHPOP provisioner.
type ProvisionerDetailsSSHPOP struct {
Type ProvisionerType `json:"type"`
}
func (*ProvisionerDetailsJWK) isProvisionerDetails() {}
func (*ProvisionerDetailsOIDC) isProvisionerDetails() {}
func (*ProvisionerDetailsGCP) isProvisionerDetails() {}
func (*ProvisionerDetailsAWS) isProvisionerDetails() {}
func (*ProvisionerDetailsAzure) isProvisionerDetails() {}
func (*ProvisionerDetailsACME) isProvisionerDetails() {}
func (*ProvisionerDetailsX5C) isProvisionerDetails() {}
func (*ProvisionerDetailsK8SSA) isProvisionerDetails() {}
func (*ProvisionerDetailsSSHPOP) isProvisionerDetails() {}
func NewProvisionerDetails(typ ProvisionerType, pc *ProvisionerCtx) (ProvisionerDetails, error) {
switch typ {
case ProvisionerTypeJWK:
return createJWKDetails(pc)
/*
case ProvisionerTypeOIDC:
return createOIDCDetails(pc)
case ProvisionerTypeACME:
return createACMEDetails(pc)
case ProvisionerTypeK8SSA:
return createK8SSADetails(pc)
case ProvisionerTypeSSHPOP:
return createSSHPOPDetails(pc)
case ProvisionerTypeX5C:
return createSSHPOPDetails(pc)
*/
default:
return nil, NewErrorISE("unsupported provisioner type %s", typ)
}
}
func createJWKDetails(pc *ProvisionerCtx) (*ProvisionerDetailsJWK, error) {
var err error
if pc.JWK != nil && pc.JWE == nil {
return nil, NewErrorISE("JWE is required with JWK for createJWKProvisioner")
}
if pc.JWE != nil && pc.JWK == nil {
return nil, NewErrorISE("JWK is required with JWE for createJWKProvisioner")
}
if pc.JWK == nil && pc.JWE == nil {
// Create a new JWK w/ encrypted private key.
if pc.Password == "" {
return nil, NewErrorISE("password is required to provisioner with new keys")
}
pc.JWK, pc.JWE, err = jose.GenerateDefaultKeyPair([]byte(pc.Password))
if err != nil {
return nil, WrapErrorISE(err, "error generating JWK key pair")
}
}
jwkPubBytes, err := pc.JWK.MarshalJSON()
if err != nil {
return nil, WrapErrorISE(err, "error marshaling JWK")
}
jwePrivStr, err := pc.JWE.CompactSerialize()
if err != nil {
return nil, WrapErrorISE(err, "error serializing JWE")
}
return &ProvisionerDetailsJWK{
Type: ProvisionerTypeJWK,
PublicKey: jwkPubBytes,
PrivateKey: jwePrivStr,
}, nil
}
func createACMEDetails(pc *ProvisionerCtx) (*ProvisionerDetailsJWK, error) {
var err error
if pc.JWK != nil && pc.JWE == nil {
return nil, NewErrorISE("JWE is required with JWK for createJWKProvisioner")
}
if pc.JWE != nil && pc.JWK == nil {
return nil, NewErrorISE("JWK is required with JWE for createJWKProvisioner")
}
if pc.JWK == nil && pc.JWE == nil {
// Create a new JWK w/ encrypted private key.
if pc.Password == "" {
return nil, NewErrorISE("password is required to provisioner with new keys")
}
pc.JWK, pc.JWE, err = jose.GenerateDefaultKeyPair([]byte(pc.Password))
if err != nil {
return nil, WrapErrorISE(err, "error generating JWK key pair")
}
}
jwkPubBytes, err := pc.JWK.MarshalJSON()
if err != nil {
return nil, WrapErrorISE(err, "error marshaling JWK")
}
jwePrivStr, err := pc.JWE.CompactSerialize()
if err != nil {
return nil, WrapErrorISE(err, "error serializing JWE")
}
return &ProvisionerDetailsJWK{
Type: ProvisionerTypeJWK,
PublicKey: jwkPubBytes,
PrivateKey: jwePrivStr,
}, nil
}
// ToCertificates converts the landlord provisioner type to the open source
// provisionerToCertificates converts the landlord provisioner type to the open source
// provisioner type.
func (p *Provisioner) ToCertificates() (provisioner.Interface, error) {
claims, err := p.Claims.ToCertificates()
func provisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface, error) {
claims, err := claimsToCertificates(p.Claims)
if err != nil {
return nil, err
}
switch details := p.Details.(type) {
case *ProvisionerDetailsJWK:
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(details.PublicKey, &jwk); err != nil {
if err := json.Unmarshal(d.JWK.PublicKey, &jwk); err != nil {
return nil, err
}
return &provisioner.JWK{
ID: p.ID,
Type: p.Type,
ID: p.Id,
Type: p.Type.String(),
Name: p.Name,
Key: jwk,
EncryptedKey: details.PrivateKey,
EncryptedKey: string(d.JWK.EncryptedPrivateKey),
Claims: claims,
Options: p.GetOptions(),
Options: provisionerGetOptions(p),
}, nil
/*
case *ProvisionerDetails_OIDC:
@ -478,9 +208,9 @@ func (p *Provisioner) ToCertificates() (provisioner.Interface, error) {
}
}
// ToCertificates converts the landlord provisioner claims type to the open source
// claimsToCertificates converts the landlord provisioner claims type to the open source
// (step-ca) claims type.
func (c *Claims) ToCertificates() (*provisioner.Claims, error) {
func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
var durs = map[string]struct {
durStr string
dur *provisioner.Duration
@ -488,12 +218,12 @@ func (c *Claims) ToCertificates() (*provisioner.Claims, error) {
"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},
"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 {
@ -513,10 +243,11 @@ func (c *Claims) ToCertificates() (*provisioner.Claims, error) {
MinHostSSHDur: durs["minSSHHostDur"].dur,
MaxHostSSHDur: durs["maxSSHHostDur"].dur,
DefaultHostSSHDur: durs["defaultSSHHostDur"].dur,
EnableSSHCA: &c.SSH.Enabled,
EnableSSHCA: &c.Ssh.Enabled,
}, nil
}
/*
type detailsType struct {
Type ProvisionerType
}
@ -557,3 +288,4 @@ func UnmarshalProvisionerDetails(data json.RawMessage) (ProvisionerDetails, erro
}
return v, nil
}
*/