diff --git a/internal/services/containers/container_group_resource.go b/internal/services/containers/container_group_resource.go index d2ee3e359477..824573fa1eb1 100644 --- a/internal/services/containers/container_group_resource.go +++ b/internal/services/containers/container_group_resource.go @@ -18,6 +18,8 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/parse" + keyVaultParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" + keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" networkParse "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" networkValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" @@ -460,6 +462,13 @@ func resourceContainerGroup() *pluginsdk.Resource { }, }, }, + + "key_vault_key_id": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: keyVaultValidate.NestedItemId, + }, }, } } @@ -663,6 +672,18 @@ func resourceContainerGroupCreate(d *pluginsdk.ResourceData, meta interface{}) e } } + if keyVaultKeyId := d.Get("key_vault_key_id").(string); keyVaultKeyId != "" { + keyId, err := keyVaultParse.ParseOptionallyVersionedNestedItemID(keyVaultKeyId) + if err != nil { + return fmt.Errorf("parsing Key Vault Key ID: %+v", err) + } + containerGroup.ContainerGroupProperties.EncryptionProperties = &containerinstance.EncryptionProperties{ + VaultBaseURL: utils.String(keyId.KeyVaultBaseUrl), + KeyName: utils.String(keyId.Name), + KeyVersion: utils.String(keyId.Version), + } + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, containerGroup) if err != nil { return fmt.Errorf("creating/updating %s: %+v", id, err) @@ -766,6 +787,28 @@ func resourceContainerGroupRead(d *pluginsdk.ResourceData, meta interface{}) err if err := d.Set("diagnostics", flattenContainerGroupDiagnostics(d, props.Diagnostics)); err != nil { return fmt.Errorf("setting `diagnostics`: %+v", err) } + + if kvProps := props.EncryptionProperties; kvProps != nil { + var keyVaultUri, keyName, keyVersion string + if kvProps.VaultBaseURL != nil && *kvProps.VaultBaseURL != "" { + keyVaultUri = *kvProps.VaultBaseURL + } else { + return fmt.Errorf("empty value returned for Key Vault URI") + } + if kvProps.KeyName != nil && *kvProps.KeyName != "" { + keyName = *kvProps.KeyName + } else { + return fmt.Errorf("empty value returned for Key Vault Key Name") + } + if kvProps.KeyVersion != nil { + keyVersion = *kvProps.KeyVersion + } + keyId, err := keyVaultParse.NewNestedItemID(keyVaultUri, "keys", keyName, keyVersion) + if err != nil { + return err + } + d.Set("key_vault_key_id", keyId.ID()) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/internal/services/containers/container_group_resource_test.go b/internal/services/containers/container_group_resource_test.go index e9c79d87b0cf..66303793ee0b 100644 --- a/internal/services/containers/container_group_resource_test.go +++ b/internal/services/containers/container_group_resource_test.go @@ -640,6 +640,21 @@ func TestAccContainerGroup_secretVolume(t *testing.T) { }) } +func TestAccContainerGroup_encryption(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_group", "test") + r := ContainerGroupResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.encryption(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (ContainerGroupResource) SystemAssignedIdentity(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -2212,3 +2227,101 @@ resource "azurerm_container_group" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (ContainerGroupResource) encryption(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +data "azurerm_client_config" "current" {} + +resource "azurerm_key_vault" "test" { + name = "acc-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" +} + +resource "azurerm_key_vault_access_policy" "terraform" { + key_vault_id = azurerm_key_vault.test.id + key_permissions = [ + "Create", + "Delete", + "Get", + "List", + "Purge", + "Update", + ] + + secret_permissions = [ + "Get", + "Delete", + "Set", + ] + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id +} + +resource "azurerm_key_vault_key" "test" { + name = "key-%[1]d" + key_vault_id = azurerm_key_vault.test.id + key_type = "RSA" + key_size = 2048 + + key_opts = [ + "decrypt", + "encrypt", + "sign", + "unwrapKey", + "verify", + "wrapKey", + ] + depends_on = [azurerm_key_vault_access_policy.terraform] +} + +data "azuread_service_principal" "test" { + display_name = "Azure Container Instance Service" +} + +resource "azurerm_key_vault_access_policy" "test" { + key_vault_id = azurerm_key_vault.test.id + key_permissions = [ + "Get", + "UnwrapKey", + "WrapKey" + ] + + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azuread_service_principal.test.object_id + depends_on = [azurerm_key_vault_access_policy.terraform] +} + +resource "azurerm_container_group" "test" { + name = "acctestcontainergroup-%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + ip_address_type = "Public" + os_type = "Linux" + + container { + name = "hw" + image = "ubuntu:20.04" + cpu = "0.5" + memory = "0.5" + ports { + port = 80 + protocol = "TCP" + } + } + key_vault_key_id = azurerm_key_vault_key.test.id + depends_on = [azurerm_key_vault_access_policy.test] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index 6bf9f254e777..029f3da11cdc 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -90,6 +90,8 @@ The following arguments are supported: ~> **Note:** `dns_name_label` and `os_type` set to `windows` are not compatible with `Private` `ip_address_type` +* `key_vault_key_id` - (Optional) The Key Vault key URI for CMK encryption. Changing this forces a new resource to be created. + * `network_profile_id` - (Optional) Network profile ID for deploying to virtual network. * `image_registry_credential` - (Optional) A `image_registry_credential` block as documented below. Changing this forces a new resource to be created.