diff --git a/internal/services/web/app_service_resource.go b/internal/services/web/app_service_resource.go index cb538b038dc8..20676a4ffc44 100644 --- a/internal/services/web/app_service_resource.go +++ b/internal/services/web/app_service_resource.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + msivalidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/msi/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/services/web/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/web/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" @@ -134,6 +135,13 @@ func resourceAppService() *pluginsdk.Resource { Default: false, }, + "key_vault_reference_identity_id": { + Type: pluginsdk.TypeString, + Optional: true, + Computed: true, + ValidateFunc: msivalidate.UserAssignedIdentityID, + }, + "logs": schemaAppServiceLogsConfig(), "site_config": schemaAppServiceSiteConfig(), @@ -274,6 +282,10 @@ func resourceAppServiceCreate(d *pluginsdk.ResourceData, meta interface{}) error }, } + if v, ok := d.GetOk("key_vault_reference_identity_id"); ok { + siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(v.(string)) + } + if _, ok := d.GetOk("identity"); ok { appServiceIdentityRaw := d.Get("identity").([]interface{}) appServiceIdentity := expandAppServiceIdentity(appServiceIdentityRaw) @@ -398,6 +410,10 @@ func resourceAppServiceUpdate(d *pluginsdk.ResourceData, meta interface{}) error }, } + if v, ok := d.GetOk("key_vault_reference_identity_id"); ok { + siteEnvelope.SiteProperties.KeyVaultReferenceIdentity = utils.String(v.(string)) + } + siteEnvelope.SiteProperties.ClientCertEnabled = utils.Bool(d.Get("client_cert_enabled").(bool)) future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope) @@ -684,6 +700,10 @@ func resourceAppServiceRead(d *pluginsdk.ResourceData, meta interface{}) error { d.Set("possible_outbound_ip_address_list", strings.Split(*props.PossibleOutboundIPAddresses, ",")) } d.Set("custom_domain_verification_id", props.CustomDomainVerificationID) + + if props.KeyVaultReferenceIdentity != nil { + d.Set("key_vault_reference_identity_id", props.KeyVaultReferenceIdentity) + } } appSettings := flattenAppServiceAppSettings(appSettingsResp.Properties) diff --git a/internal/services/web/app_service_resource_test.go b/internal/services/web/app_service_resource_test.go index 39c51c771e1e..678e6b04fca4 100644 --- a/internal/services/web/app_service_resource_test.go +++ b/internal/services/web/app_service_resource_test.go @@ -1928,6 +1928,21 @@ func TestAccAppServiceEnvironment_scopeNameCheck(t *testing.T) { }) } +func TestAccAppService_keyVaultUserAssignedIdentity(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + r := AppServiceResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.KeyVaultUserAssignedIdentity(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (r AppServiceResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.AppServiceID(state.ID) if err != nil { @@ -5591,3 +5606,47 @@ resource "azurerm_app_service" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } + +func (r AppServiceResource) KeyVaultUserAssignedIdentity(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_user_assigned_identity" "test" { + name = "acct-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + key_vault_reference_identity_id = azurerm_user_assigned_identity.test.id + + identity { + type = "UserAssigned" + identity_ids = [azurerm_user_assigned_identity.test.id] + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index ccf3723b9458..fd90204be0e2 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -87,6 +87,8 @@ The following arguments are supported: * `https_only` - (Optional) Can the App Service only be accessed via HTTPS? Defaults to `false`. +* `key_vault_reference_identity_id` - (Optional) The User Assigned Identity Id used for looking up KeyVault secrets. The identity must be assigned to the application. [For more information see - Access vaults with a user-assigned identity](https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references#access-vaults-with-a-user-assigned-identity) + * `logs` - (Optional) A `logs` block as defined below. * `storage_account` - (Optional) One or more `storage_account` blocks as defined below.