forked from TrueCloudLab/certificates
parent
7e53b28320
commit
fb6321fb2c
2 changed files with 34 additions and 13 deletions
|
@ -17,10 +17,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// gcpCertsURL is the url that servers Google OAuth2 public keys.
|
// gcpCertsURL is the url that servers Google OAuth2 public keys.
|
||||||
var gcpCertsURL = "https://www.googleapis.com/oauth2/v3/certs"
|
const gcpCertsURL = "https://www.googleapis.com/oauth2/v3/certs"
|
||||||
|
|
||||||
// gcpIdentityURL is the base url for the identity document in GCP.
|
// gcpIdentityURL is the base url for the identity document in GCP.
|
||||||
var gcpIdentityURL = "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity"
|
const gcpIdentityURL = "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity"
|
||||||
|
|
||||||
// gcpPayload extends jwt.Claims with custom GCP attributes.
|
// gcpPayload extends jwt.Claims with custom GCP attributes.
|
||||||
type gcpPayload struct {
|
type gcpPayload struct {
|
||||||
|
@ -45,6 +45,18 @@ type gcpComputeEnginePayload struct {
|
||||||
LicenseID []string `json:"license_id"`
|
LicenseID []string `json:"license_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type gcpConfig struct {
|
||||||
|
CertsURL string
|
||||||
|
IdentityURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGCPConfig() *gcpConfig {
|
||||||
|
return &gcpConfig{
|
||||||
|
CertsURL: gcpCertsURL,
|
||||||
|
IdentityURL: gcpIdentityURL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GCP is the provisioner that supports identity tokens created by the Google
|
// GCP is the provisioner that supports identity tokens created by the Google
|
||||||
// Cloud Platform metadata API.
|
// Cloud Platform metadata API.
|
||||||
type GCP struct {
|
type GCP struct {
|
||||||
|
@ -53,6 +65,7 @@ type GCP struct {
|
||||||
ServiceAccounts []string `json:"serviceAccounts"`
|
ServiceAccounts []string `json:"serviceAccounts"`
|
||||||
Claims *Claims `json:"claims,omitempty"`
|
Claims *Claims `json:"claims,omitempty"`
|
||||||
claimer *Claimer
|
claimer *Claimer
|
||||||
|
config *gcpConfig
|
||||||
keyStore *keyStore
|
keyStore *keyStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,11 +114,14 @@ func (p *GCP) GetEncryptedKey() (kid string, key string, ok bool) {
|
||||||
|
|
||||||
// GetIdentityURL returns the url that generates the GCP token.
|
// GetIdentityURL returns the url that generates the GCP token.
|
||||||
func (p *GCP) GetIdentityURL() string {
|
func (p *GCP) GetIdentityURL() string {
|
||||||
|
// Initialize config if required
|
||||||
|
p.assertConfig()
|
||||||
|
|
||||||
q := url.Values{}
|
q := url.Values{}
|
||||||
q.Add("audience", p.GetID())
|
q.Add("audience", p.GetID())
|
||||||
q.Add("format", "full")
|
q.Add("format", "full")
|
||||||
q.Add("licenses", "FALSE")
|
q.Add("licenses", "FALSE")
|
||||||
return fmt.Sprintf("%s?%s", gcpIdentityURL, q.Encode())
|
return fmt.Sprintf("%s?%s", p.config.IdentityURL, q.Encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIdentityToken does an HTTP request to the identity url.
|
// GetIdentityToken does an HTTP request to the identity url.
|
||||||
|
@ -139,12 +155,14 @@ func (p *GCP) Init(config Config) error {
|
||||||
case p.Name == "":
|
case p.Name == "":
|
||||||
return errors.New("provisioner name cannot be empty")
|
return errors.New("provisioner name cannot be empty")
|
||||||
}
|
}
|
||||||
|
// Initialize config
|
||||||
|
p.assertConfig()
|
||||||
// Update claims with global ones
|
// Update claims with global ones
|
||||||
if p.claimer, err = NewClaimer(p.Claims, config.Claims); err != nil {
|
if p.claimer, err = NewClaimer(p.Claims, config.Claims); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Initialize key store
|
// Initialize key store
|
||||||
p.keyStore, err = newKeyStore(gcpCertsURL)
|
p.keyStore, err = newKeyStore(p.config.CertsURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -188,6 +206,13 @@ func (p *GCP) AuthorizeRevoke(token string) error {
|
||||||
return errors.New("revoke is not supported on a GCP provisioner")
|
return errors.New("revoke is not supported on a GCP provisioner")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assertConfig initializes the config if it has not been initialized.
|
||||||
|
func (p *GCP) assertConfig() {
|
||||||
|
if p.config == nil {
|
||||||
|
p.config = newGCPConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// authorizeToken performs common jwt authorization actions and returns the
|
// authorizeToken performs common jwt authorization actions and returns the
|
||||||
// claims for case specific downstream parsing.
|
// claims for case specific downstream parsing.
|
||||||
// e.g. a Sign request will auth/validate different fields than a Revoke request.
|
// e.g. a Sign request will auth/validate different fields than a Revoke request.
|
||||||
|
|
|
@ -15,11 +15,6 @@ import (
|
||||||
"github.com/smallstep/assert"
|
"github.com/smallstep/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resetGoogleVars() {
|
|
||||||
gcpCertsURL = "https://www.googleapis.com/oauth2/v3/certs"
|
|
||||||
gcpIdentityURL = "http://metadata/computeMetadata/v1/instance/service-accounts/default/identity"
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGCP_Getters(t *testing.T) {
|
func TestGCP_Getters(t *testing.T) {
|
||||||
p, err := generateGCP()
|
p, err := generateGCP()
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
|
@ -91,7 +86,6 @@ func TestGCP_GetTokenID(t *testing.T) {
|
||||||
func TestGCP_GetIdentityToken(t *testing.T) {
|
func TestGCP_GetIdentityToken(t *testing.T) {
|
||||||
p1, err := generateGCP()
|
p1, err := generateGCP()
|
||||||
assert.FatalError(t, err)
|
assert.FatalError(t, err)
|
||||||
defer resetGoogleVars()
|
|
||||||
|
|
||||||
t1, err := generateGCPToken(p1.ServiceAccounts[0],
|
t1, err := generateGCPToken(p1.ServiceAccounts[0],
|
||||||
"https://accounts.google.com", p1.GetID(),
|
"https://accounts.google.com", p1.GetID(),
|
||||||
|
@ -123,7 +117,7 @@ func TestGCP_GetIdentityToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
gcpIdentityURL = tt.identityURL
|
tt.gcp.config.IdentityURL = tt.identityURL
|
||||||
got, err := tt.gcp.GetIdentityToken()
|
got, err := tt.gcp.GetIdentityToken()
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
|
@ -140,7 +134,6 @@ func TestGCP_GetIdentityToken(t *testing.T) {
|
||||||
func TestGCP_Init(t *testing.T) {
|
func TestGCP_Init(t *testing.T) {
|
||||||
srv := generateJWKServer(2)
|
srv := generateJWKServer(2)
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
defer resetGoogleVars()
|
|
||||||
|
|
||||||
config := Config{
|
config := Config{
|
||||||
Claims: globalProvisionerClaims,
|
Claims: globalProvisionerClaims,
|
||||||
|
@ -174,12 +167,15 @@ func TestGCP_Init(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
gcpCertsURL = tt.args.certsURL
|
|
||||||
p := &GCP{
|
p := &GCP{
|
||||||
Type: tt.fields.Type,
|
Type: tt.fields.Type,
|
||||||
Name: tt.fields.Name,
|
Name: tt.fields.Name,
|
||||||
ServiceAccounts: tt.fields.ServiceAccounts,
|
ServiceAccounts: tt.fields.ServiceAccounts,
|
||||||
Claims: tt.fields.Claims,
|
Claims: tt.fields.Claims,
|
||||||
|
config: &gcpConfig{
|
||||||
|
CertsURL: tt.args.certsURL,
|
||||||
|
IdentityURL: gcpIdentityURL,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
if err := p.Init(tt.args.config); (err != nil) != tt.wantErr {
|
if err := p.Init(tt.args.config); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("GCP.Init() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("GCP.Init() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
|
Loading…
Reference in a new issue