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  }