-
Notifications
You must be signed in to change notification settings - Fork 7
Fix CLoud Build SA #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix CLoud Build SA #130
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -135,7 +135,6 @@ func setPermissionsForCloudBuildSA(ctx context.Context, projectID, serviceAccoun | |||||
| gcbSARoles := []string{ | ||||||
| "roles/artifactregistry.writer", | ||||||
| "roles/cloudbuild.builds.editor", | ||||||
| "roles/cloudbuild.workerpools.use", | ||||||
| "roles/developerconnect.tokenAccessor", | ||||||
| "roles/logging.logWriter", | ||||||
| "roles/run.developer", | ||||||
|
|
@@ -174,14 +173,21 @@ func setPermissionsForCloudBuildSA(ctx context.Context, projectID, serviceAccoun | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| // 4. Role for the Cloud Build Service Agent on the Cloud Run SA (Default Compute SA) | ||||||
| // 4. Grant Cloud Build Service Agent permissions to impersonate the Cloud Run SA (Default Compute SA) | ||||||
| defaultComputeSA := fmt.Sprintf("serviceAccount:%d-compute@developer.gserviceaccount.com", projectNumber) | ||||||
| resource := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, strings.TrimPrefix(defaultComputeSA, "serviceAccount:")) | ||||||
| _, err = iamClient.AddIAMRoleBinding(ctx, resource, "roles/iam.serviceAccountUser", gcbP4sa) | ||||||
| if err != nil { | ||||||
| return "", fmt.Errorf("unable to add iam.serviceAccountUser role to Cloud Build P4SA %s on SA %s err: %w", gcbP4sa, defaultComputeSA, err) | ||||||
| } | ||||||
|
|
||||||
| // 5. Grant Cloud Build Service Agent permissions to impersonate the SA passed in (SA that is going to run the build) | ||||||
| r := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, strings.TrimPrefix(resolvedSA, "serviceAccount:")) | ||||||
| _, err = iamClient.AddIAMRoleBinding(ctx, r, "roles/iam.serviceAccountUser", gcbP4sa) | ||||||
| if err != nil { | ||||||
| return "", fmt.Errorf("unable to add iam.serviceAccountUser role to Cloud Build P4SA %s on SA %s err: %w", gcbP4sa, r, err) | ||||||
| } | ||||||
|
|
||||||
| return resolvedSA, nil | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function currently returns
Suggested change
|
||||||
| } | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,7 +42,6 @@ func TestSetPermissionsForCloudBuildSA(t *testing.T) { | |
| gcbSARoles := []string{ | ||
| "roles/artifactregistry.writer", | ||
| "roles/cloudbuild.builds.editor", | ||
| "roles/cloudbuild.workerpools.use", | ||
| "roles/developerconnect.tokenAccessor", | ||
| "roles/logging.logWriter", | ||
| "roles/run.developer", | ||
|
|
@@ -57,6 +56,7 @@ func TestSetPermissionsForCloudBuildSA(t *testing.T) { | |
| } | ||
| defaultComputeSA := fmt.Sprintf("%d-compute@developer.gserviceaccount.com", projectNumber) | ||
| saResource := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, defaultComputeSA) | ||
| userSAResource := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, "test-sa@example.com") | ||
|
|
||
| t.Run("with service account", func(t *testing.T) { | ||
| for _, r := range gcbSARoles { | ||
|
|
@@ -68,6 +68,7 @@ func TestSetPermissionsForCloudBuildSA(t *testing.T) { | |
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, fmt.Sprintf("projects/%s", projectID), r, gcbP4sa).Return(nil, nil) | ||
| } | ||
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, saResource, "roles/iam.serviceAccountUser", gcbP4sa).Return(nil, nil) | ||
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, userSAResource, "roles/iam.serviceAccountUser", gcbP4sa).Return(nil, nil) | ||
|
|
||
| resolvedSA, err := setPermissionsForCloudBuildSA(ctx, projectID, serviceAccount, mockRMClient, mockIAMClient) | ||
| assert.NoError(t, err) | ||
|
|
@@ -84,6 +85,7 @@ func TestSetPermissionsForCloudBuildSA(t *testing.T) { | |
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, fmt.Sprintf("projects/%s", projectID), r, gcbP4sa).Return(nil, nil) | ||
| } | ||
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, saResource, "roles/iam.serviceAccountUser", gcbP4sa).Return(nil, nil) | ||
| mockIAMClient.EXPECT().AddIAMRoleBinding(ctx, userSAResource, "roles/iam.serviceAccountUser", gcbP4sa).Return(nil, nil) | ||
|
|
||
| resolvedSA, err := setPermissionsForCloudBuildSA(ctx, projectID, serviceAccountWOPrefix, mockRMClient, mockIAMClient) | ||
| assert.NoError(t, err) | ||
|
|
@@ -118,3 +120,27 @@ func TestSetPermissionsForCloudBuildSA(t *testing.T) { | |
| assert.Error(t, err) | ||
| }) | ||
| } | ||
|
|
||
| func TestIsValidServiceAccount(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| sa string | ||
| want bool | ||
| }{ | ||
| {"valid sa", "serviceAccount:test-sa@project.iam.gserviceaccount.com", true}, | ||
| {"valid sa with dashes", "serviceAccount:my-sa-123@my-project-456.iam.gserviceaccount.com", true}, | ||
| {"missing prefix", "test-sa@project.iam.gserviceaccount.com", false}, | ||
| {"wrong prefix", "user:test-sa@project.iam.gserviceaccount.com", false}, | ||
| {"missing domain", "serviceAccount:test-sa@project", false}, | ||
| {"wrong domain", "serviceAccount:test-sa@project.com", false}, | ||
|
Comment on lines
+130
to
+135
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The validation logic for service accounts (and these corresponding tests) appears to be too restrictive. Google Cloud project IDs can contain dots and colons (e.g., for domain-scoped projects like |
||
| {"empty string", "", false}, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| if got := IsValidServiceAccount(tt.sa); got != tt.want { | ||
| t.Errorf("IsValidServiceAccount() = %v, want %v", got, tt.want) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.