From 900ab9cc123b491da7a8c7df9d30272d6cb9e7ba Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 15 Jul 2019 15:52:36 -0700 Subject: [PATCH 1/2] Allow custom common names in cloud identity provisioners. --- authority/provisioner/aws.go | 27 ++++++---- authority/provisioner/aws_test.go | 60 ++++++++++++++++------ authority/provisioner/azure.go | 8 +-- authority/provisioner/azure_test.go | 35 +++++++------ authority/provisioner/gcp.go | 17 +++--- authority/provisioner/gcp_test.go | 19 +++---- authority/provisioner/sign_options.go | 56 ++++++++++++++------ authority/provisioner/sign_options_test.go | 24 +++++++++ authority/provisioner/timeduration.go | 10 +++- authority/provisioner/utils_test.go | 14 ++--- 10 files changed, 182 insertions(+), 88 deletions(-) diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index be142ca3..8b288e3d 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -171,7 +171,7 @@ func (p *AWS) GetEncryptedKey() (kid string, key string, ok bool) { // GetIdentityToken retrieves the identity document and it's signature and // generates a token with them. -func (p *AWS) GetIdentityToken(caURL string) (string, error) { +func (p *AWS) GetIdentityToken(subject, caURL string) (string, error) { // Initialize the config if this method is used from the cli. if err := p.assertConfig(); err != nil { return "", err @@ -221,7 +221,7 @@ func (p *AWS) GetIdentityToken(caURL string) (string, error) { payload := awsPayload{ Claims: jose.Claims{ Issuer: awsIssuer, - Subject: idoc.InstanceID, + Subject: subject, Audience: []string{audience}, Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)), NotBefore: jose.NewNumericDate(now), @@ -273,8 +273,8 @@ func (p *AWS) AuthorizeSign(token string) ([]SignOption, error) { } doc := payload.document - // Enforce default DNS and IP if configured. - // By default we'll accept the SANs in the CSR. + // Enforce known CN and default DNS and IP if configured. + // By default we'll accept the CN and SANs in the CSR. // There's no way to trust them other than TOFU. var so []SignOption if p.DisableCustomSANs { @@ -287,9 +287,9 @@ func (p *AWS) AuthorizeSign(token string) ([]SignOption, error) { } return append(so, - commonNameValidator(doc.InstanceID), + commonNameValidator(payload.Claims.Subject), profileDefaultDuration(p.claimer.DefaultTLSCertDuration()), - newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID), + newProvisionerExtensionOption(TypeAWS, p.Name, doc.AccountID, "InstanceID", doc.InstanceID), newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()), ), nil } @@ -388,19 +388,26 @@ func (p *AWS) authorizeToken(token string) (*awsPayload, error) { // more than a few minutes. now := time.Now().UTC() if err = payload.ValidateWithLeeway(jose.Expected{ - Issuer: awsIssuer, - Subject: doc.InstanceID, - Time: now, + Issuer: awsIssuer, + Time: now, }, time.Minute); err != nil { return nil, errors.Wrapf(err, "invalid token") } // validate audiences with the defaults if !matchesAudience(payload.Audience, p.audiences.Sign) { - fmt.Println(payload.Audience, "vs", p.audiences.Sign) return nil, errors.New("invalid token: invalid audience claim (aud)") } + // Validate subject, it has to be known if disableCustomSANs is enabled + if p.DisableCustomSANs { + if payload.Subject != doc.InstanceID && + payload.Subject != doc.PrivateIP && + payload.Subject != fmt.Sprintf("ip-%s.%s.compute.internal", strings.Replace(doc.PrivateIP, ".", "-", -1), doc.Region) { + return nil, errors.New("invalid token: invalid subject claim (sub)") + } + } + // validate accounts if len(p.Accounts) > 0 { var found bool diff --git a/authority/provisioner/aws_test.go b/authority/provisioner/aws_test.go index 231b9713..ce1320ab 100644 --- a/authority/provisioner/aws_test.go +++ b/authority/provisioner/aws_test.go @@ -48,14 +48,14 @@ func TestAWS_GetTokenID(t *testing.T) { p2.config = p1.config p2.DisableTrustOnFirstUse = true - t1, err := p1.GetIdentityToken("https://ca.smallstep.com") + t1, err := p1.GetIdentityToken("foo.local", "https://ca.smallstep.com") assert.FatalError(t, err) _, claims, err := parseAWSToken(t1) assert.FatalError(t, err) sum := sha256.Sum256([]byte(fmt.Sprintf("%s.%s", p1.GetID(), claims.document.InstanceID))) w1 := strings.ToLower(hex.EncodeToString(sum[:])) - t2, err := p2.GetIdentityToken("https://ca.smallstep.com") + t2, err := p2.GetIdentityToken("foo.local", "https://ca.smallstep.com") assert.FatalError(t, err) sum = sha256.Sum256([]byte(t2)) w2 := strings.ToLower(hex.EncodeToString(sum[:])) @@ -111,12 +111,31 @@ func TestAWS_GetIdentityToken(t *testing.T) { p4.config.signatureURL = srv.URL + "/bad-signature" p4.config.identityURL = p1.config.identityURL + p5, err := generateAWS() + assert.FatalError(t, err) + p5.Accounts = p1.Accounts + p5.config.identityURL = "https://1234.1234.1234.1234" + p5.config.signatureURL = p1.config.signatureURL + + p6, err := generateAWS() + assert.FatalError(t, err) + p6.Accounts = p1.Accounts + p6.config.identityURL = p1.config.identityURL + p6.config.signatureURL = "https://1234.1234.1234.1234" + + p7, err := generateAWS() + assert.FatalError(t, err) + p7.Accounts = p1.Accounts + p7.config.identityURL = srv.URL + "/bad-json" + p7.config.signatureURL = p1.config.signatureURL + caURL := "https://ca.smallstep.com" u, err := url.Parse(caURL) assert.FatalError(t, err) type args struct { - caURL string + subject string + caURL string } tests := []struct { name string @@ -124,15 +143,18 @@ func TestAWS_GetIdentityToken(t *testing.T) { args args wantErr bool }{ - {"ok", p1, args{caURL}, false}, - {"fail ca url", p1, args{"://ca.smallstep.com"}, true}, - {"fail identityURL", p2, args{caURL}, true}, - {"fail signatureURL", p3, args{caURL}, true}, - {"fail signature", p4, args{caURL}, true}, + {"ok", p1, args{"foo.local", caURL}, false}, + {"fail ca url", p1, args{"foo.local", "://ca.smallstep.com"}, true}, + {"fail identityURL", p2, args{"foo.local", caURL}, true}, + {"fail signatureURL", p3, args{"foo.local", caURL}, true}, + {"fail signature", p4, args{"foo.local", caURL}, true}, + {"fail read identityURL", p5, args{"foo.local", caURL}, true}, + {"fail read signatureURL", p6, args{"foo.local", caURL}, true}, + {"fail unmarshal identityURL", p7, args{"foo.local", caURL}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.aws.GetIdentityToken(tt.args.caURL) + got, err := tt.aws.GetIdentityToken(tt.args.subject, tt.args.caURL) if (err != nil) != tt.wantErr { t.Errorf("AWS.GetIdentityToken() error = %v, wantErr %v", err, tt.wantErr) return @@ -141,7 +163,7 @@ func TestAWS_GetIdentityToken(t *testing.T) { _, c, err := parseAWSToken(got) if assert.NoError(t, err) { assert.Equals(t, awsIssuer, c.Issuer) - assert.Equals(t, c.document.InstanceID, c.Subject) + assert.Equals(t, tt.args.subject, c.Subject) assert.Equals(t, jose.Audience{u.ResolveReference(&url.URL{Path: "/1.0/sign", Fragment: tt.aws.GetID()}).String()}, c.Audience) assert.Equals(t, tt.aws.Accounts[0], c.document.AccountID) err = tt.aws.config.certificate.CheckSignature( @@ -221,12 +243,18 @@ func TestAWS_AuthorizeSign(t *testing.T) { assert.FatalError(t, err) p3.config = p1.config - t1, err := p1.GetIdentityToken("https://ca.smallstep.com") + t1, err := p1.GetIdentityToken("foo.local", "https://ca.smallstep.com") assert.FatalError(t, err) - t2, err := p2.GetIdentityToken("https://ca.smallstep.com") + t2, err := p2.GetIdentityToken("instance-id", "https://ca.smallstep.com") assert.FatalError(t, err) - t3, err := p3.GetIdentityToken("https://ca.smallstep.com") assert.FatalError(t, err) + t3, err := p3.GetIdentityToken("foo.local", "https://ca.smallstep.com") + assert.FatalError(t, err) + + // Alternative common names with DisableCustomSANs = true + t2PrivateIP, err := p2.GetIdentityToken("127.0.0.1", "https://ca.smallstep.com") + assert.FatalError(t, err) + t2Hostname, err := p2.GetIdentityToken("ip-127-0-0-1.us-west-1.compute.internal", "https://ca.smallstep.com") block, _ := pem.Decode([]byte(awsTestKey)) if block == nil || block.Type != "RSA PRIVATE KEY" { @@ -243,7 +271,7 @@ func TestAWS_AuthorizeSign(t *testing.T) { "127.0.0.1", "us-west-1", time.Now(), key) assert.FatalError(t, err) failSubject, err := generateAWSToken( - "bad-subject", awsIssuer, p1.GetID(), p1.Accounts[0], "instance-id", + "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( @@ -299,6 +327,8 @@ func TestAWS_AuthorizeSign(t *testing.T) { }{ {"ok", p1, args{t1}, 4, false}, {"ok", p2, args{t2}, 6, false}, + {"ok", p2, args{t2Hostname}, 6, false}, + {"ok", p2, args{t2PrivateIP}, 6, false}, {"ok", p1, args{t4}, 4, false}, {"fail account", p3, args{t3}, 0, true}, {"fail token", p1, args{"token"}, 0, true}, @@ -364,7 +394,7 @@ func TestAWS_AuthorizeRevoke(t *testing.T) { assert.FatalError(t, err) defer srv.Close() - t1, err := p1.GetIdentityToken("https://ca.smallstep.com") + t1, err := p1.GetIdentityToken("foo.local", "https://ca.smallstep.com") assert.FatalError(t, err) type args struct { diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index 6ec69095..ee7fb744 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -141,7 +141,7 @@ func (p *Azure) GetEncryptedKey() (kid string, key string, ok bool) { // GetIdentityToken retrieves from the metadata service the identity token and // returns it. -func (p *Azure) GetIdentityToken() (string, error) { +func (p *Azure) GetIdentityToken(subject, caURL string) (string, error) { // Initialize the config if this method is used from the cli. p.assertConfig() @@ -264,17 +264,17 @@ func (p *Azure) AuthorizeSign(token string) ([]SignOption, error) { } } - // Enforce default DNS if configured. - // By default we'll accept the SANs in the CSR. + // Enforce known common name and default DNS if configured. + // By default we'll accept the CN and SANs in the CSR. // There's no way to trust them other than TOFU. var so []SignOption if p.DisableCustomSANs { // name will work only inside the virtual network + so = append(so, commonNameValidator(name)) so = append(so, dnsNamesValidator([]string{name})) } return append(so, - commonNameValidator(name), profileDefaultDuration(p.claimer.DefaultTLSCertDuration()), newProvisionerExtensionOption(TypeAzure, p.Name, p.TenantID), newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()), diff --git a/authority/provisioner/azure_test.go b/authority/provisioner/azure_test.go index a247dbfa..c370682a 100644 --- a/authority/provisioner/azure_test.go +++ b/authority/provisioner/azure_test.go @@ -46,9 +46,9 @@ func TestAzure_GetTokenID(t *testing.T) { p2.keyStore = p1.keyStore p2.DisableTrustOnFirstUse = true - t1, err := p1.GetIdentityToken() + t1, err := p1.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) - t2, err := p2.GetIdentityToken() + t2, err := p2.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) sum := sha256.Sum256([]byte("/subscriptions/subscriptionID/resourceGroups/resourceGroup/providers/Microsoft.Compute/virtualMachines/virtualMachine")) @@ -105,23 +105,28 @@ func TestAzure_GetIdentityToken(t *testing.T) { })) defer srv.Close() + type args struct { + subject string + caURL string + } tests := []struct { name string azure *Azure + args args identityTokenURL string want string wantErr bool }{ - {"ok", p1, srv.URL, t1, false}, - {"fail request", p1, srv.URL + "/bad-request", "", true}, - {"fail unmarshal", p1, srv.URL + "/bad-json", "", true}, - {"fail url", p1, "://ca.smallstep.com", "", true}, - {"fail connect", p1, "foobarzar", "", true}, + {"ok", p1, args{"subject", "caURL"}, srv.URL, t1, false}, + {"fail request", p1, args{"subject", "caURL"}, srv.URL + "/bad-request", "", true}, + {"fail unmarshal", p1, args{"subject", "caURL"}, srv.URL + "/bad-json", "", true}, + {"fail url", p1, args{"subject", "caURL"}, "://ca.smallstep.com", "", true}, + {"fail connect", p1, args{"subject", "caURL"}, "foobarzar", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.azure.config.identityTokenURL = tt.identityTokenURL - got, err := tt.azure.GetIdentityToken() + got, err := tt.azure.GetIdentityToken(tt.args.subject, tt.args.caURL) if (err != nil) != tt.wantErr { t.Errorf("Azure.GetIdentityToken() error = %v, wantErr %v", err, tt.wantErr) return @@ -231,13 +236,13 @@ func TestAzure_AuthorizeSign(t *testing.T) { badKey, err := generateJSONWebKey() assert.FatalError(t, err) - t1, err := p1.GetIdentityToken() + t1, err := p1.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) - t2, err := p2.GetIdentityToken() + t2, err := p2.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) - t3, err := p3.GetIdentityToken() + t3, err := p3.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) - t4, err := p4.GetIdentityToken() + t4, err := p4.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) t11, err := generateAzureToken("subject", p1.oidcConfig.Issuer, azureDefaultAudience, @@ -276,9 +281,9 @@ func TestAzure_AuthorizeSign(t *testing.T) { wantLen int wantErr bool }{ - {"ok", p1, args{t1}, 4, false}, + {"ok", p1, args{t1}, 3, false}, {"ok", p2, args{t2}, 5, false}, - {"ok", p1, args{t11}, 4, false}, + {"ok", p1, args{t11}, 3, false}, {"fail tenant", p3, args{t3}, 0, true}, {"fail resource group", p4, args{t4}, 0, true}, {"fail token", p1, args{"token"}, 0, true}, @@ -338,7 +343,7 @@ func TestAzure_AuthorizeRevoke(t *testing.T) { assert.FatalError(t, err) defer srv.Close() - token, err := az.GetIdentityToken() + token, err := az.GetIdentityToken("subject", "caURL") assert.FatalError(t, err) type args struct { diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index 71f4413a..234b00fe 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -150,7 +150,7 @@ func (p *GCP) GetIdentityURL(audience string) string { } // GetIdentityToken does an HTTP request to the identity url. -func (p *GCP) GetIdentityToken(caURL string) (string, error) { +func (p *GCP) GetIdentityToken(subject, caURL string) (string, error) { audience, err := generateSignAudience(caURL, p.GetID()) if err != nil { return "", err @@ -212,21 +212,24 @@ func (p *GCP) AuthorizeSign(token string) ([]SignOption, error) { } ce := claims.Google.ComputeEngine - // Enforce default DNS if configured. - // By default we we'll accept the SANs in the CSR. + // Enforce known common name and default DNS if configured. + // By default we we'll accept the CN and SANs in the CSR. // There's no way to trust them other than TOFU. var so []SignOption if p.DisableCustomSANs { + dnsName1 := fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID) + dnsName2 := fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID) + so = append(so, commonNameSliceValidator([]string{ + ce.InstanceName, ce.InstanceID, dnsName1, dnsName2, + })) so = append(so, dnsNamesValidator([]string{ - fmt.Sprintf("%s.c.%s.internal", ce.InstanceName, ce.ProjectID), - fmt.Sprintf("%s.%s.c.%s.internal", ce.InstanceName, ce.Zone, ce.ProjectID), + dnsName1, dnsName2, })) } return append(so, - commonNameValidator(ce.InstanceName), profileDefaultDuration(p.claimer.DefaultTLSCertDuration()), - newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject), + newProvisionerExtensionOption(TypeGCP, p.Name, claims.Subject, "InstanceID", ce.InstanceID, "InstanceName", ce.InstanceName), newValidityValidator(p.claimer.MinTLSCertDuration(), p.claimer.MaxTLSCertDuration()), ), nil } diff --git a/authority/provisioner/gcp_test.go b/authority/provisioner/gcp_test.go index ca3a9507..ce935526 100644 --- a/authority/provisioner/gcp_test.go +++ b/authority/provisioner/gcp_test.go @@ -117,7 +117,8 @@ func TestGCP_GetIdentityToken(t *testing.T) { defer srv.Close() type args struct { - caURL string + subject string + caURL string } tests := []struct { name string @@ -127,16 +128,16 @@ func TestGCP_GetIdentityToken(t *testing.T) { want string wantErr bool }{ - {"ok", p1, args{"https://ca"}, srv.URL, t1, false}, - {"fail ca url", p1, args{"://ca"}, srv.URL, "", true}, - {"fail request", p1, args{"https://ca"}, srv.URL + "/bad-request", "", true}, - {"fail url", p1, args{"https://ca"}, "://ca.smallstep.com", "", true}, - {"fail connect", p1, args{"https://ca"}, "foobarzar", "", true}, + {"ok", p1, args{"subject", "https://ca"}, srv.URL, t1, false}, + {"fail ca url", p1, args{"subject", "://ca"}, srv.URL, "", true}, + {"fail request", p1, args{"subject", "https://ca"}, srv.URL + "/bad-request", "", true}, + {"fail url", p1, args{"subject", "https://ca"}, "://ca.smallstep.com", "", true}, + {"fail connect", p1, args{"subject", "https://ca"}, "foobarzar", "", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.gcp.config.IdentityURL = tt.identityURL - got, err := tt.gcp.GetIdentityToken(tt.args.caURL) + got, err := tt.gcp.GetIdentityToken(tt.args.subject, tt.args.caURL) t.Log(err) if (err != nil) != tt.wantErr { t.Errorf("GCP.GetIdentityToken() error = %v, wantErr %v", err, tt.wantErr) @@ -310,9 +311,9 @@ func TestGCP_AuthorizeSign(t *testing.T) { wantLen int wantErr bool }{ - {"ok", p1, args{t1}, 4, false}, + {"ok", p1, args{t1}, 3, false}, {"ok", p2, args{t2}, 5, false}, - {"ok", p3, args{t3}, 4, false}, + {"ok", p3, args{t3}, 3, false}, {"fail token", p1, args{"token"}, 0, true}, {"fail key", p1, args{failKey}, 0, true}, {"fail iss", p1, args{failIss}, 0, true}, diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index b8b4e51a..fa7e1d6f 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -55,7 +55,12 @@ func (v profileWithOption) Option(Options) x509util.WithOption { type profileDefaultDuration time.Duration func (v profileDefaultDuration) Option(so Options) x509util.WithOption { - return x509util.WithNotBeforeAfterDuration(so.NotBefore.Time(), so.NotAfter.Time(), time.Duration(v)) + notBefore := so.NotBefore.Time() + if notBefore.IsZero() { + notBefore = time.Now() + } + notAfter := so.NotAfter.RelativeTime(notBefore) + return x509util.WithNotBeforeAfterDuration(notBefore, notAfter, time.Duration(v)) } // emailOnlyIdentity is a CertificateRequestValidator that checks that the only @@ -97,6 +102,21 @@ func (v commonNameValidator) Valid(req *x509.CertificateRequest) error { return nil } +// commonNameSliceValidator validates thats the common name of a certificate request is present in the slice. +type commonNameSliceValidator []string + +func (v commonNameSliceValidator) Valid(req *x509.CertificateRequest) error { + if req.Subject.CommonName == "" { + return errors.New("certificate request cannot contain an empty common name") + } + for _, cn := range v { + if req.Subject.CommonName == cn { + return nil + } + } + return errors.Errorf("certificate request does not contain the valid common name, got %s, want %s", req.Subject.CommonName, v) +} + // dnsNamesValidator validates the DNS names SAN of a certificate request. type dnsNamesValidator []string @@ -180,29 +200,32 @@ var ( ) type stepProvisionerASN1 struct { - Type int - Name []byte - CredentialID []byte + Type int + Name []byte + CredentialID []byte + KeyValuePairs []string `asn1:"optional,omitempty"` } type provisionerExtensionOption struct { - Type int - Name string - CredentialID string + Type int + Name string + CredentialID string + KeyValuePairs []string } -func newProvisionerExtensionOption(typ Type, name, credentialID string) *provisionerExtensionOption { +func newProvisionerExtensionOption(typ Type, name, credentialID string, keyValuePairs ...string) *provisionerExtensionOption { return &provisionerExtensionOption{ - Type: int(typ), - Name: name, - CredentialID: credentialID, + Type: int(typ), + Name: name, + CredentialID: credentialID, + KeyValuePairs: keyValuePairs, } } func (o *provisionerExtensionOption) Option(Options) x509util.WithOption { return func(p x509util.Profile) error { crt := p.Subject() - ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID) + ext, err := createProvisionerExtension(o.Type, o.Name, o.CredentialID, o.KeyValuePairs...) if err != nil { return err } @@ -211,11 +234,12 @@ func (o *provisionerExtensionOption) Option(Options) x509util.WithOption { } } -func createProvisionerExtension(typ int, name, credentialID string) (pkix.Extension, error) { +func createProvisionerExtension(typ int, name, credentialID string, keyValuePairs ...string) (pkix.Extension, error) { b, err := asn1.Marshal(stepProvisionerASN1{ - Type: typ, - Name: []byte(name), - CredentialID: []byte(credentialID), + Type: typ, + Name: []byte(name), + CredentialID: []byte(credentialID), + KeyValuePairs: keyValuePairs, }) if err != nil { return pkix.Extension{}, errors.Wrapf(err, "error marshaling provisioner extension") diff --git a/authority/provisioner/sign_options_test.go b/authority/provisioner/sign_options_test.go index e1349974..18e5b8d2 100644 --- a/authority/provisioner/sign_options_test.go +++ b/authority/provisioner/sign_options_test.go @@ -64,6 +64,30 @@ func Test_commonNameValidator_Valid(t *testing.T) { } } +func Test_commonNameSliceValidator_Valid(t *testing.T) { + type args struct { + req *x509.CertificateRequest + } + tests := []struct { + name string + v commonNameSliceValidator + args args + wantErr bool + }{ + {"ok", []string{"foo.bar.zar"}, args{&x509.CertificateRequest{Subject: pkix.Name{CommonName: "foo.bar.zar"}}}, false}, + {"ok", []string{"example.com", "foo.bar.zar"}, args{&x509.CertificateRequest{Subject: pkix.Name{CommonName: "foo.bar.zar"}}}, false}, + {"empty", []string{""}, args{&x509.CertificateRequest{Subject: pkix.Name{CommonName: ""}}}, true}, + {"wrong", []string{"foo.bar.zar"}, args{&x509.CertificateRequest{Subject: pkix.Name{CommonName: "example.com"}}}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.v.Valid(tt.args.req); (err != nil) != tt.wantErr { + t.Errorf("commonNameSliceValidator.Valid() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + func Test_dnsNamesValidator_Valid(t *testing.T) { type args struct { req *x509.CertificateRequest diff --git a/authority/provisioner/timeduration.go b/authority/provisioner/timeduration.go index e3152808..fea967d5 100644 --- a/authority/provisioner/timeduration.go +++ b/authority/provisioner/timeduration.go @@ -104,6 +104,12 @@ func (t *TimeDuration) UnmarshalJSON(data []byte) error { // Time calculates the embedded time.Time, sets it if necessary, and returns it. func (t *TimeDuration) Time() time.Time { + return t.RelativeTime(now()) +} + +// RelativeTime returns the embedded time.Time or the base time plus the +// duration if this is not zero. +func (t *TimeDuration) RelativeTime(base time.Time) time.Time { switch { case t == nil: return time.Time{} @@ -111,8 +117,8 @@ func (t *TimeDuration) Time() time.Time { if t.d == 0 { return time.Time{} } - t.t = now().Add(t.d) - return t.t + t.t = base.Add(t.d) + return t.t.UTC() default: return t.t.UTC() } diff --git a/authority/provisioner/utils_test.go b/authority/provisioner/utils_test.go index d74db2b6..7871b75d 100644 --- a/authority/provisioner/utils_test.go +++ b/authority/provisioner/utils_test.go @@ -283,20 +283,12 @@ func generateAWSWithServer() (*AWS, *httptest.Server, error) { if err != nil { return nil, nil, errors.Wrap(err, "error parsing AWS private key") } - instanceID, err := randutil.Alphanumeric(10) - if err != nil { - return nil, nil, err - } - imageID, err := randutil.Alphanumeric(10) - if err != nil { - return nil, nil, err - } doc, err := json.MarshalIndent(awsInstanceIdentityDocument{ AccountID: aws.Accounts[0], Architecture: "x86_64", AvailabilityZone: "us-west-2b", - ImageID: imageID, - InstanceID: instanceID, + ImageID: "image-id", + InstanceID: "instance-id", InstanceType: "t2.micro", PendingTime: time.Now(), PrivateIP: "127.0.0.1", @@ -322,6 +314,8 @@ func generateAWSWithServer() (*AWS, *httptest.Server, error) { w.Write([]byte("{}")) case "/bad-signature": w.Write([]byte("YmFkLXNpZ25hdHVyZQo=")) + case "/bad-json": + w.Write([]byte("{")) default: http.NotFound(w, r) } From 3e69194cc45c650b8105e78f533789f121d6957b Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 15 Jul 2019 16:35:51 -0700 Subject: [PATCH 2/2] Fix lint error --- Gopkg.lock | 194 +----------------------------- authority/provisioner/aws_test.go | 1 + 2 files changed, 3 insertions(+), 192 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 830482b6..b629b1f1 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -66,14 +66,6 @@ pruneopts = "UT" revision = "6a90982ecee230ff6cba02d5bd386acc030be9d3" -[[projects]] - digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" - name = "github.com/ghodss/yaml" - packages = ["."] - pruneopts = "UT" - revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" - version = "v1.0.0" - [[projects]] branch = "master" digest = "1:81fda4d18a16651bf92245ce5d6178cdd99f918db30ae9794732655f0686e895" @@ -90,17 +82,6 @@ revision = "72cd26f257d44c1114970e19afddcd812016007e" version = "v1.4.1" -[[projects]] - digest = "1:b402bb9a24d108a9405a6f34675091b036c8b056aac843bf6ef2389a65c5cf48" - name = "github.com/gogo/protobuf" - packages = [ - "proto", - "sortkeys", - ] - pruneopts = "UT" - revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7" - version = "v1.2.0" - [[projects]] branch = "travis-1.9" digest = "1:e8f5d9c09a7209c740e769713376abda388c41b777ba8e9ed52767e21acf379f" @@ -113,27 +94,13 @@ revision = "883fe33ffc4344bad1ecd881f61afd5ec5d80e0a" [[projects]] - digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf" + digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d" name = "github.com/golang/protobuf" - packages = [ - "proto", - "ptypes", - "ptypes/any", - "ptypes/duration", - "ptypes/timestamp", - ] + packages = ["proto"] pruneopts = "UT" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" -[[projects]] - branch = "master" - digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb" - name = "github.com/google/gofuzz" - packages = ["."] - pruneopts = "UT" - revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" - [[projects]] branch = "master" digest = "1:750e747d0aad97b79f4a4e00034bae415c2ea793fd9e61438d966ee9c79579bf" @@ -150,14 +117,6 @@ pruneopts = "UT" revision = "1003c8bd00dc2869cb5ca5282e6ce33834fed514" -[[projects]] - digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea" - name = "github.com/json-iterator/go" - packages = ["."] - pruneopts = "UT" - revision = "1624edc4454b8682399def8740d46db5e4362ba4" - version = "v1.1.5" - [[projects]] branch = "master" digest = "1:e51f40f0c19b39c1825eadd07d5c0a98a2ad5942b166d9fc4f54750ce9a04810" @@ -235,22 +194,6 @@ pruneopts = "UT" revision = "2e7d06bc7ada2979f17ccf8ebf486dba23b84fc7" -[[projects]] - digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563" - name = "github.com/modern-go/concurrent" - packages = ["."] - pruneopts = "UT" - revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" - version = "1.0.3" - -[[projects]] - digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" - name = "github.com/modern-go/reflect2" - packages = ["."] - pruneopts = "UT" - revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" - version = "1.0.1" - [[projects]] digest = "1:266d082179f3a29a4bdcf1dcc49d4a304f5c7107e65bd22d1fecacf45f1ac348" name = "github.com/newrelic/go-agent" @@ -493,54 +436,6 @@ revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610" version = "v1.5.0" -[[projects]] - branch = "master" - digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c" - name = "google.golang.org/genproto" - packages = ["googleapis/rpc/status"] - pruneopts = "UT" - revision = "4b09977fb92221987e99d190c8f88f2c92727a29" - -[[projects]] - digest = "1:9ab5a33d8cb5c120602a34d2e985ce17956a4e8c2edce7e6961568f95e40c09a" - name = "google.golang.org/grpc" - packages = [ - ".", - "balancer", - "balancer/base", - "balancer/roundrobin", - "binarylog/grpc_binarylog_v1", - "codes", - "connectivity", - "credentials", - "credentials/internal", - "encoding", - "encoding/proto", - "grpclog", - "internal", - "internal/backoff", - "internal/binarylog", - "internal/channelz", - "internal/envconfig", - "internal/grpcrand", - "internal/grpcsync", - "internal/syscall", - "internal/transport", - "keepalive", - "metadata", - "naming", - "peer", - "resolver", - "resolver/dns", - "resolver/passthrough", - "stats", - "status", - "tap", - ] - pruneopts = "UT" - revision = "a02b0774206b209466313a0b525d2c738fe407eb" - version = "v1.18.0" - [[projects]] digest = "1:39efb07a0d773dc09785b237ada4e10b5f28646eb6505d97bc18f8d2ff439362" name = "gopkg.in/alecthomas/kingpin.v3-unstable" @@ -548,14 +443,6 @@ pruneopts = "UT" revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306" -[[projects]] - digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" - name = "gopkg.in/inf.v0" - packages = ["."] - pruneopts = "UT" - revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" - version = "v0.9.1" - [[projects]] digest = "1:9593bab40e981b1f90b7e07faeab0d09b75fe338880d08880f986a9d3283c53f" name = "gopkg.in/square/go-jose.v2" @@ -577,82 +464,14 @@ revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" -[[projects]] - branch = "master" - digest = "1:767b6c0b2c1d9487ee50cb8df1d0fdebf06ac0b19b723f6489d388e7b47c962d" - name = "k8s.io/api" - packages = [ - "admission/v1beta1", - "authentication/v1", - "core/v1", - ] - pruneopts = "UT" - revision = "de494049e22a9ccf748c5bbda7492f42f344d0cd" - -[[projects]] - branch = "master" - digest = "1:5eb353533eaebdfec2392210ab218a389965ba5d4dc02b4aef87b9549e5d0f84" - name = "k8s.io/apimachinery" - packages = [ - "pkg/api/resource", - "pkg/apis/meta/v1", - "pkg/apis/meta/v1/unstructured", - "pkg/conversion", - "pkg/conversion/queryparams", - "pkg/fields", - "pkg/labels", - "pkg/runtime", - "pkg/runtime/schema", - "pkg/runtime/serializer", - "pkg/runtime/serializer/json", - "pkg/runtime/serializer/protobuf", - "pkg/runtime/serializer/recognizer", - "pkg/runtime/serializer/versioning", - "pkg/selection", - "pkg/types", - "pkg/util/errors", - "pkg/util/framer", - "pkg/util/intstr", - "pkg/util/json", - "pkg/util/naming", - "pkg/util/net", - "pkg/util/runtime", - "pkg/util/sets", - "pkg/util/validation", - "pkg/util/validation/field", - "pkg/util/yaml", - "pkg/watch", - "third_party/forked/golang/reflect", - ] - pruneopts = "UT" - revision = "4b3b852955ebe47857fcf134b531b23dd8f3e793" - -[[projects]] - digest = "1:72fd56341405f53c745377e0ebc4abeff87f1a048e0eea6568a20212650f5a82" - name = "k8s.io/klog" - packages = ["."] - pruneopts = "UT" - revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0" - version = "v0.2.0" - -[[projects]] - digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849" - name = "sigs.k8s.io/yaml" - packages = ["."] - pruneopts = "UT" - revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480" - version = "v1.1.0" - [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [ "github.com/alecthomas/gometalinter", "github.com/client9/misspell/cmd/misspell", - "github.com/ghodss/yaml", "github.com/go-chi/chi", "github.com/golang/lint/golint", - "github.com/golang/protobuf/proto", "github.com/gordonklaus/ineffassign", "github.com/newrelic/go-agent", "github.com/pkg/errors", @@ -675,18 +494,9 @@ "github.com/tsenart/deadcode", "github.com/urfave/cli", "golang.org/x/crypto/ocsp", - "golang.org/x/net/context", "golang.org/x/net/http2", - "google.golang.org/grpc", - "google.golang.org/grpc/credentials", - "google.golang.org/grpc/peer", "gopkg.in/square/go-jose.v2", "gopkg.in/square/go-jose.v2/jwt", - "k8s.io/api/admission/v1beta1", - "k8s.io/api/core/v1", - "k8s.io/apimachinery/pkg/apis/meta/v1", - "k8s.io/apimachinery/pkg/runtime", - "k8s.io/apimachinery/pkg/runtime/serializer", ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/authority/provisioner/aws_test.go b/authority/provisioner/aws_test.go index ce1320ab..41793848 100644 --- a/authority/provisioner/aws_test.go +++ b/authority/provisioner/aws_test.go @@ -255,6 +255,7 @@ func TestAWS_AuthorizeSign(t *testing.T) { t2PrivateIP, err := p2.GetIdentityToken("127.0.0.1", "https://ca.smallstep.com") assert.FatalError(t, err) t2Hostname, err := p2.GetIdentityToken("ip-127-0-0-1.us-west-1.compute.internal", "https://ca.smallstep.com") + assert.FatalError(t, err) block, _ := pem.Decode([]byte(awsTestKey)) if block == nil || block.Type != "RSA PRIVATE KEY" {