Skip to content

Commit

Permalink
#29 - implement support GCP secrets manager for store SOPS Age keys
Browse files Browse the repository at this point in the history
  • Loading branch information
apanasiuk-el committed Dec 16, 2024
1 parent 92ed29e commit 81db188
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 75 deletions.
15 changes: 9 additions & 6 deletions cmd/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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(
Expand Down
48 changes: 44 additions & 4 deletions cmd/cluster_capg.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion cmd/cluster_capz.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 20 additions & 2 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}
}
Expand Down
9 changes: 9 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
5 changes: 4 additions & 1 deletion cmd/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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,
)
}
Expand Down
35 changes: 35 additions & 0 deletions cmd/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
52 changes: 26 additions & 26 deletions providers/azure_provider/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
}
Loading

0 comments on commit 81db188

Please sign in to comment.