Validate payload ID.

Related to #435
This commit is contained in:
Mariano Cano 2020-12-17 13:35:14 -08:00
parent d6ea8b13ab
commit 0cf594a003
4 changed files with 58 additions and 30 deletions

View file

@ -631,6 +631,13 @@ func (p *AWS) authorizeToken(token string) (*awsPayload, error) {
return nil, errs.Unauthorized("aws.authorizeToken; aws identity document region cannot be empty")
}
// Recalculate and validate payload.ID
unique := fmt.Sprintf("%s.%s", p.GetID(), doc.InstanceID)
sum := sha256.Sum256([]byte(unique))
if payload.ID != strings.ToLower(hex.EncodeToString(sum[:])) {
return nil, errs.Unauthorized("aws.authorizeToken; invalid token id")
}
// According to "rfc7519 JSON Web Token" acceptable skew should be no
// more than a few minutes.
now := time.Now().UTC()

View file

@ -332,7 +332,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), badKey)
assert.FatalError(t, err)
return test{
@ -346,7 +346,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), "", "instance-id",
p, "instance-id", awsIssuer, p.GetID(), "", "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -360,7 +360,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -374,7 +374,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -388,7 +388,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -402,7 +402,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", "bad-issuer", p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", "bad-issuer", p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -416,7 +416,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, "bad-audience", p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, "bad-audience", p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -431,7 +431,7 @@ func TestAWS_authorizeToken(t *testing.T) {
assert.FatalError(t, err)
p.DisableCustomSANs = true
tok, err := generateAWSToken(
"foo", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "foo", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -445,7 +445,7 @@ func TestAWS_authorizeToken(t *testing.T) {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), "foo", "instance-id",
p, "instance-id", awsIssuer, p.GetID(), "foo", "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -460,7 +460,7 @@ func TestAWS_authorizeToken(t *testing.T) {
assert.FatalError(t, err)
p.InstanceAge = Duration{1 * time.Minute}
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now().Add(-1*time.Minute), key)
assert.FatalError(t, err)
return test{
@ -470,24 +470,27 @@ func TestAWS_authorizeToken(t *testing.T) {
err: errors.New("aws.authorizeToken; aws identity document pendingTime is too old"),
}
},
"fail/identityCert": func(t *testing.T) test {
"fail/payloadId": func(t *testing.T) test {
p, err := generateAWS()
p.IIDRoots = "testdata/certs/aws.crt"
assert.FatalError(t, err)
p2, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p2, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
p: p,
token: tok,
code: http.StatusUnauthorized,
err: errors.New("aws.authorizeToken; invalid token id"),
}
},
"ok": func(t *testing.T) test {
p, err := generateAWS()
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -500,7 +503,20 @@ func TestAWS_authorizeToken(t *testing.T) {
p.IIDRoots = "testdata/certs/aws-test.crt"
assert.FatalError(t, err)
tok, err := generateAWSToken(
"instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
p: p,
token: tok,
}
},
"ok/identityCert2": func(t *testing.T) test {
p, err := generateAWS()
p.IIDRoots = "testdata/certs/aws.crt"
assert.FatalError(t, err)
tok, err := generateAWSToken(
p, "instance-id", awsIssuer, p.GetID(), p.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
return test{
@ -575,51 +591,51 @@ func TestAWS_AuthorizeSign(t *testing.T) {
assert.FatalError(t, err)
t4, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failSubject, err := generateAWSToken(
"bad-subject", awsIssuer, p2.GetID(), p2.Accounts[0], "instance-id",
p2, "bad-subject", awsIssuer, p2.GetID(), p2.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failIssuer, err := generateAWSToken(
"instance-id", "bad-issuer", p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", "bad-issuer", p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failAudience, err := generateAWSToken(
"instance-id", awsIssuer, "bad-audience", p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, "bad-audience", p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failAccount, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), "", "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), "", "instance-id",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failInstanceID, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "",
"127.0.0.1", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failPrivateIP, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"", "us-west-1", time.Now(), key)
assert.FatalError(t, err)
failRegion, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "", time.Now(), key)
assert.FatalError(t, err)
failExp, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now().Add(-360*time.Second), key)
assert.FatalError(t, err)
failNbf, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now().Add(360*time.Second), key)
assert.FatalError(t, err)
failKey, err := generateAWSToken(
"instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
p1, "instance-id", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now(), badKey)
assert.FatalError(t, err)
failInstanceAge, err := generateAWSToken(
"instance-id", awsIssuer, p2.GetID(), p2.Accounts[0], "instance-id",
p2, "instance-id", awsIssuer, p2.GetID(), p2.Accounts[0], "instance-id",
"127.0.0.1", "us-west-1", time.Now().Add(-1*time.Minute), key)
assert.FatalError(t, err)

View file

@ -127,7 +127,7 @@ func TestTemplateOptions(t *testing.T) {
}`)}, false},
{"okCustomTemplate", args{&Options{X509: &X509Options{Template: x509util.DefaultIIDLeafTemplate}}, data}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foo"},
"subject": {"commonName": "foo"},
"sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"]
@ -189,7 +189,7 @@ func TestCustomTemplateOptions(t *testing.T) {
}`)}, false},
{"okIID", args{nil, data, x509util.DefaultIIDLeafTemplate, SignOptions{}}, x509util.Options{
CertBuffer: bytes.NewBufferString(`{
"subject": {"commonName":"foo"},
"subject": {"commonName": "foo"},
"sans": [{"type":"dns","value":"foo.com"}],
"keyUsage": ["digitalSignature"],
"extKeyUsage": ["serverAuth", "clientAuth"]

View file

@ -13,6 +13,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"time"
"github.com/pkg/errors"
@ -910,7 +911,7 @@ func generateGCPToken(sub, iss, aud, instanceID, instanceName, projectID, zone s
return jose.Signed(sig).Claims(claims).CompactSerialize()
}
func generateAWSToken(sub, iss, aud, accountID, instanceID, privateIP, region string, iat time.Time, key crypto.Signer) (string, error) {
func generateAWSToken(p *AWS, sub, iss, aud, accountID, instanceID, privateIP, region string, iat time.Time, key crypto.Signer) (string, error) {
doc, err := json.MarshalIndent(awsInstanceIdentityDocument{
AccountID: accountID,
Architecture: "x86_64",
@ -946,8 +947,12 @@ func generateAWSToken(sub, iss, aud, accountID, instanceID, privateIP, region st
return "", err
}
unique := fmt.Sprintf("%s.%s", p.GetID(), instanceID)
sum = sha256.Sum256([]byte(unique))
claims := awsPayload{
Claims: jose.Claims{
ID: strings.ToLower(hex.EncodeToString(sum[:])),
Subject: sub,
Issuer: iss,
IssuedAt: jose.NewNumericDate(iat),