diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..cb13f72 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,18 @@ +## Descrição + + +## Motivação e contexto + + +## Testes + + +## Tipo de mudança + + +- [ ] Correção de bug +- [ ] Nova funcionalidade +- [ ] Melhorias na implementação +- [ ] Atualização de dependências +- [ ] Testes automatizados +- [ ] Documentação \ No newline at end of file diff --git a/.gitignore b/.gitignore index ebfc9df..cf57f8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ secrets-init dist/ *credentials* +.idea diff --git a/README.md b/README.md index ca6c14e..babf862 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is a simple CLI that reads secrets from Secrets Manager. It's a perfect "in ## CLI ```sh -./secrets-init \ +./secrets-init sync \ --provider YOUR_CLOUD_PROVIDER \ --project YOUR_PROJECT_ID \ --filter YOUR_FILTER \ @@ -29,7 +29,7 @@ Given a secret called `myapp` with the content below: Running secrets-init with the flags: ```bash -./secrets-init \ +./secrets-init sync \ --provider gcp \ --project myproject \ --filter=^myapp*" \ diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..1d32dc8 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,63 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +type rootCmd struct { + cmd *cobra.Command +} + +type data struct { + version string + commit string + date string +} + +func (r *rootCmd) execute() { + if err := r.cmd.Execute(); err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func newRootCmd(data *data) *rootCmd { + root := &rootCmd{} + cmd := &cobra.Command{ + Version: data.version, + Use: "secret-init", + Short: "Read external secrets from some providers", + Long: ` +This is a simple CLI that reads secrets from Secrets Manager, like: + - AWS + - GCP +It's a perfect "init" container in Kubernetes. +it can create a file on a shared volume so the other containers can use that file. +secrets-init can filter one or more secrets by name using a regular expression. +it also parses the secret content as plain text or json. + `, + SilenceUsage: true, + SilenceErrors: true, + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + } + + cmd.AddCommand( + newSyncCmd(data).cmd, + newVersionCmd(data).cmd, + ) + root.cmd = cmd + return root +} + +func Execute(version, commit, date string) { + newRootCmd(&data{ + version: version, + commit: commit, + date: date, + }).execute() + +} diff --git a/cmd/sync.go b/cmd/sync.go new file mode 100644 index 0000000..5a242a9 --- /dev/null +++ b/cmd/sync.go @@ -0,0 +1,59 @@ +package cmd + +import ( + "fmt" + "github.com/leocomelli/secrets-init/internal/secrets" + "github.com/leocomelli/secrets-init/pkg/provider/common" + "github.com/spf13/cobra" + "go.uber.org/zap" + "os" +) + +type syncCmd struct { + cmd *cobra.Command +} + +func (r *syncCmd) execute() { + if err := r.cmd.Execute(); err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func newSyncCmd(data *data) *syncCmd { + sync := &syncCmd{} + secretOpts := &common.SecretsOpts{} + + cmd := &cobra.Command{ + Version: data.version, + Use: "sync", + Aliases: []string{"s"}, + Short: "Sync external secrets to a container init", + SilenceUsage: true, + SilenceErrors: true, + Args: cobra.NoArgs, + ValidArgsFunction: cobra.NoFileCompletions, + RunE: func(cmd *cobra.Command, args []string) error { + + fetch, err := secrets.New(secretOpts) + if err != nil { + common.Logger.Fatal("error getting the secrets", zap.Error(err)) + return err + } + + return fetch.Secrets() + }, + } + + sync.cmd = cmd + + sync.cmd.Flags().StringVarP(&secretOpts.Provider, "provider", "e", "gcp", "name of the provider that manages the secrets") + sync.cmd.Flags().StringVarP(&secretOpts.AssumeRole, "assume-role", "a", "", "role to assume when using aws provider") + sync.cmd.Flags().StringVarP(&secretOpts.Project, "project", "p", "", "gcp project that contains the secrets") + sync.cmd.Flags().StringVarP(&secretOpts.Filter, "filter", "f", "", "regex to filter secrets by name") + sync.cmd.Flags().StringVarP(&secretOpts.Parser, "data-parser", "d", "plaintext", "parse secret based on data type") + sync.cmd.Flags().StringVarP(&secretOpts.Template, "template", "t", "", "template to render secret data") + sync.cmd.Flags().StringVarP(&secretOpts.Output, "output", "o", "", "path to write output file to") + + return sync +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..8ebaaa0 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,36 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "os" +) + +type versionCmd struct { + cmd *cobra.Command +} + +func (r *versionCmd) execute() { + if err := r.cmd.Execute(); err != nil { + _, _ = fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func newVersionCmd(data *data) *versionCmd { + sync := &versionCmd{} + cmd := &cobra.Command{ + Version: data.version, + Use: "version", + Aliases: []string{"v"}, + Short: "Return the current version of secret init", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Build Date:", data.date) + fmt.Println("Git Commit:", data.commit) + fmt.Println("Version:", data.version) + }, + } + + sync.cmd = cmd + return sync +} diff --git a/go.mod b/go.mod index 1c73bec..53417ba 100644 --- a/go.mod +++ b/go.mod @@ -3,49 +3,54 @@ module github.com/leocomelli/secrets-init go 1.19 require ( - cloud.google.com/go/secretmanager v1.11.1 - github.com/aws/aws-sdk-go-v2 v1.19.1 - github.com/aws/aws-sdk-go-v2/config v1.18.15 - github.com/aws/aws-sdk-go-v2/credentials v1.13.15 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.7 - github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 + cloud.google.com/go/secretmanager v1.11.4 + github.com/aws/aws-sdk-go-v2 v1.23.5 + github.com/aws/aws-sdk-go-v2/config v1.25.11 + github.com/aws/aws-sdk-go-v2/credentials v1.16.9 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.2 + github.com/aws/aws-sdk-go-v2/service/sts v1.26.2 + github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 go.uber.org/zap v1.26.0 - google.golang.org/api v0.126.0 - google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc + google.golang.org/api v0.152.0 + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 ) require ( - cloud.google.com/go/compute v1.19.3 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.0 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 // indirect - github.com/aws/smithy-go v1.13.5 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2 // indirect + github.com/aws/smithy-go v1.18.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-cmp v0.5.9 // indirect - github.com/google/s2a-go v0.1.4 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.11.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/oauth2 v0.14.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect - google.golang.org/grpc v1.55.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4eec02a..b33b9c4 100644 --- a/go.sum +++ b/go.sum @@ -1,67 +1,53 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= -cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/secretmanager v1.11.1 h1:cLTCwAjFh9fKvU6F13Y4L9vPcx9yiWPyWXE4+zkuEQs= -cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/secretmanager v1.11.4 h1:krnX9qpG2kR2fJ+u+uNyNo+ACVhplIAS4Pu7u+4gd+k= +cloud.google.com/go/secretmanager v1.11.4/go.mod h1:wreJlbS9Zdq21lMzWmJ0XhWW2ZxgPeahsqeV/vZoJ3w= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aws/aws-sdk-go-v2 v1.17.5/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.17.6/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.19.1 h1:STs0lbbpXu3byTPcnRLghs2DH0yk9qKDo27TyyJSKsM= -github.com/aws/aws-sdk-go-v2 v1.19.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.15 h1:509yMO0pJUGUugBP2H9FOFyV+7Mz7sRR+snfDN5W4NY= -github.com/aws/aws-sdk-go-v2/config v1.18.15/go.mod h1:vS0tddZqpE8cD9CyW0/kITHF5Bq2QasW9Y1DFHD//O0= -github.com/aws/aws-sdk-go-v2/credentials v1.13.15 h1:0rZQIi6deJFjOEgHI9HI2eZcLPPEGQPictX66oRFLL8= -github.com/aws/aws-sdk-go-v2/credentials v1.13.15/go.mod h1:vRMLMD3/rXU+o6j2MW5YefrGMBmdTvkLLGqFwMLBHQc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23 h1:Kbiv9PGnQfG/imNI4L/heyUXvzKmcWSBeDvkrQz5pFc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.23/go.mod h1:mOtmAg65GT1HIL/HT/PynwPbS+UG0BgCZ6vhkPqnxWo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.29/go.mod h1:Dip3sIGv485+xerzVv24emnjX5Sg88utCL8fwGmCeWg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30 h1:y+8n9AGDjikyXoMBTRaHHHSaFEB8267ykmvyPodJfys= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.30/go.mod h1:LUBAO3zNXQjoONBKn/kR1y0Q4cj/D02Ts0uHYjcCQLM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.23/go.mod h1:mr6c4cHC+S/MMkrjtSlG4QA36kOznDep+0fga5L/fGQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24 h1:r+Kv+SEJquhAZXaJ7G4u44cIwXV3f8K+N482NNAzJZA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.24/go.mod h1:gAuCezX/gob6BSMbItsSlMb6WZGV7K2+fWOvk8xBSto= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30 h1:IVx9L7YFhpPq0tTnGo8u8TpluFu7nAn9X3sUDMb11c0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.30/go.mod h1:vsbq62AOBwQ1LJ/GWKFxX8beUEYeRp/Agitrxee2/qM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.23/go.mod h1:9uPh+Hrz2Vn6oMnQYiUi/zbh3ovbnQk19YKINkQny44= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24 h1:c5qGfdbCHav6viBwiyDns3OXqhqAbGjfIB4uVu2ayhk= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.24/go.mod h1:HMA4FZG6fyib+NDo5bpIxX1EhYjrAOveZJY2YR0xrNE= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.7 h1:lo/d9eXqIGN4PR5xwBKWad5O2rGJ2/ghdEk+HkfW870= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.18.7/go.mod h1:CJcdJtrO6ulXfI8l2DotKWmJShhXHCEcd9Wibyx3kC0= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.4 h1:qJdM48OOLl1FBSzI7ZrA1ZfLwOyCYqkXV5lko1hYDBw= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.4/go.mod h1:jtLIhd+V+lft6ktxpItycqHqiVXrPIRjWIsFIlzMriw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4 h1:YRkWXQveFb0tFC0TLktmmhGsOcCgLwvq88MC2al47AA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.4/go.mod h1:zVwRrfdSmbRZWkUkWjOItY7SOalnFnq/Yg2LVPqDjwc= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.5/go.mod h1:1mKZHLLpDMHTNSYPJ7qrcnCQdHCWsNQaT0xRvq2u80s= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.6 h1:rIFn5J3yDoeuKCE9sESXqM5POTAhOP1du3bv/qTL+tE= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.6/go.mod h1:48WJ9l3dwP0GSHWGc5sFGGlCkuA82Mc2xnw+T6Q8aDw= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.23.5 h1:xK6C4udTyDMd82RFvNkDQxtAd00xlzFUtX4fF2nMZyg= +github.com/aws/aws-sdk-go-v2 v1.23.5/go.mod h1:t3szzKfP0NeRU27uBFczDivYJjsmSnqI8kIvKyWb9ds= +github.com/aws/aws-sdk-go-v2/config v1.25.11 h1:RWzp7jhPRliIcACefGkKp03L0Yofmd2p8M25kbiyvno= +github.com/aws/aws-sdk-go-v2/config v1.25.11/go.mod h1:BVUs0chMdygHsQtvaMyEOpW2GIW+ubrxJLgIz/JU29s= +github.com/aws/aws-sdk-go-v2/credentials v1.16.9 h1:LQo3MUIOzod9JdUK+wxmSdgzLVYUbII3jXn3S/HJZU0= +github.com/aws/aws-sdk-go-v2/credentials v1.16.9/go.mod h1:R7mDuIJoCjH6TxGUc/cylE7Lp/o0bhKVoxdBThsjqCM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 h1:FZVFahMyZle6WcogZCOxo6D/lkDA2lqKIn4/ueUmVXw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9/go.mod h1:kjq7REMIkxdtcEC9/4BVXjOsNY5isz6jQbEgk6osRTU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 h1:8GVZIR0y6JRIUNSYI1xAMF4HDfV8H/bOsZ/8AD/uY5Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8/go.mod h1:rwBfu0SoUkBUZndVgPZKAD9Y2JigaZtRP68unRiYToQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 h1:ZE2ds/qeBkhk3yqYvS3CDCFNvd9ir5hMjlVStLZWrvM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8/go.mod h1:/lAPPymDYL023+TS6DJmjuL42nxix2AvEvfjqOBRODk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 h1:e3PCNeEaev/ZF01cQyNZgmYE9oYYePIMJs2mWSKG514= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3/go.mod h1:gIeeNyaL8tIEqZrzAnTeyhHcE0yysCtcaP+N9kxLZ+E= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 h1:EamsKe+ZjkOQjDdHd86/JCEucjFKQ9T0atWKO4s2Lgs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8/go.mod h1:Q0vV3/csTpbkfKLI5Sb56cJQTCTtJ0ixdb7P+Wedqiw= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.2 h1:JKbfiLwEqJp8zaOAOn6AVSMS96gdwP3TjBMvZYsbxqE= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.2/go.mod h1:pbBOMK8UicdDK11zsPSGbpFh9Xwbd1oD3t7pSxXgNxU= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.2 h1:xJPydhNm0Hiqct5TVKEuHG7weC0+sOs4MUnd7A5n5F4= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.2/go.mod h1:zxk6y1X2KXThESWMS5CrKRvISD8mbIMab6nZrCGxDG0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2 h1:8dU9zqA77C5egbU6yd4hFLaiIdPv3rU+6cp7sz5FjCU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2/go.mod h1:7Lt5mjQ8x5rVdKqg+sKKDeuwoszDJIIPmkd8BVsEdS0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.2 h1:fFrLsy08wEbAisqW3KDl/cPHrF43GmV79zXB9EwJiZw= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.2/go.mod h1:7Ld9eTqocTvJqqJ5K/orbSDwmGcpRdlDiLjz2DO+SL8= +github.com/aws/smithy-go v1.18.1 h1:pOdBTUfXNazOlxLrgeYalVnuTpKreACHtc62xLwIB3c= +github.com/aws/smithy-go v1.18.1/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -70,17 +56,14 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -90,37 +73,34 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= -github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -128,98 +108,70 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= -google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -231,13 +183,10 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/secrets/no-parser.go b/internal/secrets/no-parser.go new file mode 100644 index 0000000..941a138 --- /dev/null +++ b/internal/secrets/no-parser.go @@ -0,0 +1,20 @@ +package secrets + +import ( + "github.com/leocomelli/secrets-init/pkg/provider/common" +) + +// NoParser represents no parser +type NoParser struct { + Tmpl string +} + +// Name returns the strategy name +func (n *NoParser) Name() string { + return "plaintext" +} + +// Parse puts the secret data in a slice +func (n *NoParser) Parse(s *common.SecretData) []*common.SecretData { + return []*common.SecretData{s} +} diff --git a/internal/secrets/options.go b/internal/secrets/options.go new file mode 100644 index 0000000..a140e26 --- /dev/null +++ b/internal/secrets/options.go @@ -0,0 +1,41 @@ +package secrets + +import ( + "github.com/leocomelli/secrets-init/pkg/provider" + "github.com/leocomelli/secrets-init/pkg/provider/common" + "go.uber.org/zap" +) + +// ContentParser defines secret content parser behaviors +type ContentParser interface { + Parse(*common.SecretData) []*common.SecretData + Name() string +} + +var ( + logger, _ = zap.NewProduction() + + providers = map[string]provider.SecretProvider{ + "gcp": &provider.GCPSecretManager{}, + "aws": &provider.AWSSecretManager{}, + } + + templates = map[string]string{ + "plaintext": `export {{ .Name | ToUpper }}="{{ .Data }}"`, + "json": `export {{ .Name | ToUpper }}_{{ .ContentKey | ToUpper }}="{{ .ContentValue }}"`, + } + + parsers = map[string]ContentParser{ + "plaintext": &NoParser{}, + "json": &JSONContentParser{}, + } + + tmplLoop = `{{ range . }} +%s +{{- end -}} +` +) + +const ( + AssumeRoleKey = "assume-role" +) diff --git a/internal/secrets/parser.go b/internal/secrets/parser.go new file mode 100644 index 0000000..6f08500 --- /dev/null +++ b/internal/secrets/parser.go @@ -0,0 +1,54 @@ +package secrets + +import ( + "encoding/json" + "fmt" + "github.com/leocomelli/secrets-init/pkg/provider/common" + "go.uber.org/zap" +) + +// JSONContenParser represents a JSON parser +type JSONContentParser struct { + Tmpl string +} + +// Name returns the strategy name +func (j *JSONContentParser) Name() string { + return "json" +} + +/* +Parse lists each json entry as a secret +Consider a secret called myscret with the content below + + { + "user": "root", + "password": "s3cr3t", + "host" : "127.0.0.1:5432", + } + +# The following secrets will be returned + + myscret_user: root + mysecret_password: s3cr3t + mysecret_host: 127.0.0.1:5432 +*/ +func (j *JSONContentParser) Parse(s *common.SecretData) []*common.SecretData { + m := map[string]interface{}{} + if err := json.Unmarshal([]byte(s.Data), &m); err != nil { + logger.Warn("invalid json", zap.String("name", s.Name)) + } + + secrets := make([]*common.SecretData, 0, len(m)) + for k, v := range m { + secrets = append(secrets, &common.SecretData{ + Name: s.Name, + Path: s.Path, + Data: s.Data, + ContentKey: k, + ContentValue: fmt.Sprintf("%v", v), + }) + } + + return secrets +} diff --git a/parser_test.go b/internal/secrets/parser_test.go similarity index 89% rename from parser_test.go rename to internal/secrets/parser_test.go index 4fdb893..9161dc3 100644 --- a/parser_test.go +++ b/internal/secrets/parser_test.go @@ -1,6 +1,7 @@ -package main +package secrets import ( + "github.com/leocomelli/secrets-init/pkg/provider/common" "sort" "testing" @@ -9,22 +10,22 @@ import ( func TestJSONParser(t *testing.T) { - expected := []*SecretData{ - &SecretData{ + expected := []*common.SecretData{ + { Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, ContentKey: "host", ContentValue: "localhost:5432", }, - &SecretData{ + { Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, ContentKey: "password", ContentValue: "s3cr3t", }, - &SecretData{ + { Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, @@ -33,7 +34,7 @@ func TestJSONParser(t *testing.T) { }, } - s := &SecretData{ + s := &common.SecretData{ Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, @@ -55,8 +56,8 @@ func TestJSONParser(t *testing.T) { func TestNoParser(t *testing.T) { - expected := []*SecretData{ - &SecretData{ + expected := []*common.SecretData{ + { Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, @@ -65,7 +66,7 @@ func TestNoParser(t *testing.T) { }, } - s := &SecretData{ + s := &common.SecretData{ Path: "/project/123/secrets/mysecret", Name: "mysecret", Data: `{"user": "myuser", "password": "s3cr3t", "host": "localhost:5432"}`, diff --git a/internal/secrets/secrets.go b/internal/secrets/secrets.go new file mode 100644 index 0000000..638453e --- /dev/null +++ b/internal/secrets/secrets.go @@ -0,0 +1,112 @@ +package secrets + +import ( + "errors" + "github.com/leocomelli/secrets-init/pkg/provider" + "github.com/leocomelli/secrets-init/pkg/provider/common" + "go.uber.org/zap" + "os" +) + +var ( + ErrProjectNotFound = errors.New("project is required") + ErrUnsupportedProvider = errors.New("unsupported provider") + ErrUnsupportedParser = errors.New("unsupported parser") +) + +// Sync has the responsibility to synchronize external secret at container initialization +type Sync struct { + provider provider.SecretProvider + parser ContentParser + template string + params map[string]string + project string + filter string + output string +} + +// Secrets return a secrets based on a set of parameters +func (s *Sync) Secrets() error { + + logger.Info("start synchronize secrets with options", + zap.String("provider", s.provider.Name()), + zap.String("project", s.project), + zap.String("filter", s.filter), + zap.String("parser", s.parser.Name()), + zap.String("template", s.template), + zap.String("output", s.output), + ) + + if err := s.provider.Init(s.params); err != nil { + return err + } + + data, err := s.provider.ListSecrets(s.project, s.filter) + if err != nil { + return err + } + + logger.Info("secrets found", zap.Int("len", len(data))) + + output := os.Stdin + if s.output != "" { + output, err = os.Create(s.output) + if err != nil { + return err + } + } + + w, err := NewWriter(output, s.template) + if err != nil { + return err + } + + for _, v := range data { + e := s.parser.Parse(v) + err := w.Write(e...) + if err != nil { + return err + } + } + + logger.Info("finish synchronize secrets", + zap.String("template", s.template), + zap.String("output", s.output), + ) + + return nil +} + +// New set secret options based on parameters +func New(options *common.SecretsOpts) (*Sync, error) { + external, ok := providers[options.Provider] + if !ok { + return nil, ErrUnsupportedProvider + } + + if external.Name() == "gcp" && options.Project == "" { + return nil, ErrProjectNotFound + } + + parser, ok := parsers[options.Parser] + if !ok { + return nil, ErrUnsupportedParser + } + + template := templates[options.Parser] + if options.Template != "" { + template = options.Template + } + + return &Sync{ + params: map[string]string{ + AssumeRoleKey: options.AssumeRole, + }, + project: options.Project, + filter: options.Filter, + output: options.Output, + template: template, + provider: external, + parser: parser, + }, nil +} diff --git a/writer.go b/internal/secrets/writer.go similarity index 83% rename from writer.go rename to internal/secrets/writer.go index 85f770c..e46ccc7 100644 --- a/writer.go +++ b/internal/secrets/writer.go @@ -1,7 +1,8 @@ -package main +package secrets import ( "fmt" + "github.com/leocomelli/secrets-init/pkg/provider/common" "io" "strings" "text/template" @@ -34,6 +35,6 @@ func NewWriter(wr io.Writer, tmpl string) (*Writer, error) { } // Write writes the secrets in a file -func (w *Writer) Write(s ...*SecretData) error { +func (w *Writer) Write(s ...*common.SecretData) error { return w.Tmpl.Execute(w.Writer, s) } diff --git a/main.go b/main.go index b99e47b..6edc477 100644 --- a/main.go +++ b/main.go @@ -1,80 +1,22 @@ package main import ( - "flag" - "fmt" - - "go.uber.org/zap" + "github.com/leocomelli/secrets-init/cmd" ) var ( - logger, _ = zap.NewProduction() - - providers = map[string]SecretProvider{ - "gcp": &GCPSecretManager{}, - "aws": &AWSSecretManager{}, - } - - templates = map[string]string{ - "plaintext": `export {{ .Name | ToUpper }}="{{ .Data }}"`, - "json": `export {{ .Name | ToUpper }}_{{ .ContentKey | ToUpper }}="{{ .ContentValue }}"`, - } - - parsers = map[string]ContentParser{ - "plaintext": &NoParser{}, - "json": &JSONContentParser{}, - } + // The git commit that was compiled. These will be filled in by the compiler. + GitCommit string - tmplLoop = `{{ range . }} -%s -{{- end -}} -` -) + // The main version number that is being run at the moment. + Version string -const ( - AssumeRoleKey = "assume-role" + // BuildDate contains the date and time of build process. + BuildDate string ) -// Options represents the command line options -type Options struct { - Provider string - AssumeRole string - Project string - Filter string - Parser string - Template string - Output string -} - -func (o *Options) String() string { - return fmt.Sprintf( - "provider: %s, project: %s, filter: %s, parser: %s, template: %s, output: %s", - o.Provider, o.Project, o.Filter, o.Parser, o.Template, o.Output, - ) -} - func main() { - - options := &Options{} - - flag.StringVar(&options.Provider, "provider", "gcp", "name of the provider that manages the secrets") - flag.StringVar(&options.AssumeRole, "assume-role", "", "role to assume when using aws provider") - flag.StringVar(&options.Project, "project", "", "gcp project that contains the secrets") - flag.StringVar(&options.Filter, "filter", "", "regex to filter secrets by name") - flag.StringVar(&options.Parser, "data-parser", "plaintext", "parse secret based on data type") - flag.StringVar(&options.Template, "template", "", "template to render secret data") - flag.StringVar(&options.Output, "output", "", "path to write output file to") - v := flag.Bool("version", false, "show the current secrets-init version") - - flag.Parse() - - if *v { - GetHumanVersion() - return - } - - err := Run(options) - if err != nil { - logger.Fatal("error getting the secrets", zap.Error(err)) - } + cmd.Execute( + Version, GitCommit, BuildDate, + ) } diff --git a/parser.go b/parser.go deleted file mode 100644 index f3e2feb..0000000 --- a/parser.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - "go.uber.org/zap" -) - -// ContentParser defines secret content parser behaviors -type ContentParser interface { - Parse(*SecretData) []*SecretData -} - -// JSONContenParser represents a JSON parser -type JSONContentParser struct { - Tmpl string -} - -// Parse lists each json entry as a secret -// -// Consider a secret called myscret with the content below -// -// { -// "user": "root", -// "password": "s3cr3t", -// "host" : "127.0.0.1:5432", -// } -// -// The following secrets will be returned -// -// myscret_user: root -// mysecret_password: s3cr3t -// mysecret_host: 127.0.0.1:5432 -func (j *JSONContentParser) Parse(s *SecretData) []*SecretData { - m := map[string]interface{}{} - if err := json.Unmarshal([]byte(s.Data), &m); err != nil { - logger.Warn("invalid json", zap.String("name", s.Name)) - } - - var secrets []*SecretData - for k, v := range m { - secrets = append(secrets, &SecretData{Name: s.Name, Path: s.Path, Data: s.Data, ContentKey: k, ContentValue: fmt.Sprintf("%v", v)}) - } - - return secrets -} - -// NoParser represents no parser -type NoParser struct { - Tmpl string -} - -// Parse puts the secret data in a slice -func (n *NoParser) Parse(s *SecretData) []*SecretData { - return []*SecretData{s} -} diff --git a/aws.go b/pkg/provider/aws.go similarity index 92% rename from aws.go rename to pkg/provider/aws.go index fed86af..2f32733 100644 --- a/aws.go +++ b/pkg/provider/aws.go @@ -1,7 +1,8 @@ -package main +package provider import ( "context" + "github.com/leocomelli/secrets-init/pkg/provider/common" "strconv" "time" @@ -42,7 +43,7 @@ func (s *AWSSecretManager) Init(params map[string]string) error { return err } - if role, ok := params[AssumeRoleKey]; ok && role != "" { + if role, ok := params[common.AssumeRoleKey]; ok && role != "" { cfg, err = s.AssumeRole(cfg, role) if err != nil { return err @@ -83,9 +84,9 @@ func (s *AWSSecretManager) AssumeRole(cfg aws.Config, role string) (aws.Config, // ListSecrets lists the AWS Secrets using external configurations. // Use prefix to filter the secrets starting with a term. // If prefix is empty, all secrets are listed. -func (s *AWSSecretManager) ListSecrets(_ string, prefix string) ([]*SecretData, error) { +func (s *AWSSecretManager) ListSecrets(_ string, prefix string) ([]*common.SecretData, error) { var ( - data []*SecretData + data []*common.SecretData token string ) @@ -113,7 +114,7 @@ func (s *AWSSecretManager) ListSecrets(_ string, prefix string) ([]*SecretData, continue } - data = append(data, &SecretData{ + data = append(data, &common.SecretData{ Path: name, Name: name, Data: aws.ToString(resp.SecretString), diff --git a/pkg/provider/common/types.go b/pkg/provider/common/types.go new file mode 100644 index 0000000..8616e23 --- /dev/null +++ b/pkg/provider/common/types.go @@ -0,0 +1,26 @@ +package common + +// SecretData represents a secret thta is store in a given Secret Manager provider +type SecretData struct { + Path string + Name string + Data string + ContentKey string + ContentValue string +} + +// SecretsOpts represents the command line options +type SecretsOpts struct { + Provider string + AssumeRole string + Project string + Filter string + Parser string + Template string + Output string +} + +const ( + // AssumeRoleKey can be use as a key to map assume role + AssumeRoleKey = "assume-role" +) diff --git a/gcp.go b/pkg/provider/gcp.go similarity index 90% rename from gcp.go rename to pkg/provider/gcp.go index 1f822e3..16193a3 100644 --- a/gcp.go +++ b/pkg/provider/gcp.go @@ -1,9 +1,10 @@ -package main +package provider // nolint:staticcheck import ( "context" "fmt" + "github.com/leocomelli/secrets-init/pkg/provider/common" "path" secretmanager "cloud.google.com/go/secretmanager/apiv1" @@ -44,13 +45,13 @@ func (s *GCPSecretManager) Init(_ map[string]string) error { // Use prefix to filter the secrets starting with a term. // If prefix is empty, all secrets are listed. // nolint:staticcheck -func (s *GCPSecretManager) ListSecrets(project string, prefix string) ([]*SecretData, error) { +func (s *GCPSecretManager) ListSecrets(project string, prefix string) ([]*common.SecretData, error) { req := &secretmanagerpb.ListSecretsRequest{ Parent: fmt.Sprintf("projects/%s", project), } it := s.client.ListSecrets(context.Background(), req) - var data []*SecretData + var data []*common.SecretData for { resp, err := it.Next() @@ -69,7 +70,7 @@ func (s *GCPSecretManager) ListSecrets(project string, prefix string) ([]*Secret return nil, err } - data = append(data, &SecretData{ + data = append(data, &common.SecretData{ Path: resp.GetName(), Name: name, Data: string(content.Payload.Data), diff --git a/provider.go b/pkg/provider/provider.go similarity index 62% rename from provider.go rename to pkg/provider/provider.go index 321e4ff..a978010 100644 --- a/provider.go +++ b/pkg/provider/provider.go @@ -1,13 +1,21 @@ -package main +package provider -import "regexp" +import ( + "github.com/leocomelli/secrets-init/pkg/provider/common" + "go.uber.org/zap" + "regexp" +) + +var ( + logger, _ = zap.NewProduction() +) // SecretProvider defines the behaviors for a secret provider type SecretProvider interface { Name() string Init(map[string]string) error Filter(string, string) bool - ListSecrets(string, string) ([]*SecretData, error) + ListSecrets(string, string) ([]*common.SecretData, error) } type GenericProvider struct{} diff --git a/provider_test.go b/pkg/provider/provider_test.go similarity index 96% rename from provider_test.go rename to pkg/provider/provider_test.go index 79b5fc0..2a49a37 100644 --- a/provider_test.go +++ b/pkg/provider/provider_test.go @@ -1,4 +1,4 @@ -package main +package provider import ( "testing" diff --git a/runner.go b/runner.go deleted file mode 100644 index 28eb3ba..0000000 --- a/runner.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "errors" - "os" - - "go.uber.org/zap" -) - -var ( - ErrProjectNotFound = errors.New("project is required") - ErrUnsupportedProvider = errors.New("unsupported provider") - ErrUnsupportedParser = errors.New("unsupported parser") -) - -func Run(options *Options) error { - provider, ok := providers[options.Provider] - if !ok { - return ErrUnsupportedProvider - } - - if provider.Name() == "gcp" && options.Project == "" { - return ErrProjectNotFound - } - - parser, ok := parsers[options.Parser] - if !ok { - return ErrUnsupportedParser - } - - template := templates[options.Parser] - if options.Template != "" { - template = options.Template - } - - logger.Info("using options", zap.Any("values", options)) - - params := map[string]string{ - AssumeRoleKey: options.AssumeRole, - } - - if err := provider.Init(params); err != nil { - return err - } - - data, err := provider.ListSecrets(options.Project, options.Filter) - if err != nil { - return err - } - - logger.Info("secrets found", zap.Int("len", len(data))) - - output := os.Stdin - if options.Output != "" { - output, err = os.Create(options.Output) - if err != nil { - return err - } - } - - w, err := NewWriter(output, template) - if err != nil { - return err - } - - for _, v := range data { - e := parser.Parse(v) - err := w.Write(e...) - if err != nil { - return err - } - } - - return nil -} diff --git a/runner_test.go b/runner_test.go deleted file mode 100644 index 893ae83..0000000 --- a/runner_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package main - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -type MockProvider struct { - GenericProvider -} - -func (m *MockProvider) Name() string { - return "mock" -} - -func (m *MockProvider) Init(_ map[string]string) error { - return nil -} - -func (m *MockProvider) ListSecrets(project string, prefix string) ([]*SecretData, error) { - return []*SecretData{ - &SecretData{ - Path: "/project/123/secrets/mysecret", - Name: "mysecret", - Data: "s3cr3t", - }, - }, nil -} - -func TestUnsupportedProvider(t *testing.T) { - opts := &Options{ - Provider: "unsupported", - Project: "my-project", - Parser: "json", - } - - err := Run(opts) - assert.Equal(t, ErrUnsupportedProvider, err) -} - -func TestUnsupportedParser(t *testing.T) { - opts := &Options{ - Provider: "gcp", - Project: "my-project", - Parser: "unsupported", - } - - err := Run(opts) - assert.Equal(t, ErrUnsupportedParser, err) -} - -func TestGCPProjectNotFound(t *testing.T) { - opts := &Options{Provider: "gcp"} - err := Run(opts) - assert.Equal(t, ErrProjectNotFound, err) -} - -func TestHappyPath(t *testing.T) { - providers["mock"] = &MockProvider{} - - file, err := os.CreateTemp("", "test") - if err != nil { - panic(err) - } - defer os.Remove(file.Name()) - - opts := &Options{ - Provider: "mock", - Project: "my-project", - Parser: "plaintext", - Output: file.Name(), - } - - err = Run(opts) - if err != nil { - panic(err) - } - - content, err := os.ReadFile(file.Name()) - if err != nil { - panic(err) - } - - expected := ` -export MYSECRET="s3cr3t"` - - assert.Equal(t, expected, string(content)) -} diff --git a/secret.go b/secret.go deleted file mode 100644 index 71167c1..0000000 --- a/secret.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -// SecretData represents a secret thta is store in a given Secret Manager provider -type SecretData struct { - Path string - Name string - Data string - ContentKey string - ContentValue string -} diff --git a/version.go b/version.go deleted file mode 100644 index 14e1c1d..0000000 --- a/version.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "fmt" -) - -var ( - // The git commit that was compiled. These will be filled in by the compiler. - GitCommit string - - // The main version number that is being run at the moment. - Version string - - // BuildDate contains the date and time of build process. - BuildDate string -) - -// GetHumanVersion composes the parts of the version in a way that's suitable -// for displaying to humans. -func GetHumanVersion() { - fmt.Printf("secrets-init %s, commit %s, built at %s", Version, GitCommit, BuildDate) -} diff --git a/writer_test.go b/writer_test.go deleted file mode 100644 index 9005a99..0000000 --- a/writer_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "bytes" - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestWriteToStdin(t *testing.T) { - var buf bytes.Buffer - - w, err := NewWriter(&buf, templates["plaintext"]) - assert.Nil(t, err) - - s := []*SecretData{ - &SecretData{ - Path: "secrets/mysecret", - Name: "mysecret_user", - Data: "root", - }, - &SecretData{ - Path: "secrets/mysecret", - Name: "mysecret_password", - Data: "s3cr3t", - }, - } - - _ = w.Write(s...) - - expected := ` -export MYSECRET_USER="root" -export MYSECRET_PASSWORD="s3cr3t"` - - assert.Equal(t, expected, buf.String()) -} - -func TestWriteToFile(t *testing.T) { - file, err := os.CreateTemp("", "test") - - if err != nil { - panic(err) - } - defer os.Remove(file.Name()) - - w, err := NewWriter(file, templates["plaintext"]) - assert.Nil(t, err) - - s := []*SecretData{ - &SecretData{ - Path: "secrets/mysecret", - Name: "mysecret_user", - Data: "root", - }, - &SecretData{ - Path: "secrets/mysecret", - Name: "mysecret_password", - Data: "s3cr3t", - }, - } - - _ = w.Write(s...) - - content, err := os.ReadFile(file.Name()) - if err != nil { - panic(err) - } - - expected := ` -export MYSECRET_USER="root" -export MYSECRET_PASSWORD="s3cr3t"` - - assert.Equal(t, expected, string(content)) -}