package secret import ( "context" "encoding/base64" "fmt" "net/url" "os" "google.golang.org/api/option" secretmanager "google.golang.org/api/secretmanager/v1" ) type gcpSecretManagerProvider struct { options *providerOptions projectID string } // GCPSecretManager is a provider for Google Cloud Secret Manager. // // Authentication must be supplied using `opts`. // // To use an API key: // // provider, err := GCPSecretManager(projectID, WithAPIKey("AI...")) // // To use credentials JSON: // // provider, err := GCPSecretManager(projectID, WithCredentials("path/to/creds.json")) // // Alternatively, the following environment variables may be used: // - GOOGLE_CLOUD_CREDENTIALS containing a path to the credentials JSON file // - GOOGLE_CLOUD_CREDENTIALS_JSON containing the credentials JSON func GCPSecretManager(projectID string, opts ...Option) (Provider, error) { var options = new(providerOptions) for _, opt := range opts { opt(options) } return &gcpSecretManagerProvider{ options: options, projectID: projectID, }, nil } func (p *gcpSecretManagerProvider) GetSecret(key string) (value []byte, err error) { ctx := context.Background() if p.options.timeout > 0 { var cancel func() ctx, cancel = context.WithTimeout(ctx, p.options.timeout) defer cancel() } var opts []option.ClientOption if p.options.apiKey != "" { opts = append(opts, option.WithAPIKey(p.options.apiKey)) } else if p.options.credentials != "" { opts = append(opts, option.WithCredentialsFile(p.options.credentials)) } else if v := os.Getenv("GOOGLE_CLOUD_CREDENTIALS"); v != "" { opts = append(opts, option.WithCredentialsFile(v)) } else if v := os.Getenv("GOOGLE_CLOUD_CREDENTIALS_JSON"); v != "" { opts = append(opts, option.WithCredentialsJSON([]byte(v))) } else { // Calling the service without authentication will fail... opts = append(opts, option.WithoutAuthentication()) } var service *secretmanager.Service if service, err = secretmanager.NewService(ctx, opts...); err != nil { return } resource := fmt.Sprintf("projects/%s/secrets/%s/versions/latest", url.PathEscape(p.projectID), url.PathEscape(key)) var response *secretmanager.AccessSecretVersionResponse if response, err = service.Projects.Secrets.Versions.Access(resource).Do(); err != nil { return } return base64.StdEncoding.DecodeString(response.Payload.Data) }