Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional Authenticated Data AAD for Cloud KMS secrets #5968

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changelog/3271.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:enhancement
kms: Added new field "Additional Authenticated Data" for Cloud KMS data source `google_kms_secret`
```
```release-note:enhancement
kms: Added new field "Additional Authenticated Data" for Cloud KMS resource `google_kms_secret_ciphertext`
```
8 changes: 8 additions & 0 deletions google/data_source_google_kms_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func dataSourceGoogleKmsSecret() *schema.Resource {
Computed: true,
Sensitive: true,
},
"additional_authenticated_data": {
Type: schema.TypeString,
Optional: true,
},
},
}
}
Expand All @@ -46,6 +50,10 @@ func dataSourceGoogleKmsSecretRead(d *schema.ResourceData, meta interface{}) err
Ciphertext: ciphertext,
}

if aad, ok := d.GetOk("additional_authenticated_data"); ok {
kmsDecryptRequest.AdditionalAuthenticatedData = aad.(string)
}

decryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Decrypt(cryptoKeyId.cryptoKeyId(), kmsDecryptRequest).Do()

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion google/data_source_google_kms_secret_ciphertext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestAccDataKmsSecretCiphertext_basic(t *testing.T) {
{
Config: testGoogleKmsSecretCiphertext_datasource(kms.CryptoKey.Name, plaintext),
Check: func(s *terraform.State) error {
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "data.google_kms_secret_ciphertext.acceptance")
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "data.google_kms_secret_ciphertext.acceptance", "")

if err != nil {
return err
Expand Down
44 changes: 42 additions & 2 deletions google/data_source_google_kms_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestAccKmsSecret_basic(t *testing.T) {
cryptoKeyName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))

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

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

if err != nil {
return err
Expand All @@ -50,14 +51,39 @@ func TestAccKmsSecret_basic(t *testing.T) {
},
})

return nil
},
},
// With AAD
{
Config: testGoogleKmsCryptoKey_basic(projectId, projectOrg, projectBillingAccount, keyRingName, cryptoKeyName),
Check: func(s *terraform.State) error {
ciphertext, cryptoKeyId, err := testAccEncryptSecretDataWithCryptoKey(s, "google_kms_crypto_key.crypto_key", plaintext, aad)

if err != nil {
return err
}

// The second test asserts that the data source has the correct plaintext, given the created ciphertext
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testGoogleKmsSecret_aadDatasource(cryptoKeyId.terraformId(), ciphertext, base64.StdEncoding.EncodeToString([]byte(aad))),
Check: resource.TestCheckResourceAttr("data.google_kms_secret.acceptance", "plaintext", plaintext),
},
},
})

return nil
},
},
},
})
}

func testAccEncryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyResourceName, plaintext string) (string, *kmsCryptoKeyId, error) {
func testAccEncryptSecretDataWithCryptoKey(s *terraform.State, cryptoKeyResourceName, plaintext, aad string) (string, *kmsCryptoKeyId, error) {
config := testAccProvider.Meta().(*Config)

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

if aad != "" {
kmsEncryptRequest.AdditionalAuthenticatedData = base64.StdEncoding.EncodeToString([]byte(aad))
}

encryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Encrypt(cryptoKeyId.cryptoKeyId(), kmsEncryptRequest).Do()

if err != nil {
Expand All @@ -94,3 +124,13 @@ data "google_kms_secret" "acceptance" {
}
`, cryptoKeyTerraformId, ciphertext)
}

