Add ca-url based audience for AWS tokens

Fixes smallstep/step#156
This commit is contained in:
Mariano Cano 2019-06-06 12:49:51 -07:00
parent 4fa9e9333d
commit 2491593cdd

View file

@ -131,11 +131,12 @@ type AWS struct {
Claims *Claims `json:"claims,omitempty"` Claims *Claims `json:"claims,omitempty"`
claimer *Claimer claimer *Claimer
config *awsConfig config *awsConfig
audiences Audiences
} }
// GetID returns the provisioner unique identifier. // GetID returns the provisioner unique identifier.
func (p *AWS) GetID() string { func (p *AWS) GetID() string {
return "aws:" + p.Name return "aws/" + p.Name
} }
// GetTokenID returns the identifier of the token. // GetTokenID returns the identifier of the token.
@ -170,7 +171,7 @@ func (p *AWS) GetEncryptedKey() (kid string, key string, ok bool) {
// GetIdentityToken retrieves the identity document and it's signature and // GetIdentityToken retrieves the identity document and it's signature and
// generates a token with them. // generates a token with them.
func (p *AWS) GetIdentityToken() (string, error) { func (p *AWS) GetIdentityToken(caURL string) (string, error) {
// Initialize the config if this method is used from the cli. // Initialize the config if this method is used from the cli.
if err := p.assertConfig(); err != nil { if err := p.assertConfig(); err != nil {
return "", err return "", err
@ -196,6 +197,11 @@ func (p *AWS) GetIdentityToken() (string, error) {
return "", err return "", err
} }
audience, err := generateSignAudience(caURL, p.GetID())
if err != nil {
return "", err
}
// Create unique ID for Trust On First Use (TOFU). Only the first instance // Create unique ID for Trust On First Use (TOFU). Only the first instance
// per provisioner is allowed as we don't have a way to trust the given // per provisioner is allowed as we don't have a way to trust the given
// sans. // sans.
@ -216,7 +222,7 @@ func (p *AWS) GetIdentityToken() (string, error) {
Claims: jose.Claims{ Claims: jose.Claims{
Issuer: awsIssuer, Issuer: awsIssuer,
Subject: idoc.InstanceID, Subject: idoc.InstanceID,
Audience: []string{p.GetID()}, Audience: []string{audience},
Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)), Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)),
NotBefore: jose.NewNumericDate(now), NotBefore: jose.NewNumericDate(now),
IssuedAt: jose.NewNumericDate(now), IssuedAt: jose.NewNumericDate(now),
@ -254,6 +260,7 @@ func (p *AWS) Init(config Config) (err error) {
if p.config, err = newAWSConfig(); err != nil { if p.config, err = newAWSConfig(); err != nil {
return err return err
} }
p.audiences = config.Audiences.WithFragment(p.GetID())
return nil return nil
} }
@ -381,14 +388,18 @@ func (p *AWS) authorizeToken(token string) (*awsPayload, error) {
// more than a few minutes. // more than a few minutes.
now := time.Now().UTC() now := time.Now().UTC()
if err = payload.ValidateWithLeeway(jose.Expected{ if err = payload.ValidateWithLeeway(jose.Expected{
Issuer: awsIssuer, Issuer: awsIssuer,
Subject: doc.InstanceID, Subject: doc.InstanceID,
Audience: []string{p.GetID()}, Time: now,
Time: now,
}, time.Minute); err != nil { }, time.Minute); err != nil {
return nil, errors.Wrapf(err, "invalid token") return nil, errors.Wrapf(err, "invalid token")
} }
// validate audiences with the defaults
if !matchesAudience(payload.Audience, p.audiences.Sign) {
return nil, errors.New("invalid token: invalid audience claim (aud)")
}
// validate accounts // validate accounts
if len(p.Accounts) > 0 { if len(p.Accounts) > 0 {
var found bool var found bool