Skip to content

Commit d3065ce

Browse files
Additional Authenticated Data AAD for Cloud KMS secrets (#3271) (#1886)
* AAD for KMS secrets * add test for decryption * update datasource docs for google_kms_secret (decrypt) * add test for encryption with aad Signed-off-by: Modular Magician <[email protected]>
1 parent c1eeb70 commit d3065ce

8 files changed

+113
-5
lines changed

.changelog/3271.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
```release-note:enhancement
2+
kms: Added new field "Additional Authenticated Data" for Cloud KMS data source `google_kms_secret`
3+
```
4+
```release-note:enhancement
5+
kms: Added new field "Additional Authenticated Data" for Cloud KMS resource `google_kms_secret_ciphertext`
6+
```

google-beta/data_source_google_kms_secret.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ func dataSourceGoogleKmsSecret() *schema.Resource {
2727
Computed: true,
2828
Sensitive: true,
2929
},
30+
"additional_authenticated_data": {
31+
Type: schema.TypeString,
32+
Optional: true,
33+
},
3034
},
3135
}
3236
}
@@ -46,6 +50,10 @@ func dataSourceGoogleKmsSecretRead(d *schema.ResourceData, meta interface{}) err
4650
Ciphertext: ciphertext,
4751
}
4852

53+
if aad, ok := d.GetOk("additional_authenticated_data"); ok {
54+
kmsDecryptRequest.AdditionalAuthenticatedData = aad.(string)
55+
}
56+
4957
decryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Decrypt(cryptoKeyId.cryptoKeyId(), kmsDecryptRequest).Do()
5058

5159
if err != nil {

google-beta/data_source_google_kms_secret_ciphertext_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestAccDataKmsSecretCiphertext_basic(t *testing.T) {
2323
{
2424
Config: testGoogleKmsSecretCiphertext_datasource(kms.CryptoKey.Name, plaintext),
2525
Check: func(s *terraform.State) error {
26-
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "data.google_kms_secret_ciphertext.acceptance")
26+
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "data.google_kms_secret_ciphertext.acceptance", "")
2727

2828
if err != nil {
2929
return err

google-beta/data_source_google_kms_secret_test.go

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func TestAccKmsSecret_basic(t *testing.T) {
2323
cryptoKeyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
2424

2525
plaintext := fmt.Sprintf("secret-%s", acctest.RandString(10))
26+
aad := "plainaad"
2627

2728
// The first test creates resources needed to encrypt plaintext and produce ciphertext
2829
resource.Test(t, resource.TestCase{
@@ -32,7 +33,7 @@ func TestAccKmsSecret_basic(t *testing.T) {
3233
{
3334
Config: testGoogleKmsCryptoKey_basic(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName),
3435
Check: func(s *terraform.State) error {
35-
ciphertext, cryptoKeyId, err := testAccEncryptSecretDataWithCryptoKey(s, "google_kms_crypto_key.crypto_key", plaintext)
36+
ciphertext, cryptoKeyId, err := testAccEncryptSecretDataWithCryptoKey(s, "google_kms_crypto_key.crypto_key", plaintext, "")
3637

3738
if err != nil {
3839
return err
@@ -50,14 +51,39 @@ func TestAccKmsSecret_basic(t *testing.T) {
5051
},
5152
})
5253

54+
return nil
55+
},
56+
},
57+
// With AAD
58+
{
59+
Config: testGoogleKmsCryptoKey_basic(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName),
60+
Check: func(s *terraform.State) error {
61+
ciphertext, cryptoKeyId, err := testAccEncryptSecretDataWithCryptoKey(s, "google_kms_crypto_key.crypto_key", plaintext, aad)
62+
63+
if err != nil {
64+
return err
65+
}
66+
67+
// The second test asserts that the data source has the correct plaintext, given the created ciphertext
68+
resource.Test(t, resource.TestCase{
69+
PreCheck: func() { testAccPreCheck(t) },
70+
Providers: testAccProviders,
71+
Steps: []resource.TestStep{
72+
{
73+
Config: testGoogleKmsSecret_aadDatasource(cryptoKeyId.terraformId(), ciphertext, base64.StdEncoding.EncodeToString([]byte(aad))),
74+
Check: resource.TestCheckResourceAttr("data.google_kms_secret.acceptance", "plaintext", plaintext),
75+
},
76+
},
77+
})
78+
5379
return nil
5480
},
5581
},
5682
},
5783
})
5884
}
5985

60-
func testAccEncryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyResourceName, plaintext string) (string, *kmsCryptoKeyId, error) {
86+
func testAccEncryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyResourceName, plaintext, aad string) (string, *kmsCryptoKeyId, error) {
6187
config := testAccProvider.Meta().(*Config)
6288

6389
rs, ok := s.RootModule().Resources[cryptoKeyResourceName]
@@ -75,6 +101,10 @@ func testAccEncryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyResource
75101
Plaintext: base64.StdEncoding.EncodeToString([]byte(plaintext)),
76102
}
77103

104+
if aad != "" {
105+
kmsEncryptRequest.AdditionalAuthenticatedData = base64.StdEncoding.EncodeToString([]byte(aad))
106+
}
107+
78108
encryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Encrypt(cryptoKeyId.cryptoKeyId(), kmsEncryptRequest).Do()
79109

80110
if err != nil {
@@ -94,3 +124,13 @@ data "google_kms_secret" "acceptance" {
94124
}
95125
`, cryptoKeyTerraformId, ciphertext)
96126
}
127+
128+
func testGoogleKmsSecret_aadDatasource(cryptoKeyTerraformId, ciphertext, aad string) string {
129+
return fmt.Sprintf(`
130+
data "google_kms_secret" "acceptance" {
131+
crypto_key = "%s"
132+
ciphertext = "%s"
133+
additional_authenticated_data = "%s"
134+
}
135+
`, cryptoKeyTerraformId, ciphertext, aad)
136+
}

google-beta/resource_kms_secret_ciphertext.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ Format: ''projects/{{project}}/locations/{{location}}/keyRings/{{keyRing}}/crypt
5151
Description: `The plaintext to be encrypted.`,
5252
Sensitive: true,
5353
},
54+
"additional_authenticated_data": {
55+
Type: schema.TypeString,
56+
Optional: true,
57+
ForceNew: true,
58+
Description: `The additional authenticated data used for integrity checks during encryption and decryption.`,
59+
Sensitive: true,
60+
},
5461
"ciphertext": {
5562
Type: schema.TypeString,
5663
Computed: true,
@@ -70,6 +77,12 @@ func resourceKMSSecretCiphertextCreate(d *schema.ResourceData, meta interface{})
7077
} else if v, ok := d.GetOkExists("plaintext"); !isEmptyValue(reflect.ValueOf(plaintextProp)) && (ok || !reflect.DeepEqual(v, plaintextProp)) {
7178
obj["plaintext"] = plaintextProp
7279
}
80+
additionalAuthenticatedDataProp, err := expandKMSSecretCiphertextAdditionalAuthenticatedData(d.Get("additional_authenticated_data"), d, config)
81+
if err != nil {
82+
return err
83+
} else if v, ok := d.GetOkExists("additional_authenticated_data"); !isEmptyValue(reflect.ValueOf(additionalAuthenticatedDataProp)) && (ok || !reflect.DeepEqual(v, additionalAuthenticatedDataProp)) {
84+
obj["additionalAuthenticatedData"] = additionalAuthenticatedDataProp
85+
}
7386

7487
url, err := replaceVars(d, config, "{{KMSBasePath}}{{crypto_key}}:encrypt")
7588
if err != nil {
@@ -160,6 +173,14 @@ func expandKMSSecretCiphertextPlaintext(v interface{}, d TerraformResourceData,
160173
return base64.StdEncoding.EncodeToString([]byte(v.(string))), nil
161174
}
162175

176+
func expandKMSSecretCiphertextAdditionalAuthenticatedData(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
177+
if v == nil {
178+
return nil, nil
179+
}
180+
181+
return base64.StdEncoding.EncodeToString([]byte(v.(string))), nil
182+
}
183+
163184
func resourceKMSSecretCiphertextDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
164185
return res, nil
165186
}

google-beta/resource_kms_secret_ciphertext_test.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
1818
kms := BootstrapKMSKey(t)
1919

2020
plaintext := fmt.Sprintf("secret-%s", acctest.RandString(10))
21+
aad := "plainaad"
2122

2223
resource.Test(t, resource.TestCase{
2324
PreCheck: func() { testAccPreCheck(t) },
@@ -26,7 +27,20 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
2627
{
2728
Config: testGoogleKmsSecretCiphertext(kms.CryptoKey.Name, plaintext),
2829
Check: func(s *terraform.State) error {
29-
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance")
30+
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance", "")
31+
32+
if err != nil {
33+
return err
34+
}
35+
36+
return resource.TestCheckResourceAttr("google_kms_secret_ciphertext.acceptance", "plaintext", plaintext)(s)
37+
},
38+
},
39+
// With AAD
40+
{
41+
Config: testGoogleKmsSecretCiphertext_withAAD(kms.CryptoKey.Name, plaintext, aad),
42+
Check: func(s *terraform.State) error {
43+
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance", aad)
3044

3145
if err != nil {
3246
return err
@@ -39,7 +53,7 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
3953
})
4054
}
4155

42-
func testAccDecryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyId string, secretCiphertextResourceName string) (string, error) {
56+
func testAccDecryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyId string, secretCiphertextResourceName, aad string) (string, error) {
4357
config := testAccProvider.Meta().(*Config)
4458
rs, ok := s.RootModule().Resources[secretCiphertextResourceName]
4559
if !ok {
@@ -54,6 +68,10 @@ func testAccDecryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyId strin
5468
Ciphertext: ciphertext,
5569
}
5670

71+
if aad != "" {
72+
kmsDecryptRequest.AdditionalAuthenticatedData = base64.StdEncoding.EncodeToString([]byte(aad))
73+
}
74+
5775
decryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Decrypt(cryptoKeyId, kmsDecryptRequest).Do()
5876

5977
if err != nil {
@@ -80,3 +98,13 @@ resource "google_kms_secret_ciphertext" "acceptance" {
8098
}
8199
`, cryptoKeyTerraformId, plaintext)
82100
}
101+
102+
func testGoogleKmsSecretCiphertext_withAAD(cryptoKeyTerraformId, plaintext, aad string) string {
103+
return fmt.Sprintf(`
104+
resource "google_kms_secret_ciphertext" "acceptance" {
105+
crypto_key = "%s"
106+
plaintext = "%s"
107+
additional_authenticated_data = "%s"
108+
}
109+
`, cryptoKeyTerraformId, plaintext, aad)
110+
}

website/docs/d/google_kms_secret.html.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ The following arguments are supported:
9090
* `crypto_key` (Required) - The id of the CryptoKey that will be used to
9191
decrypt the provided ciphertext. This is represented by the format
9292
`{projectId}/{location}/{keyRingName}/{cryptoKeyName}`.
93+
* `additional_authenticated_data` (Optional) - The [additional authenticated data](https://cloud.google.com/kms/docs/additional-authenticated-data) used for integrity checks during encryption and decryption.
9394

9495
## Attributes Reference
9596

website/docs/r/kms_secret_ciphertext.html.markdown

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ The following arguments are supported:
103103
- - -
104104

105105

106+
* `additional_authenticated_data` -
107+
(Optional)
108+
The additional authenticated data used for integrity checks during encryption and decryption.
109+
106110

107111
## Attributes Reference
108112

0 commit comments

Comments
 (0)