diff --git a/azurerm/internal/services/web/resource_arm_app_service_certificate.go b/azurerm/internal/services/web/resource_arm_app_service_certificate.go index a48a7905cc2b..1da8ae32bd31 100644 --- a/azurerm/internal/services/web/resource_arm_app_service_certificate.go +++ b/azurerm/internal/services/web/resource_arm_app_service_certificate.go @@ -73,6 +73,12 @@ func resourceArmAppServiceCertificate() *schema.Resource { ConflictsWith: []string{"pfx_blob", "password"}, }, + "hosting_environment_profile_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "friendly_name": { Type: schema.TypeString, Computed: true, @@ -130,6 +136,7 @@ func resourceArmAppServiceCertificateCreateUpdate(d *schema.ResourceData, meta i pfxBlob := d.Get("pfx_blob").(string) password := d.Get("password").(string) keyVaultSecretId := d.Get("key_vault_secret_id").(string) + hostingEnvironmentProfileId := d.Get("hosting_environment_profile_id").(string) t := d.Get("tags").(map[string]interface{}) if pfxBlob == "" && keyVaultSecretId == "" { @@ -157,6 +164,12 @@ func resourceArmAppServiceCertificateCreateUpdate(d *schema.ResourceData, meta i Tags: tags.Expand(t), } + if len(hostingEnvironmentProfileId) > 0 { + certificate.CertificateProperties.HostingEnvironmentProfile = &web.HostingEnvironmentProfile{ + ID: &hostingEnvironmentProfileId, + } + } + if pfxBlob != "" { decodedPfxBlob, err := base64.StdEncoding.DecodeString(pfxBlob) if err != nil { @@ -237,6 +250,10 @@ func resourceArmAppServiceCertificateRead(d *schema.ResourceData, meta interface d.Set("issue_date", props.IssueDate.Format(time.RFC3339)) d.Set("expiration_date", props.ExpirationDate.Format(time.RFC3339)) d.Set("thumbprint", props.Thumbprint) + + if hep := props.HostingEnvironmentProfile; hep != nil { + d.Set("hosting_environment_profile_id", hep.ID) + } } return tags.FlattenAndSet(d, resp.Tags) diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index 71769ef80e8e..3828fc8ed968 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -139,6 +139,26 @@ func TestAccAzureRMAppServiceEnvironment_dedicatedResourceGroup(t *testing.T) { }) } +func TestAccAzureRMAppServiceEnvironment_withCertificatePfx(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + certData := acceptance.BuildTestData(t, "azurerm_app_service_certificate", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceEnvironment_withCertificatePfx(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMCertHostingEnvProfileIdMatchesAseId(data.ResourceName, certData.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMAppServiceEnvironmentExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient @@ -168,6 +188,45 @@ func testCheckAzureRMAppServiceEnvironmentExists(resourceName string) resource.T } } +func testCheckAzureRMCertHostingEnvProfileIdMatchesAseId(aseResourceName, certResourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + certsConn := acceptance.AzureProvider.Meta().(*clients.Client).Web.CertificatesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + aseRs, ok := s.RootModule().Resources[aseResourceName] + if !ok { + return fmt.Errorf("Not found: %s", aseResourceName) + } + certRs, ok := s.RootModule().Resources[certResourceName] + if !ok { + return fmt.Errorf("Not found: %s", certResourceName) + } + + aseId := aseRs.Primary.Attributes["id"] + + certName := certRs.Primary.Attributes["name"] + certResourceGroup, hasResourceGroup := certRs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for Certificate: %s", certName) + } + + certResp, err := certsConn.Get(ctx, certResourceGroup, certName) + if err != nil { + if utils.ResponseWasNotFound(certResp.Response) { + return fmt.Errorf("Bad: Certificatet %q (resource group: %q) does not exist", certName, certResourceGroup) + } + + return fmt.Errorf("Bad: Get on certificatesClient: %+v", err) + } + + if *certResp.HostingEnvironmentProfile.ID != aseId { + return fmt.Errorf("Bad: Certificate hostingEnvironmentProfile.ID (%s) not equal to ASE ID (%s)", *certResp.HostingEnvironmentProfile.ID, aseId) + } + + return nil + } +} + func testCheckAzureRMAppServiceEnvironmentDestroy(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient @@ -271,6 +330,22 @@ resource "azurerm_app_service_environment" "test" { `, template, data.RandomInteger, data.Locations.Secondary) } +func testAccAzureRMAppServiceEnvironment_withCertificatePfx(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_certificate" "test" { + name = "acctest-cert-%d" + resource_group_name = azurerm_app_service_environment.test.resource_group_name + location = azurerm_resource_group.test.location + pfx_blob = filebase64("testdata/app_service_certificate.pfx") + password = "terraform" + hosting_environment_profile_id = azurerm_app_service_environment.test.id +} +`, template, data.RandomInteger) +} + func testAccAzureRMAppServiceEnvironment_template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/website/docs/r/app_service_certificate.html.markdown b/website/docs/r/app_service_certificate.html.markdown index 0c814c474116..9ff0ce18bd06 100644 --- a/website/docs/r/app_service_certificate.html.markdown +++ b/website/docs/r/app_service_certificate.html.markdown @@ -47,6 +47,8 @@ The following arguments are supported: * `password` - (Optional) The password to access the certificate's private key. Changing this forces a new resource to be created. +* `hosting_environment_profile_id` - (Optional) Must be specified when the certificate is for an App Service Environment hosted App Service. Changing this forces a new resource to be created. + * `key_vault_secret_id` - (Optional) The ID of the Key Vault secret. Changing this forces a new resource to be created. -> **NOTE:** If using `key_vault_secret_id`, the WebApp Service Resource Principal ID `abfa0a7c-a6b6-4736-8310-5855508787cd` must have 'Secret -> get' and 'Certificate -> get' permissions on the Key Vault containing the certificate. (Source: [App Service Blog](https://azure.github.io/AppService/2016/05/24/Deploying-Azure-Web-App-Certificate-through-Key-Vault.html)) If you use Terraform to create the access policy you have to specify the Object ID of this Principal. This Object ID can be retrieved via following data reference, since it is different in every AAD Tenant: