github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/gcp_kms/provider.go (about)

     1  package gcp_kms
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  
     7  	"cloud.google.com/go/kms/apiv1/kmspb"
     8  	"github.com/googleapis/gax-go/v2"
     9  	"github.com/opentofu/opentofu/internal/encryption/keyprovider"
    10  )
    11  
    12  type keyMeta struct {
    13  	Ciphertext []byte `json:"ciphertext"`
    14  }
    15  
    16  func (m keyMeta) isPresent() bool {
    17  	return len(m.Ciphertext) != 0
    18  }
    19  
    20  type keyManagementClient interface {
    21  	Encrypt(ctx context.Context, req *kmspb.EncryptRequest, opts ...gax.CallOption) (*kmspb.EncryptResponse, error)
    22  	Decrypt(ctx context.Context, req *kmspb.DecryptRequest, opts ...gax.CallOption) (*kmspb.DecryptResponse, error)
    23  }
    24  
    25  type keyProvider struct {
    26  	svc       keyManagementClient
    27  	ctx       context.Context
    28  	keyName   string
    29  	keyLength int
    30  }
    31  
    32  func (p keyProvider) Provide(rawMeta keyprovider.KeyMeta) (keyprovider.Output, keyprovider.KeyMeta, error) {
    33  	if rawMeta == nil {
    34  		return keyprovider.Output{}, nil, &keyprovider.ErrInvalidMetadata{Message: "bug: no metadata struct provided"}
    35  	}
    36  	inMeta, ok := rawMeta.(*keyMeta)
    37  	if !ok {
    38  		return keyprovider.Output{}, nil, &keyprovider.ErrInvalidMetadata{Message: "bug: invalid metadata struct type"}
    39  	}
    40  
    41  	outMeta := &keyMeta{}
    42  	out := keyprovider.Output{}
    43  
    44  	// Generate new key
    45  	out.EncryptionKey = make([]byte, p.keyLength)
    46  	_, err := rand.Read(out.EncryptionKey)
    47  	if err != nil {
    48  		return out, outMeta, &keyprovider.ErrKeyProviderFailure{
    49  			Message: "failed to generate key",
    50  			Cause:   err,
    51  		}
    52  	}
    53  
    54  	// Encrypt new encryption key using kms
    55  	encryptedKeyData, err := p.svc.Encrypt(p.ctx, &kmspb.EncryptRequest{
    56  		Name:      p.keyName,
    57  		Plaintext: out.EncryptionKey,
    58  	})
    59  	if err != nil {
    60  		return out, outMeta, &keyprovider.ErrKeyProviderFailure{
    61  			Message: "failed to encrypt key",
    62  			Cause:   err,
    63  		}
    64  	}
    65  
    66  	outMeta.Ciphertext = encryptedKeyData.Ciphertext
    67  
    68  	// We do not set the DecryptionKey here as we should only be setting the decryption key if we are decrypting
    69  	// and that is handled below when we check if the inMeta has a CiphertextBlob
    70  
    71  	if inMeta.isPresent() {
    72  		// We have an existing decryption key to decrypt, so we should now populate the DecryptionKey
    73  		decryptedKeyData, decryptErr := p.svc.Decrypt(p.ctx, &kmspb.DecryptRequest{
    74  			Name:       p.keyName,
    75  			Ciphertext: inMeta.Ciphertext,
    76  		})
    77  
    78  		if decryptErr != nil {
    79  			return out, outMeta, decryptErr
    80  		}
    81  
    82  		// Set decryption key on the output
    83  		out.DecryptionKey = decryptedKeyData.Plaintext
    84  	}
    85  
    86  	return out, outMeta, nil
    87  }