From a54bf925ebb0f6dd635c59cce73f01ee4debacea Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 3 Jun 2019 11:56:42 -0700 Subject: [PATCH] Add filtering by GCP Project ID. Fixes smallstep/step#155 --- authority/provisioner/gcp.go | 15 +++++++++++++++ authority/provisioner/gcp_test.go | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index bc221cbd..8ee3d86c 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -70,6 +70,7 @@ type GCP struct { Type string `json:"type"` Name string `json:"name"` ServiceAccounts []string `json:"serviceAccounts"` + ProjectIDs []string `json:"projectIDs"` DisableCustomSANs bool `json:"disableCustomSANs"` DisableTrustOnFirstUse bool `json:"disableTrustOnFirstUse"` Claims *Claims `json:"claims,omitempty"` @@ -284,6 +285,20 @@ func (p *GCP) authorizeToken(token string) (*gcpPayload, error) { } } + // validate projects + if len(p.ProjectIDs) > 0 { + var found bool + for _, pi := range p.ProjectIDs { + if pi == claims.Google.ComputeEngine.ProjectID { + found = true + break + } + } + if !found { + return nil, errors.New("invalid token: invalid project id") + } + } + switch { case claims.Google.ComputeEngine.InstanceID == "": return nil, errors.New("token google.compute_engine.instance_id cannot be empty") diff --git a/authority/provisioner/gcp_test.go b/authority/provisioner/gcp_test.go index 4e63c2b1..75eac9bf 100644 --- a/authority/provisioner/gcp_test.go +++ b/authority/provisioner/gcp_test.go @@ -203,6 +203,10 @@ func TestGCP_AuthorizeSign(t *testing.T) { assert.FatalError(t, err) p2.DisableCustomSANs = true + p3, err := generateGCP() + assert.FatalError(t, err) + p3.ProjectIDs = []string{"other-project-id"} + aKey, err := generateJSONWebKey() assert.FatalError(t, err) @@ -216,6 +220,11 @@ func TestGCP_AuthorizeSign(t *testing.T) { "instance-id", "instance-name", "project-id", "zone", time.Now(), &p2.keyStore.keySet.Keys[0]) assert.FatalError(t, err) + t3, err := generateGCPToken(p3.ServiceAccounts[0], + "https://accounts.google.com", p3.GetID(), + "instance-id", "instance-name", "other-project-id", "zone", + time.Now(), &p3.keyStore.keySet.Keys[0]) + assert.FatalError(t, err) failKey, err := generateGCPToken(p1.ServiceAccounts[0], "https://accounts.google.com", p1.GetID(), @@ -247,6 +256,11 @@ func TestGCP_AuthorizeSign(t *testing.T) { "instance-id", "instance-name", "project-id", "zone", time.Now(), &p1.keyStore.keySet.Keys[0]) assert.FatalError(t, err) + failInvalidProjectID, err := generateGCPToken(p3.ServiceAccounts[0], + "https://accounts.google.com", p3.GetID(), + "instance-id", "instance-name", "project-id", "zone", + time.Now(), &p3.keyStore.keySet.Keys[0]) + assert.FatalError(t, err) failInstanceID, err := generateGCPToken(p1.ServiceAccounts[0], "https://accounts.google.com", p1.GetID(), "", "instance-name", "project-id", "zone", @@ -280,6 +294,7 @@ func TestGCP_AuthorizeSign(t *testing.T) { }{ {"ok", p1, args{t1}, 4, false}, {"ok", p2, args{t2}, 5, false}, + {"ok", p3, args{t3}, 4, false}, {"fail token", p1, args{"token"}, 0, true}, {"fail key", p1, args{failKey}, 0, true}, {"fail iss", p1, args{failIss}, 0, true}, @@ -287,6 +302,7 @@ func TestGCP_AuthorizeSign(t *testing.T) { {"fail exp", p1, args{failExp}, 0, true}, {"fail nbf", p1, args{failNbf}, 0, true}, {"fail service account", p1, args{failServiceAccount}, 0, true}, + {"fail invalid project id", p3, args{failInvalidProjectID}, 0, true}, {"fail instance id", p1, args{failInstanceID}, 0, true}, {"fail instance name", p1, args{failInstanceName}, 0, true}, {"fail project id", p1, args{failProjectID}, 0, true},