forked from TrueCloudLab/certificates
wip
This commit is contained in:
parent
4f3e5ef64d
commit
638766c615
12 changed files with 123 additions and 6 deletions
|
@ -13,6 +13,7 @@ import (
|
|||
// provisioning flow.
|
||||
type ACME struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
ForceCN bool `json:"forceCN,omitempty"`
|
||||
|
@ -23,6 +24,15 @@ type ACME struct {
|
|||
|
||||
// GetID returns the provisioner unique identifier.
|
||||
func (p ACME) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *ACME) GetIDForToken() string {
|
||||
return "acme/" + p.Name
|
||||
}
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ type awsInstanceIdentityDocument struct {
|
|||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
|
||||
type AWS struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Accounts []string `json:"accounts"`
|
||||
|
@ -269,6 +270,15 @@ type AWS struct {
|
|||
|
||||
// GetID returns the provisioner unique identifier.
|
||||
func (p *AWS) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *AWS) GetIDForToken() string {
|
||||
return "aws/" + p.Name
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ type azurePayload struct {
|
|||
// and https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service
|
||||
type Azure struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
TenantID string `json:"tenantID"`
|
||||
|
@ -101,6 +102,15 @@ type Azure struct {
|
|||
|
||||
// GetID returns the provisioner unique identifier.
|
||||
func (p *Azure) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *Azure) GetIDForToken() string {
|
||||
return p.TenantID
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ type Collection struct {
|
|||
byID *sync.Map
|
||||
byKey *sync.Map
|
||||
byName *sync.Map
|
||||
byTokenID *sync.Map
|
||||
sorted provisionerSlice
|
||||
audiences Audiences
|
||||
}
|
||||
|
@ -57,6 +58,7 @@ func NewCollection(audiences Audiences) *Collection {
|
|||
byID: new(sync.Map),
|
||||
byKey: new(sync.Map),
|
||||
byName: new(sync.Map),
|
||||
byTokenID: new(sync.Map),
|
||||
audiences: audiences,
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +73,13 @@ func (c *Collection) LoadByName(name string) (Interface, bool) {
|
|||
return loadProvisioner(c.byName, name)
|
||||
}
|
||||
|
||||
// LoadByTokenID a provisioner by identifier found in token.
|
||||
// For different provisioner types this identifier may be found in in different
|
||||
// attributes of the token.
|
||||
func (c *Collection) LoadByTokenID(tokenProvisionerID string) (Interface, bool) {
|
||||
return loadProvisioner(c.byTokenID, tokenProvisionerID)
|
||||
}
|
||||
|
||||
// LoadByToken parses the token claims and loads the provisioner associated.
|
||||
func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims) (Interface, bool) {
|
||||
var audiences []string
|
||||
|
@ -86,11 +95,12 @@ func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims)
|
|||
if matchesAudience(claims.Audience, audiences) {
|
||||
// Use fragment to get provisioner name (GCP, AWS, SSHPOP)
|
||||
if fragment != "" {
|
||||
return c.Load(fragment)
|
||||
return c.LoadByTokenID(fragment)
|
||||
}
|
||||
// If matches with stored audiences it will be a JWT token (default), and
|
||||
// the id would be <issuer>:<kid>.
|
||||
return c.Load(claims.Issuer + ":" + token.Headers[0].KeyID)
|
||||
// TODO: is this ok?
|
||||
return c.LoadByTokenID(claims.Issuer + ":" + token.Headers[0].KeyID)
|
||||
}
|
||||
|
||||
// The ID will be just the clientID stored in azp, aud or tid.
|
||||
|
@ -101,7 +111,7 @@ func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims)
|
|||
|
||||
// Kubernetes Service Account tokens.
|
||||
if payload.Issuer == k8sSAIssuer {
|
||||
if p, ok := c.Load(K8sSAID); ok {
|
||||
if p, ok := c.LoadByTokenID(K8sSAID); ok {
|
||||
return p, ok
|
||||
}
|
||||
// Kubernetes service account provisioner not found
|
||||
|
@ -115,18 +125,18 @@ func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims)
|
|||
|
||||
// Try with azp (OIDC)
|
||||
if len(payload.AuthorizedParty) > 0 {
|
||||
if p, ok := c.Load(payload.AuthorizedParty); ok {
|
||||
if p, ok := c.LoadByTokenID(payload.AuthorizedParty); ok {
|
||||
return p, ok
|
||||
}
|
||||
}
|
||||
// Try with tid (Azure)
|
||||
if payload.TenantID != "" {
|
||||
if p, ok := c.Load(payload.TenantID); ok {
|
||||
if p, ok := c.LoadByTokenID(payload.TenantID); ok {
|
||||
return p, ok
|
||||
}
|
||||
}
|
||||
// Fallback to aud
|
||||
return c.Load(payload.Audience[0])
|
||||
return c.LoadByTokenID(payload.Audience[0])
|
||||
}
|
||||
|
||||
// LoadByCertificate looks for the provisioner extension and extracts the
|
||||
|
@ -185,6 +195,12 @@ func (c *Collection) Store(p Interface) error {
|
|||
c.byID.Delete(p.GetID())
|
||||
return errors.New("cannot add multiple provisioners with the same name")
|
||||
}
|
||||
// Store provisioner always by ID presented in token.
|
||||
if _, loaded := c.byTokenID.LoadOrStore(p.GetIDForToken(), p); loaded {
|
||||
c.byID.Delete(p.GetID())
|
||||
c.byName.Delete(p.GetName())
|
||||
return errors.New("cannot add multiple provisioners with the same token identifier")
|
||||
}
|
||||
|
||||
// Store provisioner in byKey if EncryptedKey is defined.
|
||||
if kid, _, ok := p.GetEncryptedKey(); ok {
|
||||
|
|
|
@ -78,6 +78,7 @@ func newGCPConfig() *gcpConfig {
|
|||
// https://cloud.google.com/compute/docs/instances/verifying-instance-identity
|
||||
type GCP struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
ServiceAccounts []string `json:"serviceAccounts"`
|
||||
|
@ -96,6 +97,16 @@ type GCP struct {
|
|||
// GetID returns the provisioner unique identifier. The name should uniquely
|
||||
// identify any GCP provisioner.
|
||||
func (p *GCP) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *GCP) GetIDForToken() string {
|
||||
return "gcp/" + p.Name
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ func (p *JWK) GetID() string {
|
|||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *JWK) GetIDForToken() string {
|
||||
return p.Name + ":" + p.Key.KeyID
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ type k8sSAPayload struct {
|
|||
// entity trusted to make signature requests.
|
||||
type K8sSA struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
PubKeys []byte `json:"publicKeys,omitempty"`
|
||||
|
@ -56,6 +57,15 @@ type K8sSA struct {
|
|||
// GetID returns the provisioner unique identifier. The name and credential id
|
||||
// should uniquely identify any K8sSA provisioner.
|
||||
func (p *K8sSA) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *K8sSA) GetIDForToken() string {
|
||||
return K8sSAID
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ func (p *noop) GetID() string {
|
|||
return "noop"
|
||||
}
|
||||
|
||||
func (p *noop) GetIDForToken() string {
|
||||
return "noop"
|
||||
}
|
||||
|
||||
func (p *noop) GetTokenID(token string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ type openIDPayload struct {
|
|||
// ClientSecret is mandatory, but it can be an empty string.
|
||||
type OIDC struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
ClientID string `json:"clientID"`
|
||||
|
@ -111,6 +112,15 @@ func sanitizeEmail(email string) string {
|
|||
// GetID returns the provisioner unique identifier, the OIDC provisioner the
|
||||
// uses the clientID for this.
|
||||
func (o *OIDC) GetID() string {
|
||||
if o.ID != "" {
|
||||
return o.ID
|
||||
}
|
||||
return o.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (o *OIDC) GetIDForToken() string {
|
||||
return o.ClientID
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
// Interface is the interface that all provisioner types must implement.
|
||||
type Interface interface {
|
||||
GetID() string
|
||||
GetIDForToken() string
|
||||
GetTokenID(token string) (string, error)
|
||||
GetName() string
|
||||
GetType() Type
|
||||
|
@ -388,6 +389,7 @@ type MockProvisioner struct {
|
|||
Mret1, Mret2, Mret3 interface{}
|
||||
Merr error
|
||||
MgetID func() string
|
||||
MgetIDForToken func() string
|
||||
MgetTokenID func(string) (string, error)
|
||||
MgetName func() string
|
||||
MgetType func() Type
|
||||
|
@ -410,6 +412,14 @@ func (m *MockProvisioner) GetID() string {
|
|||
return m.Mret1.(string)
|
||||
}
|
||||
|
||||
// GetIDForToken mock
|
||||
func (m *MockProvisioner) GetIDForToken() string {
|
||||
if m.MgetIDForToken != nil {
|
||||
return m.MgetIDForToken()
|
||||
}
|
||||
return m.Mret1.(string)
|
||||
}
|
||||
|
||||
// GetTokenID mock
|
||||
func (m *MockProvisioner) GetTokenID(token string) (string, error) {
|
||||
if m.MgetTokenID != nil {
|
||||
|
|
|
@ -26,6 +26,7 @@ type sshPOPPayload struct {
|
|||
// signature requests.
|
||||
type SSHPOP struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Claims *Claims `json:"claims,omitempty"`
|
||||
|
@ -38,6 +39,15 @@ type SSHPOP struct {
|
|||
// GetID returns the provisioner unique identifier. The name and credential id
|
||||
// should uniquely identify any SSH-POP provisioner.
|
||||
func (p *SSHPOP) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *SSHPOP) GetIDForToken() string {
|
||||
return "sshpop/" + p.Name
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ type x5cPayload struct {
|
|||
// signature requests.
|
||||
type X5C struct {
|
||||
*base
|
||||
ID string `json:"-"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Roots []byte `json:"roots"`
|
||||
|
@ -39,6 +40,15 @@ type X5C struct {
|
|||
// GetID returns the provisioner unique identifier. The name and credential id
|
||||
// should uniquely identify any X5C provisioner.
|
||||
func (p *X5C) GetID() string {
|
||||
if p.ID != "" {
|
||||
return p.ID
|
||||
}
|
||||
return p.GetIDForToken()
|
||||
}
|
||||
|
||||
// GetIDForToken returns an identifier that will be used to load the provisioner
|
||||
// from a token.
|
||||
func (p *X5C) GetIDForToken() string {
|
||||
return "x5c/" + p.Name
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue