github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/openbao/client.go (about) 1 package openbao 2 3 import ( 4 "context" 5 "encoding/base64" 6 "errors" 7 "fmt" 8 "net/url" 9 "path" 10 11 openbao "github.com/openbao/openbao/api" 12 ) 13 14 type client interface { 15 WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*openbao.Secret, error) 16 } 17 18 // service implements missing utility functions from openbao/api such as routing and serialization. 19 type service struct { 20 c client 21 transitPath string 22 } 23 24 type dataKey struct { 25 Plaintext []byte 26 Ciphertext []byte 27 } 28 29 func (s service) generateDataKey(ctx context.Context, keyName string, bitSize int) (dataKey, error) { 30 path := path.Join(s.transitPath, "datakey/plaintext", url.PathEscape(keyName)) 31 32 secret, err := s.c.WriteWithContext(ctx, path, map[string]interface{}{ 33 "bits": bitSize, 34 }) 35 if err != nil { 36 return dataKey{}, fmt.Errorf("error sending datakey request to OpenBao: %w", err) 37 } 38 39 key := dataKey{} 40 41 key.Ciphertext, err = retrieveCiphertext(secret) 42 if err != nil { 43 return dataKey{}, err 44 } 45 46 key.Plaintext, err = retrievePlaintext(secret) 47 if err != nil { 48 return dataKey{}, err 49 } 50 51 return key, nil 52 } 53 54 func (s service) decryptData(ctx context.Context, keyName string, ciphertext []byte) ([]byte, error) { 55 path := path.Join(s.transitPath, "decrypt", url.PathEscape(keyName)) 56 57 secret, err := s.c.WriteWithContext(ctx, path, map[string]interface{}{ 58 "ciphertext": string(ciphertext), 59 }) 60 if err != nil { 61 return nil, fmt.Errorf("error sending decryption request to OpenBao: %w", err) 62 } 63 64 return retrievePlaintext(secret) 65 } 66 67 func retrievePlaintext(s *openbao.Secret) ([]byte, error) { 68 base64Plaintext, ok := s.Data["plaintext"].(string) 69 if !ok { 70 return nil, errors.New("failed to deserialize 'plaintext' (it's either OpenTofu bug or incompatible OpenBao version)") 71 } 72 73 plaintext, err := base64.StdEncoding.DecodeString(base64Plaintext) 74 if err != nil { 75 return nil, fmt.Errorf("base64 decoding 'plaintext' (it's either OpenTofu bug or incompatible OpenBao version): %w", err) 76 } 77 78 return plaintext, nil 79 } 80 81 func retrieveCiphertext(s *openbao.Secret) ([]byte, error) { 82 ciphertext, ok := s.Data["ciphertext"].(string) 83 if !ok { 84 return nil, errors.New("failed to deserialize 'ciphertext' (it's either OpenTofu bug or incompatible OpenBao version)") 85 } 86 87 return []byte(ciphertext), nil 88 }