go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers-sdk/v1/vault/gcpsecretmanager/secretmanager.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package gcpsecretmanager 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "strings" 11 12 secretmanager "cloud.google.com/go/secretmanager/apiv1" 13 "go.mondoo.com/cnquery/providers-sdk/v1/vault" 14 "go.mondoo.com/cnquery/utils/multierr" 15 secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" 16 ) 17 18 var notImplemented = errors.New("not implemented") 19 20 // https://cloud.google.com/secret-manager 21 // https://cloud.google.com/secret-manager/docs/reference/libraries#client-libraries-install-go 22 func New(projectID string) *Vault { 23 return &Vault{ 24 projectID: projectID, 25 } 26 } 27 28 type Vault struct { 29 projectID string 30 } 31 32 func (v *Vault) About(context.Context, *vault.Empty) (*vault.VaultInfo, error) { 33 return &vault.VaultInfo{Name: "GCP Secret Manager: " + v.projectID}, nil 34 } 35 36 // Dial gets a Vault client. 37 func (v *Vault) client(ctx context.Context) (*secretmanager.Client, error) { 38 client, err := secretmanager.NewClient(ctx) 39 if err != nil { 40 return nil, multierr.Wrap(err, "failed to setup gcp secret manager client") 41 } 42 return client, nil 43 } 44 45 // we need to remove the leading // from mrns, this should not be done here, therefore we just throw an error 46 func validKey(key string) error { 47 if strings.HasPrefix(key, "/") { 48 return errors.New("leading / are not allowed") 49 } 50 return nil 51 } 52 53 // gcp does not support / in strings which we heavily use 54 // 😤 secret names can only contain english letters (A-Z), numbers (0-9), dashes (-), and underscores (_) 55 // therefore we cannot use url encode and we need to fallback to an unsafe mechanism where we may 56 // run into issues of two keys matching the same value, lets not maintain a mapping table for now 57 // since we do not allow "list" a one-way transformation is okay for now 58 func gcpKeyID(key string) string { 59 gcpKey := strings.ReplaceAll(key, "/", "-") 60 gcpKey = strings.ReplaceAll(gcpKey, ".", "-") 61 return gcpKey 62 } 63 64 func (v *Vault) Get(ctx context.Context, id *vault.SecretID) (*vault.Secret, error) { 65 err := validKey(id.Key) 66 if err != nil { 67 return nil, err 68 } 69 70 c, err := v.client(ctx) 71 if err != nil { 72 return nil, err 73 } 74 75 // retrieve secret metadata 76 result, err := c.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ 77 Name: fmt.Sprintf("projects/%s/secrets/%s/versions/latest", v.projectID, gcpKeyID(id.Key)), 78 }) 79 if err != nil { 80 return nil, vault.NotFoundError 81 } 82 83 return &vault.Secret{ 84 Key: id.Key, 85 Data: result.Payload.Data, 86 }, nil 87 } 88 89 func (v *Vault) Set(ctx context.Context, cred *vault.Secret) (*vault.SecretID, error) { 90 return nil, errors.New("not implemented") 91 }