This commit is contained in:
max furman 2021-05-25 16:52:06 -07:00
parent 423942da44
commit 1726076ea2
9 changed files with 154 additions and 298 deletions

View file

@ -178,12 +178,3 @@ func loadAdmin(m *sync.Map, key string) (*linkedca.Admin, bool) {
} }
return adm, true return adm, true
} }
/*
// provisionerSum returns the SHA1 of the provisioners ID. From this we will
// create the unique and sorted id.
func provisionerSum(p Interface) []byte {
sum := sha1.Sum([]byte(p.GetID()))
return sum[:]
}
*/

View file

@ -8,11 +8,11 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/admin"
"github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/authority/provisioner"
cas "github.com/smallstep/certificates/cas/apiv1" cas "github.com/smallstep/certificates/cas/apiv1"
"github.com/smallstep/certificates/db" "github.com/smallstep/certificates/db"
kms "github.com/smallstep/certificates/kms/apiv1" kms "github.com/smallstep/certificates/kms/apiv1"
"github.com/smallstep/certificates/linkedca"
"github.com/smallstep/certificates/templates" "github.com/smallstep/certificates/templates"
) )
@ -96,7 +96,7 @@ type AuthConfig struct {
*cas.Options *cas.Options
AuthorityID string `json:"authorityID,omitempty"` AuthorityID string `json:"authorityID,omitempty"`
Provisioners provisioner.List `json:"provisioners"` Provisioners provisioner.List `json:"provisioners"`
Admins []*admin.Admin `json:"-"` Admins []*linkedca.Admin `json:"-"`
Template *ASN1DN `json:"template,omitempty"` Template *ASN1DN `json:"template,omitempty"`
Claims *provisioner.Claims `json:"claims,omitempty"` Claims *provisioner.Claims `json:"claims,omitempty"`
DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"` DisableIssuedAtCheck bool `json:"disableIssuedAtCheck,omitempty"`

View file

@ -2,6 +2,7 @@ package mgmt
import ( import (
"github.com/smallstep/certificates/authority/config" "github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/linkedca"
) )
const ( const (
@ -11,49 +12,22 @@ const (
DefaultAuthorityID = "00000000-0000-0000-0000-000000000000" DefaultAuthorityID = "00000000-0000-0000-0000-000000000000"
) )
// Claims encapsulates all x509 and ssh claims applied to the authority func NewDefaultClaims() *linkedca.Claims {
// configuration. E.g. maxTLSCertDuration, defaultSSHCertDuration, etc. return &linkedca.Claims{
type Claims struct { X509: &linkedca.X509Claims{
X509 *X509Claims `json:"x509Claims"` Durations: &linkedca.Durations{
SSH *SSHClaims `json:"sshClaims"`
DisableRenewal bool `json:"disableRenewal"`
}
// X509Claims are the x509 claims applied to the authority.
type X509Claims struct {
Durations *Durations `json:"durations"`
}
// SSHClaims are the ssh claims applied to the authority.
type SSHClaims struct {
Enabled bool `json:"enabled"`
UserDurations *Durations `json:"userDurations"`
HostDurations *Durations `json:"hostDurations"`
}
// Durations represents min, max, default, duration.
type Durations struct {
Min string `json:"min"`
Max string `json:"max"`
Default string `json:"default"`
}
func NewDefaultClaims() *Claims {
return &Claims{
X509: &X509Claims{
Durations: &Durations{
Min: config.GlobalProvisionerClaims.MinTLSDur.String(), Min: config.GlobalProvisionerClaims.MinTLSDur.String(),
Max: config.GlobalProvisionerClaims.MaxTLSDur.String(), Max: config.GlobalProvisionerClaims.MaxTLSDur.String(),
Default: config.GlobalProvisionerClaims.DefaultTLSDur.String(), Default: config.GlobalProvisionerClaims.DefaultTLSDur.String(),
}, },
}, },
SSH: &SSHClaims{ Ssh: &linkedca.SSHClaims{
UserDurations: &Durations{ UserDurations: &linkedca.Durations{
Min: config.GlobalProvisionerClaims.MinUserSSHDur.String(), Min: config.GlobalProvisionerClaims.MinUserSSHDur.String(),
Max: config.GlobalProvisionerClaims.MaxUserSSHDur.String(), Max: config.GlobalProvisionerClaims.MaxUserSSHDur.String(),
Default: config.GlobalProvisionerClaims.DefaultUserSSHDur.String(), Default: config.GlobalProvisionerClaims.DefaultUserSSHDur.String(),
}, },
HostDurations: &Durations{ HostDurations: &linkedca.Durations{
Min: config.GlobalProvisionerClaims.MinHostSSHDur.String(), Min: config.GlobalProvisionerClaims.MinHostSSHDur.String(),
Max: config.GlobalProvisionerClaims.MaxHostSSHDur.String(), Max: config.GlobalProvisionerClaims.MaxHostSSHDur.String(),
Default: config.GlobalProvisionerClaims.DefaultHostSSHDur.String(), Default: config.GlobalProvisionerClaims.DefaultHostSSHDur.String(),

View file

@ -17,11 +17,13 @@ type DB interface {
GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error)
GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error)
UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error
DeleteProvisioner(ctx context.Context, id string) error
CreateAdmin(ctx context.Context, admin *linkedca.Admin) error CreateAdmin(ctx context.Context, admin *linkedca.Admin) error
GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error)
GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error)
UpdateAdmin(ctx context.Context, admin *linkedca.Admin) error UpdateAdmin(ctx context.Context, admin *linkedca.Admin) error
DeleteAdmin(ctx context.Context, id string) error
} }
// MockDB is an implementation of the DB interface that should only be used as // MockDB is an implementation of the DB interface that should only be used as
@ -31,11 +33,13 @@ type MockDB struct {
MockGetProvisioner func(ctx context.Context, id string) (*linkedca.Provisioner, error) MockGetProvisioner func(ctx context.Context, id string) (*linkedca.Provisioner, error)
MockGetProvisioners func(ctx context.Context) ([]*linkedca.Provisioner, error) MockGetProvisioners func(ctx context.Context) ([]*linkedca.Provisioner, error)
MockUpdateProvisioner func(ctx context.Context, prov *linkedca.Provisioner) error MockUpdateProvisioner func(ctx context.Context, prov *linkedca.Provisioner) error
MockDeleteProvisioner func(ctx context.Context, id string) error
MockCreateAdmin func(ctx context.Context, adm *linkedca.Admin) error MockCreateAdmin func(ctx context.Context, adm *linkedca.Admin) error
MockGetAdmin func(ctx context.Context, id string) (*linkedca.Admin, error) MockGetAdmin func(ctx context.Context, id string) (*linkedca.Admin, error)
MockGetAdmins func(ctx context.Context) ([]*linkedca.Admin, error) MockGetAdmins func(ctx context.Context) ([]*linkedca.Admin, error)
MockUpdateAdmin func(ctx context.Context, adm *linkedca.Admin) error MockUpdateAdmin func(ctx context.Context, adm *linkedca.Admin) error
MockDeleteAdmin func(ctx context.Context, id string) error
MockError error MockError error
MockRet1 interface{} MockRet1 interface{}
@ -79,6 +83,14 @@ func (m *MockDB) UpdateProvisioner(ctx context.Context, prov *linkedca.Provision
return m.MockError return m.MockError
} }
// DeleteProvisioner mock
func (m *MockDB) DeleteProvisioner(ctx context.Context, id string) error {
if m.MockDeleteProvisioner != nil {
return m.MockDeleteProvisioner(ctx, id)
}
return m.MockError
}
// CreateAdmin mock // CreateAdmin mock
func (m *MockDB) CreateAdmin(ctx context.Context, admin *linkedca.Admin) error { func (m *MockDB) CreateAdmin(ctx context.Context, admin *linkedca.Admin) error {
if m.MockCreateAdmin != nil { if m.MockCreateAdmin != nil {
@ -114,3 +126,11 @@ func (m *MockDB) UpdateAdmin(ctx context.Context, adm *linkedca.Admin) error {
} }
return m.MockError return m.MockError
} }
// DeleteAdmin mock
func (m *MockDB) DeleteAdmin(ctx context.Context, id string) error {
if m.MockDeleteAdmin != nil {
return m.MockDeleteAdmin(ctx, id)
}
return m.MockError
}

View file

@ -6,21 +6,20 @@ import (
"time" "time"
"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"
"github.com/smallstep/certificates/authority/status" "github.com/smallstep/certificates/linkedca"
"github.com/smallstep/nosql" "github.com/smallstep/nosql"
) )
// dbAdmin is the database representation of the Admin type. // dbAdmin is the database representation of the Admin type.
type dbAdmin struct { type dbAdmin struct {
ID string `json:"id"` ID string `json:"id"`
AuthorityID string `json:"authorityID"` AuthorityID string `json:"authorityID"`
ProvisionerID string `json:"provisionerID"` ProvisionerID string `json:"provisionerID"`
Subject string `json:"subject"` Subject string `json:"subject"`
Type admin.Type `json:"type"` Type linkedca.Admin_Type `json:"type"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
DeletedAt time.Time `json:"deletedAt"` DeletedAt time.Time `json:"deletedAt"`
} }
func (dbp *dbAdmin) clone() *dbAdmin { func (dbp *dbAdmin) clone() *dbAdmin {
@ -59,30 +58,28 @@ func unmarshalDBAdmin(data []byte, id string) (*dbAdmin, error) {
if err := json.Unmarshal(data, dba); err != nil { if err := json.Unmarshal(data, dba); err != nil {
return nil, errors.Wrapf(err, "error unmarshaling admin %s into dbAdmin", id) return nil, errors.Wrapf(err, "error unmarshaling admin %s into dbAdmin", id)
} }
if !dba.DeletedAt.IsZero() {
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "admin %s is deleted", id)
}
return dba, nil return dba, nil
} }
func unmarshalAdmin(data []byte, id string) (*mgmt.Admin, error) { func unmarshalAdmin(data []byte, id string) (*linkedca.Admin, error) {
var dba = new(dbAdmin) dba, err := unmarshalDBAdmin(data, id)
if err := json.Unmarshal(data, dba); err != nil { if err != nil {
return nil, errors.Wrapf(err, "error unmarshaling admin %s into dbAdmin", id) return nil, err
} }
adm := &mgmt.Admin{ return &linkedca.Admin{
ID: dba.ID, Id: dba.ID,
AuthorityID: dba.AuthorityID, AuthorityId: dba.AuthorityID,
ProvisionerID: dba.ProvisionerID, ProvisionerId: dba.ProvisionerID,
Subject: dba.Subject, Subject: dba.Subject,
Type: dba.Type, Type: dba.Type,
Status: status.Active, }, nil
}
if !dba.DeletedAt.IsZero() {
adm.Status = status.Deleted
}
return adm, nil
} }
// GetAdmin retrieves and unmarshals a admin from the database. // GetAdmin retrieves and unmarshals a admin from the database.
func (db *DB) GetAdmin(ctx context.Context, id string) (*mgmt.Admin, error) { func (db *DB) GetAdmin(ctx context.Context, id string) (*linkedca.Admin, error) {
data, err := db.getDBAdminBytes(ctx, id) data, err := db.getDBAdminBytes(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -91,12 +88,9 @@ func (db *DB) GetAdmin(ctx context.Context, id string) (*mgmt.Admin, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if adm.Status == status.Deleted { if adm.AuthorityId != db.authorityID {
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "admin %s is deleted", adm.ID)
}
if adm.AuthorityID != db.authorityID {
return nil, mgmt.NewError(mgmt.ErrorAuthorityMismatchType, return nil, mgmt.NewError(mgmt.ErrorAuthorityMismatchType,
"admin %s is not owned by authority %s", adm.ID, db.authorityID) "admin %s is not owned by authority %s", adm.Id, db.authorityID)
} }
return adm, nil return adm, nil
@ -105,21 +99,18 @@ func (db *DB) GetAdmin(ctx context.Context, id string) (*mgmt.Admin, error) {
// GetAdmins retrieves and unmarshals all active (not deleted) admins // GetAdmins retrieves and unmarshals all active (not deleted) admins
// from the database. // from the database.
// TODO should we be paginating? // TODO should we be paginating?
func (db *DB) GetAdmins(ctx context.Context) ([]*mgmt.Admin, error) { func (db *DB) GetAdmins(ctx context.Context) ([]*linkedca.Admin, error) {
dbEntries, err := db.db.List(authorityAdminsTable) dbEntries, err := db.db.List(authorityAdminsTable)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error loading admins") return nil, errors.Wrap(err, "error loading admins")
} }
var admins = []*mgmt.Admin{} var admins = []*linkedca.Admin{}
for _, entry := range dbEntries { for _, entry := range dbEntries {
adm, err := unmarshalAdmin(entry.Value, string(entry.Key)) adm, err := unmarshalAdmin(entry.Value, string(entry.Key))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if adm.Status == status.Deleted { if adm.AuthorityId != db.authorityID {
continue
}
if adm.AuthorityID != db.authorityID {
continue continue
} }
admins = append(admins, adm) admins = append(admins, adm)
@ -128,18 +119,18 @@ func (db *DB) GetAdmins(ctx context.Context) ([]*mgmt.Admin, error) {
} }
// CreateAdmin stores a new admin to the database. // CreateAdmin stores a new admin to the database.
func (db *DB) CreateAdmin(ctx context.Context, adm *mgmt.Admin) error { func (db *DB) CreateAdmin(ctx context.Context, adm *linkedca.Admin) error {
var err error var err error
adm.ID, err = randID() adm.Id, err = randID()
if err != nil { if err != nil {
return mgmt.WrapErrorISE(err, "error generating random id for admin") return mgmt.WrapErrorISE(err, "error generating random id for admin")
} }
adm.AuthorityID = db.authorityID adm.AuthorityId = db.authorityID
dba := &dbAdmin{ dba := &dbAdmin{
ID: adm.ID, ID: adm.Id,
AuthorityID: db.authorityID, AuthorityID: db.authorityID,
ProvisionerID: adm.ProvisionerID, ProvisionerID: adm.ProvisionerId,
Subject: adm.Subject, Subject: adm.Subject,
Type: adm.Type, Type: adm.Type,
CreatedAt: clock.Now(), CreatedAt: clock.Now(),
@ -149,19 +140,27 @@ func (db *DB) CreateAdmin(ctx context.Context, adm *mgmt.Admin) error {
} }
// UpdateAdmin saves an updated admin to the database. // UpdateAdmin saves an updated admin to the database.
func (db *DB) UpdateAdmin(ctx context.Context, adm *mgmt.Admin) error { func (db *DB) UpdateAdmin(ctx context.Context, adm *linkedca.Admin) error {
old, err := db.getDBAdmin(ctx, adm.ID) old, err := db.getDBAdmin(ctx, adm.Id)
if err != nil { if err != nil {
return err return err
} }
nu := old.clone() nu := old.clone()
// If the admin was active but is now deleted ...
if old.DeletedAt.IsZero() && adm.Status == status.Deleted {
nu.DeletedAt = clock.Now()
}
nu.Type = adm.Type nu.Type = adm.Type
return db.save(ctx, old.ID, nu, old, "admin", authorityAdminsTable) return db.save(ctx, old.ID, nu, old, "admin", authorityAdminsTable)
} }
// DeleteAdmin saves an updated admin to the database.
func (db *DB) DeleteAdmin(ctx context.Context, id string) error {
old, err := db.getDBAdmin(ctx, id)
if err != nil {
return err
}
nu := old.clone()
nu.DeletedAt = clock.Now()
return db.save(ctx, old.ID, nu, old, "admin", authorityAdminsTable)
}

View file

@ -1,117 +0,0 @@
package nosql
import (
"context"
"encoding/json"
"time"
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority/config"
"github.com/smallstep/certificates/authority/mgmt"
"github.com/smallstep/certificates/authority/status"
"github.com/smallstep/nosql"
)
type dbAuthConfig struct {
ID string `json:"id"`
ASN1DN *config.ASN1DN `json:"asn1dn"`
Claims *mgmt.Claims `json:"claims"`
Backdate string `json:"backdate,omitempty"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt time.Time `json:"deletedAt"`
}
func (dbp *dbAuthConfig) clone() *dbAuthConfig {
u := *dbp
return &u
}
func (db *DB) getDBAuthConfigBytes(ctx context.Context, id string) ([]byte, error) {
data, err := db.db.Get(authorityConfigsTable, []byte(id))
if nosql.IsErrNotFound(err) {
return nil, mgmt.NewError(mgmt.ErrorNotFoundType, "authConfig %s not found", id)
} else if err != nil {
return nil, errors.Wrapf(err, "error loading authConfig %s", id)
}
return data, nil
}
func (db *DB) getDBAuthConfig(ctx context.Context, id string) (*dbAuthConfig, error) {
data, err := db.getDBAuthConfigBytes(ctx, id)
if err != nil {
return nil, err
}
var dba = new(dbAuthConfig)
if err = json.Unmarshal(data, dba); err != nil {
return nil, errors.Wrapf(err, "error unmarshaling authority %s into dbAuthConfig", id)
}
return dba, nil
}
// GetAuthConfig retrieves an AuthConfig configuration from the DB.
func (db *DB) GetAuthConfig(ctx context.Context, id string) (*mgmt.AuthConfig, error) {
dba, err := db.getDBAuthConfig(ctx, id)
if err != nil {
return nil, err
}
provs, err := db.GetProvisioners(ctx)
if err != nil {
return nil, err
}
admins, err := db.GetAdmins(ctx)
if err != nil {
return nil, err
}
return &mgmt.AuthConfig{
ID: dba.ID,
Admins: admins,
Provisioners: provs,
ASN1DN: dba.ASN1DN,
Backdate: dba.Backdate,
Claims: dba.Claims,
}, nil
}
// CreateAuthConfig stores a new provisioner to the database.
func (db *DB) CreateAuthConfig(ctx context.Context, ac *mgmt.AuthConfig) error {
var err error
if ac.ID == "" {
ac.ID, err = randID()
if err != nil {
return errors.Wrap(err, "error generating random id for provisioner")
}
}
dba := &dbAuthConfig{
ID: ac.ID,
ASN1DN: ac.ASN1DN,
Claims: ac.Claims,
Backdate: ac.Backdate,
CreatedAt: clock.Now(),
}
return db.save(ctx, dba.ID, dba, nil, "authConfig", authorityConfigsTable)
}
// UpdateAuthConfig saves an updated provisioner to the database.
func (db *DB) UpdateAuthConfig(ctx context.Context, ac *mgmt.AuthConfig) error {
old, err := db.getDBAuthConfig(ctx, ac.ID)
if err != nil {
return err
}
nu := old.clone()
// If the authority was active but is now deleted ...
if old.DeletedAt.IsZero() && ac.Status == status.Deleted {
nu.DeletedAt = clock.Now()
}
nu.Claims = ac.Claims
nu.Backdate = ac.Backdate
return db.save(ctx, old.ID, nu, old, "authConfig", authorityProvisionersTable)
}

View file

@ -7,25 +7,25 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/certificates/authority/mgmt" "github.com/smallstep/certificates/authority/mgmt"
"github.com/smallstep/certificates/authority/status" "github.com/smallstep/certificates/linkedca"
"github.com/smallstep/nosql" "github.com/smallstep/nosql"
) )
// dbProvisioner is the database representation of a Provisioner type. // dbProvisioner is the database representation of a Provisioner type.
type dbProvisioner struct { type dbProvisioner struct {
ID string `json:"id"` ID string `json:"id"`
AuthorityID string `json:"authorityID"` AuthorityID string `json:"authorityID"`
Type string `json:"type"` Type linkedca.Provisioner_Type `json:"type"`
// Name is the key // Name is the key
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 []byte `json:"x509Template"`
X509TemplateData []byte `json:"x509TemplateData"` X509TemplateData []byte `json:"x509TemplateData"`
SSHTemplate string `json:"sshTemplate"` SSHTemplate []byte `json:"sshTemplate"`
SSHTemplateData []byte `json:"sshTemplateData"` SSHTemplateData []byte `json:"sshTemplateData"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
DeletedAt time.Time `json:"deletedAt"` DeletedAt time.Time `json:"deletedAt"`
} }
type provisionerNameID struct { type provisionerNameID struct {
@ -68,7 +68,7 @@ func (db *DB) getDBProvisioner(ctx context.Context, id string) (*dbProvisioner,
} }
// GetProvisioner retrieves and unmarshals a provisioner from the database. // GetProvisioner retrieves and unmarshals a provisioner from the database.
func (db *DB) GetProvisioner(ctx context.Context, id string) (*mgmt.Provisioner, error) { func (db *DB) GetProvisioner(ctx context.Context, id string) (*linkedca.Provisioner, error) {
data, err := db.getDBProvisionerBytes(ctx, id) data, err := db.getDBProvisionerBytes(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -78,12 +78,9 @@ func (db *DB) GetProvisioner(ctx context.Context, id string) (*mgmt.Provisioner,
if err != nil { if err != nil {
return nil, err return nil, err
} }
if prov.Status == status.Deleted { if prov.AuthorityId != db.authorityID {
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "provisioner %s is deleted", prov.ID)
}
if prov.AuthorityID != db.authorityID {
return nil, mgmt.NewError(mgmt.ErrorAuthorityMismatchType, return nil, mgmt.NewError(mgmt.ErrorAuthorityMismatchType,
"provisioner %s is not owned by authority %s", prov.ID, db.authorityID) "provisioner %s is not owned by authority %s", prov.Id, db.authorityID)
} }
return prov, nil return prov, nil
} }
@ -93,56 +90,52 @@ func unmarshalDBProvisioner(data []byte, name string) (*dbProvisioner, error) {
if err := json.Unmarshal(data, dbp); err != nil { if err := json.Unmarshal(data, dbp); err != nil {
return nil, errors.Wrapf(err, "error unmarshaling provisioner %s into dbProvisioner", name) return nil, errors.Wrapf(err, "error unmarshaling provisioner %s into dbProvisioner", name)
} }
if !dbp.DeletedAt.IsZero() {
return nil, mgmt.NewError(mgmt.ErrorDeletedType, "provisioner %s is deleted", name)
}
return dbp, nil return dbp, nil
} }
func unmarshalProvisioner(data []byte, name string) (*mgmt.Provisioner, error) { func unmarshalProvisioner(data []byte, name string) (*linkedca.Provisioner, error) {
dbp, err := unmarshalDBProvisioner(data, name) dbp, err := unmarshalDBProvisioner(data, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
details, err := mgmt.UnmarshalProvisionerDetails(dbp.Details) details, err := linkedca.UnmarshalProvisionerDetails(dbp.Type, dbp.Details)
if err != nil { if err != nil {
return nil, err return nil, err
} }
prov := &mgmt.Provisioner{ prov := &linkedca.Provisioner{
ID: dbp.ID, Id: dbp.ID,
AuthorityID: dbp.AuthorityID, AuthorityId: dbp.AuthorityID,
Type: dbp.Type, Type: dbp.Type,
Name: dbp.Name, Name: dbp.Name,
Claims: dbp.Claims, Claims: dbp.Claims,
Details: details, Details: details,
Status: status.Active,
X509Template: dbp.X509Template, X509Template: dbp.X509Template,
X509TemplateData: dbp.X509TemplateData, X509TemplateData: dbp.X509TemplateData,
SSHTemplate: dbp.SSHTemplate, SshTemplate: dbp.SSHTemplate,
SSHTemplateData: dbp.SSHTemplateData, SshTemplateData: dbp.SSHTemplateData,
}
if !dbp.DeletedAt.IsZero() {
prov.Status = status.Deleted
} }
return prov, nil return prov, nil
} }
// GetProvisioners retrieves and unmarshals all active (not deleted) provisioners // GetProvisioners retrieves and unmarshals all active (not deleted) provisioners
// from the database. // from the database.
func (db *DB) GetProvisioners(ctx context.Context) ([]*mgmt.Provisioner, error) { func (db *DB) GetProvisioners(ctx context.Context) ([]*linkedca.Provisioner, error) {
dbEntries, err := db.db.List(authorityProvisionersTable) dbEntries, err := db.db.List(authorityProvisionersTable)
if err != nil { if err != nil {
return nil, mgmt.WrapErrorISE(err, "error loading provisioners") return nil, mgmt.WrapErrorISE(err, "error loading provisioners")
} }
var provs []*mgmt.Provisioner var provs []*linkedca.Provisioner
for _, entry := range dbEntries { for _, entry := range dbEntries {
prov, err := unmarshalProvisioner(entry.Value, string(entry.Key)) prov, err := unmarshalProvisioner(entry.Value, string(entry.Key))
if err != nil { if err != nil {
return nil, err return nil, err
} }
if prov.Status == status.Deleted { if prov.AuthorityId != db.authorityID {
continue
}
if prov.AuthorityID != db.authorityID {
continue continue
} }
provs = append(provs, prov) provs = append(provs, prov)
@ -151,9 +144,9 @@ func (db *DB) GetProvisioners(ctx context.Context) ([]*mgmt.Provisioner, error)
} }
// CreateProvisioner stores a new provisioner to the database. // CreateProvisioner stores a new provisioner to the database.
func (db *DB) CreateProvisioner(ctx context.Context, prov *mgmt.Provisioner) error { func (db *DB) CreateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
var err error var err error
prov.ID, err = randID() prov.Id, err = randID()
if err != nil { if err != nil {
return errors.Wrap(err, "error generating random id for provisioner") return errors.Wrap(err, "error generating random id for provisioner")
} }
@ -164,7 +157,7 @@ func (db *DB) CreateProvisioner(ctx context.Context, prov *mgmt.Provisioner) err
} }
dbp := &dbProvisioner{ dbp := &dbProvisioner{
ID: prov.ID, ID: prov.Id,
AuthorityID: db.authorityID, AuthorityID: db.authorityID,
Type: prov.Type, Type: prov.Type,
Name: prov.Name, Name: prov.Name,
@ -172,12 +165,12 @@ func (db *DB) CreateProvisioner(ctx context.Context, prov *mgmt.Provisioner) err
Details: details, Details: details,
X509Template: prov.X509Template, X509Template: prov.X509Template,
X509TemplateData: prov.X509TemplateData, X509TemplateData: prov.X509TemplateData,
SSHTemplate: prov.SSHTemplate, SSHTemplate: prov.SshTemplate,
SSHTemplateData: prov.SSHTemplateData, SSHTemplateData: prov.SshTemplateData,
CreatedAt: clock.Now(), CreatedAt: clock.Now(),
} }
if err := db.save(ctx, prov.ID, dbp, nil, "provisioner", authorityProvisionersTable); err != nil { if err := db.save(ctx, prov.Id, dbp, nil, "provisioner", authorityProvisionersTable); err != nil {
return mgmt.WrapErrorISE(err, "error creating provisioner %s", prov.Name) return mgmt.WrapErrorISE(err, "error creating provisioner %s", prov.Name)
} }
@ -185,8 +178,8 @@ func (db *DB) CreateProvisioner(ctx context.Context, prov *mgmt.Provisioner) err
} }
// UpdateProvisioner saves an updated provisioner to the database. // UpdateProvisioner saves an updated provisioner to the database.
func (db *DB) UpdateProvisioner(ctx context.Context, prov *mgmt.Provisioner) error { func (db *DB) UpdateProvisioner(ctx context.Context, prov *linkedca.Provisioner) error {
old, err := db.getDBProvisioner(ctx, prov.ID) old, err := db.getDBProvisioner(ctx, prov.Id)
if err != nil { if err != nil {
return err return err
} }
@ -202,9 +195,10 @@ func (db *DB) UpdateProvisioner(ctx context.Context, prov *mgmt.Provisioner) err
} }
nu.X509Template = prov.X509Template nu.X509Template = prov.X509Template
nu.X509TemplateData = prov.X509TemplateData nu.X509TemplateData = prov.X509TemplateData
nu.SSHTemplateData = prov.SSHTemplateData nu.SSHTemplate = prov.SshTemplate
nu.SSHTemplateData = prov.SshTemplateData
if err := db.save(ctx, prov.ID, nu, old, "provisioner", authorityProvisionersTable); err != nil { if err := db.save(ctx, prov.Id, nu, old, "provisioner", authorityProvisionersTable); err != nil {
return mgmt.WrapErrorISE(err, "error updating provisioner %s", prov.Name) return mgmt.WrapErrorISE(err, "error updating provisioner %s", prov.Name)
} }

View file

@ -246,46 +246,3 @@ func claimsToCertificates(c *linkedca.Claims) (*provisioner.Claims, error) {
EnableSSHCA: &c.Ssh.Enabled, EnableSSHCA: &c.Ssh.Enabled,
}, nil }, nil
} }
/*
type detailsType struct {
Type ProvisionerType
}
// UnmarshalProvisionerDetails unmarshals bytes into the proper details type.
func UnmarshalProvisionerDetails(data json.RawMessage) (ProvisionerDetails, error) {
dt := new(detailsType)
if err := json.Unmarshal(data, dt); err != nil {
return nil, WrapErrorISE(err, "error unmarshaling provisioner details")
}
var v ProvisionerDetails
switch dt.Type {
case ProvisionerTypeJWK:
v = new(ProvisionerDetailsJWK)
case ProvisionerTypeOIDC:
v = new(ProvisionerDetailsOIDC)
case ProvisionerTypeGCP:
v = new(ProvisionerDetailsGCP)
case ProvisionerTypeAWS:
v = new(ProvisionerDetailsAWS)
case ProvisionerTypeAZURE:
v = new(ProvisionerDetailsAzure)
case ProvisionerTypeACME:
v = new(ProvisionerDetailsACME)
case ProvisionerTypeX5C:
v = new(ProvisionerDetailsX5C)
case ProvisionerTypeK8SSA:
v = new(ProvisionerDetailsK8SSA)
case ProvisionerTypeSSHPOP:
v = new(ProvisionerDetailsSSHPOP)
default:
return nil, fmt.Errorf("unsupported provisioner type %s", dt.Type)
}
if err := json.Unmarshal(data, v); err != nil {
return nil, err
}
return v, nil
}
*/

38
linkedca/provisioners.go Normal file
View file

@ -0,0 +1,38 @@
package linkedca
import (
"encoding/json"
"fmt"
)
// UnmarshalProvisionerDetails unmarshals details type to the specific provisioner details.
func UnmarshalProvisionerDetails(typ Provisioner_Type, data []byte) (*ProvisionerDetails, error) {
var v isProvisionerDetails_Data
switch typ {
case Provisioner_JWK:
v = new(ProvisionerDetails_JWK)
case Provisioner_OIDC:
v = new(ProvisionerDetails_OIDC)
case Provisioner_GCP:
v = new(ProvisionerDetails_GCP)
case Provisioner_AWS:
v = new(ProvisionerDetails_AWS)
case Provisioner_AZURE:
v = new(ProvisionerDetails_Azure)
case Provisioner_ACME:
v = new(ProvisionerDetails_ACME)
case Provisioner_X5C:
v = new(ProvisionerDetails_X5C)
case Provisioner_K8SSA:
v = new(ProvisionerDetails_K8SSA)
case Provisioner_SSHPOP:
v = new(ProvisionerDetails_SSHPOP)
default:
return nil, fmt.Errorf("unsupported provisioner type %s", typ)
}
if err := json.Unmarshal(data, v); err != nil {
return nil, err
}
return &ProvisionerDetails{Data: v}, nil
}