From 0ee32ee573f10ecf746072309f5d5e5cf0c0a80b Mon Sep 17 00:00:00 2001 From: magodo Date: Wed, 20 Sep 2023 15:12:53 +0800 Subject: [PATCH 1/2] `azurerm_container_group` - Supports CMK with user assigned identity --- .../containers/container_group_resource.go | 16 +++ .../container_group_resource_test.go | 121 ++++++++++++++++++ website/docs/r/container_group.html.markdown | 2 + 3 files changed, 139 insertions(+) diff --git a/internal/services/containers/container_group_resource.go b/internal/services/containers/container_group_resource.go index d3b2fcb8aed9..7661c25eb746 100644 --- a/internal/services/containers/container_group_resource.go +++ b/internal/services/containers/container_group_resource.go @@ -553,6 +553,12 @@ func resourceContainerGroup() *pluginsdk.Resource { ForceNew: true, ValidateFunc: keyVaultValidate.NestedItemId, }, + + "key_vault_user_identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: commonids.ValidateUserAssignedIdentityID, + }, }, } } @@ -777,6 +783,10 @@ func resourceContainerGroupCreate(d *pluginsdk.ResourceData, meta interface{}) e KeyName: keyId.Name, KeyVersion: keyId.Version, } + + if keyVaultUAI := d.Get("key_vault_user_identity_id").(string); keyVaultUAI != "" { + containerGroup.Properties.EncryptionProperties.Identity = &keyVaultUAI + } } // Avoid parallel provisioning if "subnet_ids" are given. @@ -942,6 +952,12 @@ func resourceContainerGroupRead(d *pluginsdk.ResourceData, meta interface{}) err return err } d.Set("key_vault_key_id", keyId.ID()) + + var uai string + if kvProps.Identity != nil { + uai = *kvProps.Identity + } + d.Set("key_vault_user_identity_id", uai) } } diff --git a/internal/services/containers/container_group_resource_test.go b/internal/services/containers/container_group_resource_test.go index 671a180f4fda..a864907da629 100644 --- a/internal/services/containers/container_group_resource_test.go +++ b/internal/services/containers/container_group_resource_test.go @@ -695,6 +695,21 @@ func TestAccContainerGroup_encryption(t *testing.T) { }) } +func TestAccContainerGroup_encryptionWithUserAssignedIdentity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_group", "test") + r := ContainerGroupResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.encryptionWithUserAssignedIdentity(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccContainerGroup_securityContext(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_container_group", "test") r := ContainerGroupResource{} @@ -2489,6 +2504,112 @@ resource "azurerm_container_group" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } +func (ContainerGroupResource) encryptionWithUserAssignedIdentity(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", + "GetRotationPolicy", + ] + + 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] +} + +resource "azurerm_user_assigned_identity" "test" { + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + name = "uai-%[1]d" +} + +resource "azurerm_key_vault_access_policy" "test" { + key_vault_id = azurerm_key_vault.test.id + key_permissions = [ + "Get", + "UnwrapKey", + "WrapKey", + "GetRotationPolicy", + ] + tenant_id = azurerm_user_assigned_identity.test.tenant_id + object_id = azurerm_user_assigned_identity.test.principal_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 + key_vault_user_identity_id = azurerm_user_assigned_identity.test.id + identity { + type = "UserAssigned" + identity_ids = [azurerm_user_assigned_identity.test.id] + } + depends_on = [azurerm_key_vault_access_policy.test] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} + func (ContainerGroupResource) securityContextPriviledged(data acceptance.TestData, v bool) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index db1d29cc7841..32180b72b6ac 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -99,6 +99,8 @@ The following arguments are supported: * `key_vault_key_id` - (Optional) The Key Vault key URI for CMK encryption. Changing this forces a new resource to be created. +* `key_vault_user_identity_id` - (Optional) The user assigned identity that has access to the Key Vault Key. If not specified, the RP principal named "Azure Container Instance Service" will be used instead. Make sure the identity has the proper `key_permissions` set, at least with `Get`, `UnwrapKey`, `WrapKey` and `GetRotationPolicy`. + * `subnet_ids` - (Optional) The subnet resource IDs for a container group. Changing this forces a new resource to be created. * `image_registry_credential` - (Optional) An `image_registry_credential` block as documented below. Changing this forces a new resource to be created. From e069a7c66c1522561fb204a1d7931626ea1dcb64 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 21 Sep 2023 09:32:25 +0800 Subject: [PATCH 2/2] Renaming & minor clean up --- .../services/containers/container_group_resource.go | 11 +++-------- .../containers/container_group_resource_test.go | 4 ++-- website/docs/r/container_group.html.markdown | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/internal/services/containers/container_group_resource.go b/internal/services/containers/container_group_resource.go index 7661c25eb746..ca0cfcbae8cf 100644 --- a/internal/services/containers/container_group_resource.go +++ b/internal/services/containers/container_group_resource.go @@ -554,7 +554,7 @@ func resourceContainerGroup() *pluginsdk.Resource { ValidateFunc: keyVaultValidate.NestedItemId, }, - "key_vault_user_identity_id": { + "key_vault_user_assigned_identity_id": { Type: pluginsdk.TypeString, Optional: true, ValidateFunc: commonids.ValidateUserAssignedIdentityID, @@ -784,7 +784,7 @@ func resourceContainerGroupCreate(d *pluginsdk.ResourceData, meta interface{}) e KeyVersion: keyId.Version, } - if keyVaultUAI := d.Get("key_vault_user_identity_id").(string); keyVaultUAI != "" { + if keyVaultUAI := d.Get("key_vault_user_assigned_identity_id").(string); keyVaultUAI != "" { containerGroup.Properties.EncryptionProperties.Identity = &keyVaultUAI } } @@ -952,12 +952,7 @@ func resourceContainerGroupRead(d *pluginsdk.ResourceData, meta interface{}) err return err } d.Set("key_vault_key_id", keyId.ID()) - - var uai string - if kvProps.Identity != nil { - uai = *kvProps.Identity - } - d.Set("key_vault_user_identity_id", uai) + d.Set("key_vault_user_assigned_identity_id", pointer.From(kvProps.Identity)) } } diff --git a/internal/services/containers/container_group_resource_test.go b/internal/services/containers/container_group_resource_test.go index a864907da629..1cdc1790fe56 100644 --- a/internal/services/containers/container_group_resource_test.go +++ b/internal/services/containers/container_group_resource_test.go @@ -2599,8 +2599,8 @@ resource "azurerm_container_group" "test" { protocol = "TCP" } } - key_vault_key_id = azurerm_key_vault_key.test.id - key_vault_user_identity_id = azurerm_user_assigned_identity.test.id + key_vault_key_id = azurerm_key_vault_key.test.id + key_vault_user_assigned_identity_id = azurerm_user_assigned_identity.test.id identity { type = "UserAssigned" identity_ids = [azurerm_user_assigned_identity.test.id] diff --git a/website/docs/r/container_group.html.markdown b/website/docs/r/container_group.html.markdown index 32180b72b6ac..6ef1889f9c30 100644 --- a/website/docs/r/container_group.html.markdown +++ b/website/docs/r/container_group.html.markdown @@ -99,7 +99,7 @@ The following arguments are supported: * `key_vault_key_id` - (Optional) The Key Vault key URI for CMK encryption. Changing this forces a new resource to be created. -* `key_vault_user_identity_id` - (Optional) The user assigned identity that has access to the Key Vault Key. If not specified, the RP principal named "Azure Container Instance Service" will be used instead. Make sure the identity has the proper `key_permissions` set, at least with `Get`, `UnwrapKey`, `WrapKey` and `GetRotationPolicy`. +* `key_vault_user_assigned_identity_id` - (Optional) The user assigned identity that has access to the Key Vault Key. If not specified, the RP principal named "Azure Container Instance Service" will be used instead. Make sure the identity has the proper `key_permissions` set, at least with `Get`, `UnwrapKey`, `WrapKey` and `GetRotationPolicy`. * `subnet_ids` - (Optional) The subnet resource IDs for a container group. Changing this forces a new resource to be created.