wip
This commit is contained in:
parent
3f30552b60
commit
423942da44
7 changed files with 84 additions and 516 deletions
|
@ -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"`
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue