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