diff --git a/cmd/cluster.go b/cmd/cluster.go index 3cc7f30..264e045 100644 --- a/cmd/cluster.go +++ b/cmd/cluster.go @@ -341,12 +341,13 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error { return err } case google_provider.GoogleClusterProvider: - // Pre-provision hook for GCP - //if err := cc.createGCPNATGateway(); err != nil { - // return err - //} + if err := cc.createGCPNATGateway(); err != nil { + return err + } - //return nil + if err := cc.createGCPSecrets(); err != nil { + return err + } } cc.SpecCMD = cc.prepareHelmfile("--log-level", "error", "-l", "cluster="+cc.Conf.ClusterProvider, "sync") @@ -397,7 +398,9 @@ func (cc *ClusterCommands) provisionDestroyTargetCluster() error { case azure_provider.AzureClusterProvider: // Pre-destroy hook for Azure case google_provider.GoogleClusterProvider: - // Pre-destroy hook for GCP + if err := cc.deleteGCPNATGateway(); err != nil { + return err + } } kubeConfig, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( diff --git a/cmd/cluster_capg.go b/cmd/cluster_capg.go index 57acdd7..6064e2d 100644 --- a/cmd/cluster_capg.go +++ b/cmd/cluster_capg.go @@ -3,11 +3,13 @@ package cmd import ( "os" "path/filepath" + "strings" corev1 "k8s.io/api/core/v1" v1 "k8s.io/client-go/applyconfigurations/core/v1" "rmk/providers/google_provider" + "rmk/util" ) const ( @@ -86,7 +88,45 @@ func (cc *ClusterCommands) getGCPClusterContext() ([]byte, error) { GetGCPClusterContext(cc.Conf.Name) } -//func (cc *ClusterCommands) createGCPNATGateway() error { -// return google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath). -// CreateGateway() -//} +func (cc *ClusterCommands) createGCPNATGateway() error { + return google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath). + CreateGCPCloudNATGateway(cc.Conf.GCPRegion) +} + +func (cc *ClusterCommands) deleteGCPNATGateway() error { + return google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath). + DeleteGCPCloudNATGateway(cc.Conf.GCPRegion) +} + +func (cc *ClusterCommands) createGCPSecrets() error { + gcp := google_provider.NewGCPConfigure(cc.Ctx.Context, cc.Conf.GCPConfigure.AppCredentialsPath) + + secrets, err := gcp.GetGCPSecrets(cc.Conf.Tenant) + if err != nil { + return err + } + + if len(secrets) > 0 { + return nil + } + + walkMatch, err := util.WalkMatch(cc.Conf.SopsAgeKeys, cc.Conf.Tenant+"*"+util.SopsAgeKeyExt) + if err != nil { + return err + } + + for _, val := range walkMatch { + file, err := os.ReadFile(val) + if err != nil { + return err + } + + keyName := strings.TrimSuffix(filepath.Base(val), util.SopsAgeKeyExt) + + if err := gcp.SetGCPSecret(cc.Conf.Tenant, cc.Conf.GCPRegion, keyName, file); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/cluster_capz.go b/cmd/cluster_capz.go index d0e5b4f..de1bae8 100644 --- a/cmd/cluster_capz.go +++ b/cmd/cluster_capz.go @@ -160,7 +160,7 @@ func (cc *ClusterCommands) createAzureSecrets(ac *azure_provider.AzureConfigure) } if len(secrets) > 0 { - return err + return nil } walkMatch, err := util.WalkMatch(cc.Conf.SopsAgeKeys, cc.Conf.Tenant+"*"+util.SopsAgeKeyExt) diff --git a/cmd/config.go b/cmd/config.go index 8cdd4ff..984ed10 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -382,7 +382,7 @@ func initAzureProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler. func initGCPProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler.GitSpec) error { gcp := google_provider.NewGCPConfigure(c.Context, - util.GetHomePath(google_provider.GoogleHomeDir, google_provider.GooglePrefix+gitSpec.ID+".json")) + util.GetHomePath(google_provider.GoogleHomeDir, google_provider.GoogleCredentialsPrefix+gitSpec.ID+".json")) if c.IsSet("google-application-credentials") { gcp.AppCredentialsPath = c.String("google-application-credentials") @@ -399,8 +399,26 @@ func initGCPProfile(c *cli.Context, conf *config.Config, gitSpec *git_handler.Gi } } + if !c.IsSet("gcp-region") { + return fmt.Errorf("GCP provider option gcp-region required") + } + + conf.GCPRegion = c.String("gcp-region") conf.GCPConfigure = gcp + secrets, err := gcp.GetGCPSecrets(conf.Tenant) + if err != nil { + return err + } + + for key, val := range secrets { + zap.S().Infof("download GCP secret %s to %s", + key, filepath.Join(conf.SopsAgeKeys, key+util.SopsAgeKeyExt)) + if err := os.WriteFile(filepath.Join(conf.SopsAgeKeys, key+util.SopsAgeKeyExt), val, 0644); err != nil { + return err + } + } + return nil } @@ -439,7 +457,7 @@ func configDeleteAction(conf *config.Config) cli.ActionFunc { } case c.String("cluster-provider") == google_provider.GoogleClusterProvider: if err := os.RemoveAll(util.GetHomePath(google_provider.GoogleHomeDir, - google_provider.GooglePrefix+conf.Name+".json")); err != nil { + google_provider.GoogleCredentialsPrefix+conf.Name+".json")); err != nil { return err } } diff --git a/cmd/flags.go b/cmd/flags.go index cc24b04..4d413e1 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -111,6 +111,15 @@ func flagsConfig() []cli.Flag { EnvVars: []string{"RMK_GITHUB_TOKEN"}, }, ), + altsrc.NewStringFlag( + &cli.StringFlag{ + Category: gcpFlagsCategory, + Name: "gcp-region", + Usage: "GCP region", + Aliases: []string{"gr"}, + EnvVars: []string{"RMK_GCP_REGION", "GCP_REGION"}, + }, + ), &cli.StringFlag{ Category: gcpFlagsCategory, Name: "google-application-credentials", diff --git a/cmd/release.go b/cmd/release.go index bd46fea..fb4a706 100644 --- a/cmd/release.go +++ b/cmd/release.go @@ -157,8 +157,10 @@ func (rc *ReleaseCommands) prepareHelmfile(args ...string) *util.SpecCMD { switch rc.Conf.ClusterProvider { case aws_provider.AWSClusterProvider: envs = append(envs, - "AWS_PROFILE="+rc.Conf.Profile, + "AWS_ACCOUNT_ID="+rc.Conf.AccountID, "AWS_CONFIG_FILE="+strings.Join(rc.Conf.AWSSharedConfigFile(rc.Conf.Profile), ""), + "AWS_PROFILE="+rc.Conf.Profile, + "AWS_REGION="+rc.Conf.Region, "AWS_SHARED_CREDENTIALS_FILE="+strings.Join(rc.Conf.AWSSharedCredentialsFile(rc.Conf.Profile), ""), ) case azure_provider.AzureClusterProvider: @@ -169,6 +171,7 @@ func (rc *ReleaseCommands) prepareHelmfile(args ...string) *util.SpecCMD { case google_provider.GoogleClusterProvider: envs = append(envs, "GCP_PROJECT_ID="+rc.Conf.GCPConfigure.ProjectID, + "GCP_REGION="+rc.Conf.GCPRegion, "GOOGLE_APPLICATION_CREDENTIALS="+rc.Conf.GCPConfigure.AppCredentialsPath, ) } diff --git a/cmd/secret.go b/cmd/secret.go index a5eabf3..0f58afc 100644 --- a/cmd/secret.go +++ b/cmd/secret.go @@ -177,6 +177,21 @@ func (sc *SecretCommands) DownloadKeys() error { return nil case google_provider.GoogleClusterProvider: + gcp := google_provider.NewGCPConfigure(sc.Ctx.Context, sc.Conf.GCPConfigure.AppCredentialsPath) + + secrets, err := gcp.GetGCPSecrets(sc.Conf.Tenant) + if err != nil { + return err + } + + for key, val := range secrets { + zap.S().Infof("download GCP secret %s to %s", + key, filepath.Join(sc.Conf.SopsAgeKeys, key+util.SopsAgeKeyExt)) + if err := os.WriteFile(filepath.Join(sc.Conf.SopsAgeKeys, key+util.SopsAgeKeyExt), val, 0644); err != nil { + return err + } + } + return nil default: return nil @@ -213,6 +228,26 @@ func (sc *SecretCommands) UploadKeys() error { return nil case google_provider.GoogleClusterProvider: + gcp := google_provider.NewGCPConfigure(sc.Ctx.Context, sc.Conf.GCPConfigure.AppCredentialsPath) + + walkMatch, err := util.WalkMatch(sc.Conf.SopsAgeKeys, sc.Conf.Tenant+"*"+util.SopsAgeKeyExt) + if err != nil { + return err + } + + for _, val := range walkMatch { + file, err := os.ReadFile(val) + if err != nil { + return err + } + + keyName := strings.TrimSuffix(filepath.Base(val), util.SopsAgeKeyExt) + + if err := gcp.SetGCPSecret(sc.Conf.Tenant, sc.Conf.GCPRegion, keyName, file); err != nil { + return err + } + } + return nil default: return nil diff --git a/config/config.go b/config/config.go index 8493676..0f05425 100644 --- a/config/config.go +++ b/config/config.go @@ -37,6 +37,7 @@ type Config struct { SopsAgeKeys string `yaml:"sops-age-keys,omitempty"` AWSMFAProfile string `yaml:"aws-mfa-profile,omitempty"` AWSMFATokenExpiration string `yaml:"aws-mfa-token-expiration,omitempty"` + GCPRegion string `yaml:"gcp-region,omitempty"` *aws_provider.AwsConfigure `yaml:"aws,omitempty"` *azure_provider.AzureConfigure `yaml:"azure,omitempty"` *google_provider.GCPConfigure `yaml:"gcp,omitempty"` diff --git a/go.mod b/go.mod index 699da08..9a4da6e 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ toolchain go1.22.8 require ( cloud.google.com/go/auth v0.10.2 + cloud.google.com/go/secretmanager v1.11.5 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 @@ -27,6 +28,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/go-git/go-git/v5 v5.11.0 github.com/google/go-github v17.0.0+incompatible + github.com/googleapis/gax-go/v2 v2.12.3 github.com/hashicorp/go-getter v1.7.3 github.com/slack-go/slack v0.12.3 github.com/urfave/cli/v2 v2.27.1 @@ -98,7 +100,6 @@ require ( github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect diff --git a/go.sum b/go.sum index de55e31..72de160 100644 --- a/go.sum +++ b/go.sum @@ -156,6 +156,8 @@ cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92 cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.11.5 h1:82fpF5vBBvu9XW4qj0FU2C6qVMtj1RM/XHwKXUEAfYY= +cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= diff --git a/providers/azure_provider/azure.go b/providers/azure_provider/azure.go index 4395456..fe0921b 100644 --- a/providers/azure_provider/azure.go +++ b/providers/azure_provider/azure.go @@ -302,32 +302,6 @@ func (ac *AzureConfigure) GetAzureKeyVault(tenant string) (bool, error) { return true, nil } -func (ac *AzureConfigure) SetAzureSecret(keyName, value string) error { - client, err := azsecrets.NewClient(ac.KeyVaultURI, ac.Credentials, nil) - if err != nil { - return err - } - - params := azsecrets.SetSecretParameters{ - Value: to.Ptr(value), - } - - secret, err := client.SetSecret(ac.Ctx, keyName, params, nil) - if err != nil { - var respErr *azcore.ResponseError - if errors.As(err, &respErr) && respErr.StatusCode == 403 { - zap.S().Warnf("permission denied to create Azure key vault secret: %s", keyName) - return nil - } - - return err - } - - zap.S().Infof("created Azure key vault secret: %s, %s", keyName, *secret.ID) - - return nil -} - func (ac *AzureConfigure) GetAzureSecrets() (map[string][]byte, error) { var secrets = make(map[string][]byte) @@ -374,3 +348,29 @@ func (ac *AzureConfigure) GetAzureSecrets() (map[string][]byte, error) { return secrets, nil } + +func (ac *AzureConfigure) SetAzureSecret(keyName, value string) error { + client, err := azsecrets.NewClient(ac.KeyVaultURI, ac.Credentials, nil) + if err != nil { + return err + } + + params := azsecrets.SetSecretParameters{ + Value: to.Ptr(value), + } + + secret, err := client.SetSecret(ac.Ctx, keyName, params, nil) + if err != nil { + var respErr *azcore.ResponseError + if errors.As(err, &respErr) && respErr.StatusCode == 403 { + zap.S().Warnf("permission denied to create Azure key vault secret: %s", keyName) + return nil + } + + return err + } + + zap.S().Infof("created Azure key vault secret: %s, %s", keyName, *secret.ID) + + return nil +} diff --git a/providers/google_provider/gcp.go b/providers/google_provider/gcp.go index d2e0345..2dbedcb 100644 --- a/providers/google_provider/gcp.go +++ b/providers/google_provider/gcp.go @@ -3,13 +3,23 @@ package google_provider import ( "context" "encoding/base64" + "errors" "fmt" + "hash/crc32" "os" + "path/filepath" "strings" "cloud.google.com/go/auth" "cloud.google.com/go/auth/credentials" + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb" + "github.com/googleapis/gax-go/v2/apierror" + "go.uber.org/zap" + "google.golang.org/api/compute/v1" container "google.golang.org/api/container/v1beta1" + "google.golang.org/api/googleapi" + "google.golang.org/api/iterator" "google.golang.org/api/option" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" @@ -18,9 +28,15 @@ import ( ) const ( - GoogleClusterProvider = "gcp" - GoogleHomeDir = ".config/gcloud" - GooglePrefix = "gcp-credentials-" + GoogleClusterProvider = "gcp" + GoogleCredentialsPrefix = "gcp-credentials-" + GoogleHomeDir = ".config/gcloud" + + // List of APIs errors + apiErrorAlreadyExists = "alreadyExists" + apiErrorNotFound = "notFound" + gRPCErrorAlreadyExists = "AlreadyExists" + gRPCErrorPermissionDenied = "PermissionDenied" ) type GCPConfigure struct { @@ -35,6 +51,10 @@ func NewGCPConfigure(ctx context.Context, appCredentialsPath string) *GCPConfigu } func (gcp *GCPConfigure) ReadSACredentials() error { + if !util.IsExists(gcp.AppCredentialsPath, true) { + return fmt.Errorf("google application credentials JSON file for GCP not found") + } + data, err := os.ReadFile(gcp.AppCredentialsPath) if err != nil { return err @@ -58,40 +78,195 @@ func (gcp *GCPConfigure) CopySACredentials(fileSuffix string) error { return err } - gcp.AppCredentialsPath = util.GetHomePath(GoogleHomeDir, GooglePrefix+fileSuffix+".json") + gcp.AppCredentialsPath = util.GetHomePath(GoogleHomeDir, GoogleCredentialsPrefix+fileSuffix+".json") - return os.WriteFile(util.GetHomePath(GoogleHomeDir, GooglePrefix+fileSuffix+".json"), + return os.WriteFile(util.GetHomePath(GoogleHomeDir, GoogleCredentialsPrefix+fileSuffix+".json"), gcp.AppCredentials.JSON(), 0644) } -//func (gcp *GCPConfigure) CreateGateway() error { -// if err := gcp.ReadSACredentials(); err != nil { -// return err -// } -// -// client, err := compute.NewService(gcp.Ctx, option.WithAuthCredentials(gcp.AppCredentials)) -// if err != nil { -// return err -// } -// -// client.BasePath = compute.CloudPlatformScope + "/v1" -// -// fmt.Printf("%#v\n", *client) -// -// req := client.Routers.List(gcp.ProjectID, "europe-central2") -// if err := req.Pages(gcp.Ctx, func(page *compute.RouterList) error { -// for _, router := range page.Items { -// // process each `router` resource: -// fmt.Printf("%#v\n", router) -// // NAT Gateways are found in router.nats -// } -// return nil -// }); err != nil { -// log.Fatal(err) -// } -// -// return nil -//} +func (gcp *GCPConfigure) GetGCPSecrets(tenant string) (map[string][]byte, error) { + var secrets = make(map[string][]byte) + + if err := gcp.ReadSACredentials(); err != nil { + return nil, err + } + + client, err := secretmanager.NewClient(gcp.Ctx, option.WithCredentialsJSON(gcp.AppCredentials.JSON())) + if err != nil { + return nil, err + } + + defer client.Close() + + listReq := &secretmanagerpb.ListSecretsRequest{ + Parent: fmt.Sprintf("projects/%s", gcp.ProjectID), + Filter: "labels.resource-group=" + tenant + "-" + util.SopsRootName, + } + + it := client.ListSecrets(gcp.Ctx, listReq) + for { + resp, err := it.Next() + if errors.Is(err, iterator.Done) { + break + } + + if err != nil { + var respError *apierror.APIError + if errors.As(err, &respError) && respError.GRPCStatus().Code().String() == gRPCErrorPermissionDenied { + zap.S().Warnf("permission denied to list GCP secrets") + return nil, nil + } else { + return nil, err + } + } + + accReq := &secretmanagerpb.AccessSecretVersionRequest{Name: resp.Name + "/versions/latest"} + result, err := client.AccessSecretVersion(gcp.Ctx, accReq) + if err != nil { + var respError *apierror.APIError + if errors.As(err, &respError) && respError.GRPCStatus().Code().String() == gRPCErrorPermissionDenied { + zap.S().Warnf("permission denied to get access for GCP secrets values") + return nil, nil + } else { + return nil, err + } + } + + crc32c := crc32.MakeTable(crc32.Castagnoli) + checksum := int64(crc32.Checksum(result.Payload.Data, crc32c)) + if checksum != *result.Payload.DataCrc32C { + return nil, fmt.Errorf("data corruption detected for GCP secrets value: %s", resp.Name) + } + + secrets[filepath.Base(resp.Name)] = result.Payload.Data + } + + return secrets, nil +} + +func (gcp *GCPConfigure) SetGCPSecret(tenant, region, keyName string, value []byte) error { + if err := gcp.ReadSACredentials(); err != nil { + return err + } + + client, err := secretmanager.NewClient(gcp.Ctx, option.WithCredentialsJSON(gcp.AppCredentials.JSON())) + if err != nil { + return err + } + + defer client.Close() + + secretReq := &secretmanagerpb.CreateSecretRequest{ + Parent: fmt.Sprintf("projects/%s", gcp.ProjectID), + SecretId: keyName, + Secret: &secretmanagerpb.Secret{ + Replication: &secretmanagerpb.Replication{ + Replication: &secretmanagerpb.Replication_UserManaged_{ + UserManaged: &secretmanagerpb.Replication_UserManaged{ + Replicas: []*secretmanagerpb.Replication_UserManaged_Replica{{Location: region}}, + }, + }, + }, + Labels: map[string]string{"resource-group": tenant + "-" + util.SopsRootName}, + }, + } + + _, err = client.CreateSecret(gcp.Ctx, secretReq) + if err != nil { + var respError *apierror.APIError + if errors.As(err, &respError) && respError.GRPCStatus().Code().String() == gRPCErrorPermissionDenied { + zap.S().Warnf("permission denied to create GCP secret: %s", keyName) + } else if respError.GRPCStatus().Code().String() != gRPCErrorAlreadyExists { + return err + } + } + + secretVersionReq := &secretmanagerpb.AddSecretVersionRequest{ + Parent: fmt.Sprintf("projects/%s/secrets/%s", gcp.ProjectID, keyName), + Payload: &secretmanagerpb.SecretPayload{Data: value}, + } + + version, err := client.AddSecretVersion(gcp.Ctx, secretVersionReq) + if err != nil { + var respError *apierror.APIError + if errors.As(err, &respError) && respError.GRPCStatus().Code().String() == gRPCErrorPermissionDenied { + zap.S().Warnf("permission denied to add to secret %s value", keyName) + } else { + return err + } + } + + zap.S().Infof("created Azure key vault secret: %s, %s", keyName, version.Name) + + return nil +} + +func (gcp *GCPConfigure) CreateGCPCloudNATGateway(region string) error { + if err := gcp.ReadSACredentials(); err != nil { + return err + } + + client, err := compute.NewService(gcp.Ctx, option.WithCredentialsJSON(gcp.AppCredentials.JSON())) + if err != nil { + return err + } + + routerNat := &compute.RouterNat{ + AutoNetworkTier: "STANDARD", + EndpointTypes: []string{"ENDPOINT_TYPE_VM"}, + Name: "default-nat-" + region, + NatIpAllocateOption: "AUTO_ONLY", + SourceSubnetworkIpRangesToNat: "ALL_SUBNETWORKS_ALL_IP_RANGES", + Type: "PUBLIC", + } + + router := &compute.Router{ + Name: "default-router-" + region, + Nats: []*compute.RouterNat{routerNat}, + Network: "projects/" + gcp.ProjectID + "/global/networks/default", + } + + _, err = client.Routers.Insert(gcp.ProjectID, region, router).Context(gcp.Ctx).Do() + if err != nil { + var respError *googleapi.Error + if errors.As(err, &respError) && respError.Code == 409 && respError.Errors[0].Reason == apiErrorAlreadyExists { + zap.S().Infof("GCP router %s with router NAT %s already exists for region %s", + router.Name, routerNat.Name, region) + return nil + } + + return err + } + + zap.S().Infof("created GCP router %s with router NAT %s", router.Name, routerNat.Name) + + return nil +} + +func (gcp *GCPConfigure) DeleteGCPCloudNATGateway(region string) error { + if err := gcp.ReadSACredentials(); err != nil { + return err + } + + client, err := compute.NewService(gcp.Ctx, option.WithCredentialsJSON(gcp.AppCredentials.JSON())) + if err != nil { + return err + } + + _, err = client.Routers.Delete(gcp.ProjectID, region, "default-router-"+region).Context(gcp.Ctx).Do() + if err != nil { + var respError *googleapi.Error + if errors.As(err, &respError) && respError.Code == 404 && respError.Errors[0].Reason == apiErrorNotFound { + return nil + } + + return err + } + + zap.S().Infof("deleted GCP router %s for region %s", "default-router-"+region, region) + + return nil +} func (gcp *GCPConfigure) GetGCPClusterContext(clusterName string) ([]byte, error) { var cluster *container.Cluster @@ -100,7 +275,7 @@ func (gcp *GCPConfigure) GetGCPClusterContext(clusterName string) ([]byte, error return nil, err } - client, err := container.NewService(gcp.Ctx, option.WithAuthCredentials(gcp.AppCredentials)) + client, err := container.NewService(gcp.Ctx, option.WithCredentialsJSON(gcp.AppCredentials.JSON())) if err != nil { return nil, err }