Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #850 from upodroid/cloudrun-sva
Browse files Browse the repository at this point in the history
Add Service Account Field to Cloud Run
  • Loading branch information
mitchellh committed Nov 28, 2020
1 parent f68806f commit 44b186c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ IMPROVEMENTS:
* core: align `-raw` flag to behave like `-json` flag with `waypoint config set` [GH-828]
* plugin/aws-ecr: environment variables to be used instead of 'region' property for aws-ecr registry [GH-841]
* plugin/google-cloud-run: allow images from Google Artifact Registry [GH-804]
* plugin/google-cloud-run: added service account name field [GH-850]

BUG FIXES:

Expand Down
11 changes: 11 additions & 0 deletions builtin/google/cloudrun/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/hashicorp/go-hclog"
"google.golang.org/api/googleapi"
"google.golang.org/api/iam/v1"
"google.golang.org/api/option"
run "google.golang.org/api/run/v1"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -53,6 +54,16 @@ func (d *Deployment) apiService(ctx context.Context) (*run.APIService, error) {
return result, nil
}

// iamAPIService returns the IAM API service for GCP client usage.
func (d *Deployment) iamAPIService(ctx context.Context) (*iam.Service, error) {
result, err := iam.NewService(ctx)
if err != nil {
return nil, status.Errorf(codes.Aborted, err.Error())
}

return result, nil
}

// getLocationsForProject returns the Cloud Run regions which are usable by this project
func (d *Deployment) getLocationsForProject(ctx context.Context) ([]*run.Location, error) {
apiService, err := run.NewService(ctx)
Expand Down
59 changes: 56 additions & 3 deletions builtin/google/cloudrun/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/hashicorp/go-hclog"
"google.golang.org/api/iam/v1"
run "google.golang.org/api/run/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -119,10 +120,10 @@ func (p *Platform) ValidateAuth(
src.App,
)

st.Update("Testing IAM permissions...")
st.Update("Testing Cloud Run IAM permissions...")
result, err := client.TestIamPermissions(apiResource, &testReq).Do()
if err != nil {
st.Step(terminal.StatusError, "Error testing IAM permissions: "+err.Error())
st.Step(terminal.StatusError, "Error testing Cloud Run IAM permissions: "+err.Error())
return err
}

Expand All @@ -132,10 +133,48 @@ func (p *Platform) ValidateAuth(
return fmt.Errorf("incorrect IAM permissions, received %s", strings.Join(result.Permissions, ", "))
}

// Validate if user has access to the service account specified
if p.config.ServiceAccountName != "" {

iamAPIService, err := deployment.iamAPIService(ctx)
if err != nil {
ui.Output("Error constructing api client: "+err.Error(), terminal.WithErrorStyle())
return status.Errorf(codes.Aborted, err.Error())
}

client := iam.NewProjectsServiceAccountsService(iamAPIService)

expectedPermissions := []string{
"iam.serviceAccounts.actAs",
}

// We need to ensure that the service creator has Service Account User role.
testReq := iam.TestIamPermissionsRequest{
Permissions: expectedPermissions,
}

apiResource := fmt.Sprintf("projects/%s/serviceAccounts/%s",
p.config.Project,
p.config.ServiceAccountName,
)

st.Update("Testing IAM permissions on the supplied service account...")
result, err := client.TestIamPermissions(apiResource, &testReq).Do()
if err != nil {
st.Step(terminal.StatusError, "Error testing IAM permissions of the Service Account: "+err.Error())
return err
}

// If our resulting permissions do not equal our expected permissions, auth does not validate
if !reflect.DeepEqual(result.Permissions, expectedPermissions) {
st.Step(terminal.StatusError, "Incorrect IAM permissions on the Service Account, received "+strings.Join(result.Permissions, ", "))
return fmt.Errorf("Incorrect IAM permissions on the Service Account, received %s", strings.Join(result.Permissions, ", "))
}
}
return nil
}

// Deploy deploys an image to GCR.
// Deploy deploys an image to Cloud Run.
func (p *Platform) Deploy(
ctx context.Context,
log hclog.Logger,
Expand Down Expand Up @@ -323,6 +362,10 @@ func (p *Platform) Deploy(
*/
}

if p.config.ServiceAccountName != "" {
service.Spec.Template.Spec.ServiceAccountName = p.config.ServiceAccountName
}

if create {
// Create the service
log.Info("creating the service")
Expand Down Expand Up @@ -433,6 +476,8 @@ app "wpmini" {
request_timeout = 300
}
service_account_name = "cloudrun@waypoint-project-id.iam.gserviceaccount.com"
auto_scaling {
max = 10
}
Expand Down Expand Up @@ -504,6 +549,11 @@ app "wpmini" {
"Configuration to control the auto scaling parameters for Cloud Run.",
)

doc.SetField(
"service_account_name",
"Specify a service account email that Cloud Run will use to run the service. You must have the `iam.serviceAccounts.actAs` permission on the service account.",
)

doc.SetField(
"auto_scaling.max",
`Maximum number of Cloud Run instances. When the maximum requests per container is exceeded, Cloud Run will create an additional container instance to handle load.
Expand Down Expand Up @@ -543,6 +593,9 @@ type Config struct {

// AutoScaling details.
AutoScaling *AutoScaling `hcl:"auto_scaling,block"`

// Service Account details
ServiceAccountName string `hcl:"service_account_name,optional"`
}

// Capacity defines configuration for deployed Cloud Run resources
Expand Down

0 comments on commit 44b186c

Please sign in to comment.