func testGoogleKmsSecret_aadDatasource(cryptoKeyTerraformId, ciphertext, aad string) string {
return fmt.Sprintf(`
data "google_kms_secret" "acceptance" {
crypto_key = "%s"
ciphertext = "%s"
additional_authenticated_data = "%s"
}
`, cryptoKeyTerraformId, ciphertext, aad)
}
21 changes: 21 additions & 0 deletions google/resource_kms_secret_ciphertext.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ Format: ''projects/{{project}}/locations/{{location}}/keyRings/{{keyRing}}/crypt
Description: `The plaintext to be encrypted.`,
Sensitive: true,
},
"additional_authenticated_data": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `The additional authenticated data used for integrity checks during encryption and decryption.`,
Sensitive: true,
},
"ciphertext": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -70,6 +77,12 @@ func resourceKMSSecretCiphertextCreate(d *schema.ResourceData, meta interface{})
} else if v, ok := d.GetOkExists("plaintext"); !isEmptyValue(reflect.ValueOf(plaintextProp)) && (ok || !reflect.DeepEqual(v, plaintextProp)) {
obj["plaintext"] = plaintextProp
}
additionalAuthenticatedDataProp, err := expandKMSSecretCiphertextAdditionalAuthenticatedData(d.Get("additional_authenticated_data"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("additional_authenticated_data"); !isEmptyValue(reflect.ValueOf(additionalAuthenticatedDataProp)) && (ok || !reflect.DeepEqual(v, additionalAuthenticatedDataProp)) {
obj["additionalAuthenticatedData"] = additionalAuthenticatedDataProp
}

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

func expandKMSSecretCiphertextAdditionalAuthenticatedData(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
if v == nil {
return nil, nil
}

return base64.StdEncoding.EncodeToString([]byte(v.(string))), nil
}

func resourceKMSSecretCiphertextDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) {
return res, nil
}
32 changes: 30 additions & 2 deletions google/resource_kms_secret_ciphertext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
kms := BootstrapKMSKey(t)

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

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -26,7 +27,20 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
{
Config: testGoogleKmsSecretCiphertext(kms.CryptoKey.Name, plaintext),
Check: func(s *terraform.State) error {
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance")
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance", "")

if err != nil {
return err
}

return resource.TestCheckResourceAttr("google_kms_secret_ciphertext.acceptance", "plaintext", plaintext)(s)
},
},
// With AAD
{
Config: testGoogleKmsSecretCiphertext_withAAD(kms.CryptoKey.Name, plaintext, aad),
Check: func(s *terraform.State) error {
plaintext, err := testAccDecryptSecretDataWithCryptoKey(s, kms.CryptoKey.Name, "google_kms_secret_ciphertext.acceptance", aad)

if err != nil {
return err
Expand All @@ -39,7 +53,7 @@ func TestAccKmsSecretCiphertext_basic(t *testing.T) {
})
}

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

if aad != "" {
kmsDecryptRequest.AdditionalAuthenticatedData = base64.StdEncoding.EncodeToString([]byte(aad))
}

decryptResponse, err := config.clientKms.Projects.Locations.KeyRings.CryptoKeys.Decrypt(cryptoKeyId, kmsDecryptRequest).Do()

if err != nil {
Expand All @@ -80,3 +98,13 @@ resource "google_kms_secret_ciphertext" "acceptance" {
}
`, cryptoKeyTerraformId, plaintext)
}

func testGoogleKmsSecretCiphertext_withAAD(cryptoKeyTerraformId, plaintext, aad string) string {
return fmt.Sprintf(`
resource "google_kms_secret_ciphertext" "acceptance" {
crypto_key = "%s"
plaintext = "%s"
additional_authenticated_data = "%s"
}
`, cryptoKeyTerraformId, plaintext, aad)
}
1 change: 1 addition & 0 deletions website/docs/d/google_kms_secret.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ The following arguments are supported:
* `crypto_key` (Required) - The id of the CryptoKey that will be used to
decrypt the provided ciphertext. This is represented by the format
`{projectId}/{location}/{keyRingName}/{cryptoKeyName}`.
* `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.

## Attributes Reference

Expand Down
4 changes: 4 additions & 0 deletions website/docs/r/kms_secret_ciphertext.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ The following arguments are supported:
- - -


* `additional_authenticated_data` -
(Optional)
The additional authenticated data used for integrity checks during encryption and decryption.


## Attributes Reference

Expand Down