From 84bacedac113a6c8abfb14db5df7aa311c6b6277 Mon Sep 17 00:00:00 2001 From: Robert Kopaczewski Date: Mon, 1 Aug 2022 15:27:54 +0200 Subject: [PATCH] fix: cloud function public iam --- deploy/app_function.go | 1 + gcp/cloud_function.go | 97 ++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/deploy/app_function.go b/deploy/app_function.go index f75465e..79fdaaf 100644 --- a/deploy/app_function.go +++ b/deploy/app_function.go @@ -148,6 +148,7 @@ func (o *FunctionApp) Plan(ctx context.Context, pctx *config.PluginContext, r *r Runtime: fields.String(o.Props.Runtime), SourceBucket: o.Bucket.Name, SourceObject: o.Archive.Name, + IsPublic: fields.Bool(!o.Props.Private), MinScale: fields.Int(o.DeployOpts.MinScale), MaxScale: fields.Int(o.DeployOpts.MaxScale), diff --git a/gcp/cloud_function.go b/gcp/cloud_function.go index 43aa158..86b7e14 100644 --- a/gcp/cloud_function.go +++ b/gcp/cloud_function.go @@ -12,6 +12,7 @@ import ( "github.com/outblocks/cli-plugin-gcp/internal/config" "github.com/outblocks/outblocks-plugin-go/registry" "github.com/outblocks/outblocks-plugin-go/registry/fields" + plugin_util "github.com/outblocks/outblocks-plugin-go/util" "google.golang.org/api/cloudfunctions/v1" ) @@ -25,6 +26,7 @@ type CloudFunction struct { Runtime fields.StringInputField SourceBucket fields.StringInputField SourceObject fields.StringInputField + IsPublic fields.BoolInputField URL fields.StringOutputField Ready fields.BoolOutputField @@ -103,6 +105,22 @@ func (o *CloudFunction) Read(ctx context.Context, meta interface{}) error { o.EnvVars.SetCurrent(envVars) o.Ingress.SetCurrent(cf.IngressSettings) + policy, err := cli.Projects.Locations.Functions.GetIamPolicy(cf.Name).Do() + if err != nil { + return fmt.Errorf("error fetching cloud function policy: %w", err) + } + + isPublic := false + + for _, b := range policy.Bindings { + if b.Role == "roles/cloudfunctions.invoker" { + isPublic = plugin_util.StringSliceContains(b.Members, "allUsers") + break + } + } + + o.IsPublic.SetCurrent(isPublic) + return nil } @@ -166,6 +184,28 @@ func (o *CloudFunction) Create(ctx context.Context, meta interface{}) error { o.setCurrentStatusInfo(cf) + if !o.IsPublic.Wanted() { + return nil + } + + policy, err := cli.Projects.Locations.Functions.GetIamPolicy(cf.Name).Do() + if err != nil { + return fmt.Errorf("error fetching cloud function policy: %w", err) + } + + policy.Bindings = append(policy.Bindings, &cloudfunctions.Binding{ + Members: []string{"allUsers"}, + Role: "roles/cloudfunctions.invoker", + }) + + _, err = cli.Projects.Locations.Functions.SetIamPolicy(cf.Name, &cloudfunctions.SetIamPolicyRequest{ + Policy: policy, + }).Do() + + if err != nil { + return fmt.Errorf("error settings cloud function policy: %w", err) + } + return nil } @@ -199,6 +239,63 @@ func (o *CloudFunction) Update(ctx context.Context, meta interface{}) error { o.setCurrentStatusInfo(cf) + policy, err := cli.Projects.Locations.Functions.GetIamPolicy(cf.Name).Do() + if err != nil { + return fmt.Errorf("error fetching cloud function policy: %w", err) + } + + var newBindings []*cloudfunctions.Binding + + added := false + + for _, b := range policy.Bindings { + if b.Role == "roles/cloudfunctions.invoker" { + if !o.IsPublic.Wanted() { + if !plugin_util.StringSliceContains(b.Members, "allUsers") { + newBindings = append(newBindings, b) + continue + } + + // Remove member or whole binding if it's the only member. + if len(b.Members) == 1 { + continue + } + + var newMembers []string + + for _, m := range b.Members { + if m != "allUsers" { + newMembers = append(newMembers, m) + } + } + + b.Members = newMembers + } else if !plugin_util.StringSliceContains(b.Members, "allUsers") { + b.Members = append(b.Members, "allUsers") + added = true + } + } + + newBindings = append(newBindings, b) + } + + if o.IsPublic.Wanted() && !added { + newBindings = append(newBindings, &cloudfunctions.Binding{ + Members: []string{"allUsers"}, + Role: "roles/cloudfunctions.invoker", + }) + } + + policy.Bindings = newBindings + + _, err = cli.Projects.Locations.Functions.SetIamPolicy(cf.Name, &cloudfunctions.SetIamPolicyRequest{ + Policy: policy, + }).Do() + + if err != nil { + return fmt.Errorf("error settings cloud function policy: %w", err) + } + return nil } diff --git a/go.mod b/go.mod index 4265bd1..6076418 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/docker/docker v20.10.17+incompatible github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/google/go-containerregistry v0.9.0 - github.com/outblocks/outblocks-plugin-go v0.0.0-20220630124715-bf4c067bd696 + github.com/outblocks/outblocks-plugin-go v0.0.0-20220712161354-7d8111dfc469 golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 google.golang.org/api v0.85.0 google.golang.org/genproto v0.0.0-20220622171453-ea41d75dfa0f diff --git a/go.sum b/go.sum index c4c3951..1ff7501 100644 --- a/go.sum +++ b/go.sum @@ -560,8 +560,8 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/outblocks/outblocks-plugin-go v0.0.0-20220630124715-bf4c067bd696 h1:MXOTKabSMpaxZjR79MsN8gHd9H7qT7tVtLRvDq6u+Q0= -github.com/outblocks/outblocks-plugin-go v0.0.0-20220630124715-bf4c067bd696/go.mod h1:Wnb50otE4YCKHxyxpnJi1G3iYVW5pnTAeLHpo3Mu0Lk= +github.com/outblocks/outblocks-plugin-go v0.0.0-20220712161354-7d8111dfc469 h1:KviouI7jaoEij8qlvLlKf6EMcUwCWWrwtQ7kqFo+OnY= +github.com/outblocks/outblocks-plugin-go v0.0.0-20220712161354-7d8111dfc469/go.mod h1:Wnb50otE4YCKHxyxpnJi1G3iYVW5pnTAeLHpo3Mu0Lk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=