Skip to content

Commit

Permalink
Merge pull request #25356 from hashicorp/f/container-app-custom-domai…
Browse files Browse the repository at this point in the history
…n-managed-cert-support

`azurerm_container_app_custom_domain` - support the ability to use Azure Managed Certificates
  • Loading branch information
jackofallops authored Apr 25, 2024
2 parents 869bf6a + a56e208 commit 923fd84
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ func (a ContainerAppCustomDomainResource) Arguments() map[string]*pluginsdk.Sche

"container_app_environment_certificate_id": {
Type: pluginsdk.TypeString,
Required: true,
Optional: true,
ForceNew: true,
RequiredWith: []string{"certificate_binding_type"},
ValidateFunc: managedenvironments.ValidateCertificateID,
},

"certificate_binding_type": {
Type: pluginsdk.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(containerapps.PossibleValuesForBindingType(), false),
Description: "The Binding type. Possible values include `Disabled` and `SniEnabled`.",
Expand Down Expand Up @@ -106,9 +107,12 @@ func (a ContainerAppCustomDomainResource) Create() sdk.ResourceFunc {

id := parse.NewContainerAppCustomDomainId(containerAppId.SubscriptionId, containerAppId.ResourceGroupName, containerAppId.ContainerAppName, model.Name)

certificateId, err := managedenvironments.ParseCertificateID(model.CertificateId)
if err != nil {
return err
var certificateId *managedenvironments.CertificateId
if model.CertificateId != "" {
certificateId, err = managedenvironments.ParseCertificateID(model.CertificateId)
if err != nil {
return err
}
}

containerApp, err := client.Get(ctx, *containerAppId)
Expand Down Expand Up @@ -149,11 +153,17 @@ func (a ContainerAppCustomDomainResource) Create() sdk.ResourceFunc {
customDomains = *existingCustomDomains
}

customDomains = append(customDomains, containerapps.CustomDomain{
BindingType: pointer.To(containerapps.BindingType(model.BindingType)),
CertificateId: pointer.To(certificateId.ID()),
Name: model.Name,
})
customDomain := containerapps.CustomDomain{
Name: model.Name,
BindingType: pointer.To(containerapps.BindingTypeDisabled),
}

if certificateId != nil {
customDomain.CertificateId = pointer.To(certificateId.ID())
customDomain.BindingType = pointer.To(containerapps.BindingType(model.BindingType))
}

customDomains = append(customDomains, customDomain)

containerApp.Model.Properties.Configuration.Ingress.CustomDomains = pointer.To(customDomains)

Expand Down Expand Up @@ -200,11 +210,14 @@ func (a ContainerAppCustomDomainResource) Read() sdk.ResourceFunc {
found = true
state.Name = id.CustomDomainName
state.ContainerAppId = containerAppId.ID()
certId, err := managedenvironments.ParseCertificateIDInsensitively(pointer.From(v.CertificateId))
if err != nil {
return err
if pointer.From(v.CertificateId) != "" {
certId, err := managedenvironments.ParseCertificateIDInsensitively(pointer.From(v.CertificateId))
if err != nil {
return err
}
state.CertificateId = certId.ID()
}
state.CertificateId = certId.ID()

state.BindingType = string(pointer.From(v.BindingType))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,25 @@ func TestAccContainerAppCustomDomainResource_basic(t *testing.T) {
})
}

func TestAccContainerAppCustomDomainResource_managedCertificate(t *testing.T) {
if os.Getenv("ARM_TEST_DNS_ZONE") == "" || os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" {
t.Skipf("Skipping as either ARM_TEST_DNS_ZONE or ARM_TEST_DATA_RESOURCE_GROUP is not set")
}

data := acceptance.BuildTestData(t, "azurerm_container_app_custom_domain", "test")
r := ContainerAppCustomDomainResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.managedCertificate(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func TestAccContainerAppCustomDomainResource_multiple(t *testing.T) {
if os.Getenv("ARM_TEST_DNS_ZONE") == "" || os.Getenv("ARM_TEST_DATA_RESOURCE_GROUP") == "" {
t.Skipf("Skipping as either ARM_TEST_DNS_ZONE or ARM_TEST_DATA_RESOURCE_GROUP is not set")
Expand Down Expand Up @@ -142,6 +161,27 @@ resource "azurerm_container_app_custom_domain" "test" {
certificate_binding_type = "SniEnabled"
}
`, r.template(data))
}

func (r ContainerAppCustomDomainResource) managedCertificate(data acceptance.TestData) string {
return fmt.Sprintf(`
provider azurerm {
features {}
}
%s
resource "azurerm_container_app_custom_domain" "test" {
name = trimprefix(azurerm_dns_txt_record.test.fqdn, "asuid.")
container_app_id = azurerm_container_app.test.id
lifecycle {
ignore_changes = [certificate_binding_type, container_app_environment_certificate_id]
}
}
`, r.template(data))
}

Expand Down
24 changes: 22 additions & 2 deletions website/docs/r/container_app_custom_domain.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ resource "azurerm_container_app_custom_domain" "example" {
```

## Example Usage - Managed Certificate

```hcl
resource "azurerm_container_app_custom_domain" "example" {
name = trimprefix(azurerm_dns_txt_record.example.fqdn, "asuid.")
container_app_id = azurerm_container_app.example.id
lifecycle {
// When using an Azure created Managed Certificate these values must be added to ignore_changes to prevent resource recreation.
ignore_changes = [certificate_binding_type, container_app_environment_certificate_id]
}
}
```


## Arguments Reference

The following arguments are supported:
Expand All @@ -101,9 +117,13 @@ The following arguments are supported:

* `container_app_id` - (Required) The ID of the Container App to which this Custom Domain should be bound. Changing this forces a new resource to be created.

* `container_app_environment_certificate_id` - (Required) The ID of the Container App Environment Certificate to use. Changing this forces a new resource to be created.
* `container_app_environment_certificate_id` - (Optional) The ID of the Container App Environment Certificate to use. Changing this forces a new resource to be created.

-> **NOTE:** Omit this value if you wish to use an Azure Managed certificate. You must create the relevant DNS verification steps before this process will be successful.

* `certificate_binding_type` - (Optional) The Certificate Binding type. Possible values include `Disabled` and `SniEnabled`. Required with `container_app_environment_certificate_id`. Changing this forces a new resource to be created.

* `certificate_binding_type` - (Required) The Certificate Binding type. Possible values include `Disabled` and `SniEnabled`. Changing this forces a new resource to be created.
!> **NOTE:** If using an Azure Managed Certificate `container_app_environment_certificate_id` and `certificate_binding_type` should be added to `ignore_changes` to prevent resource recreation due to these values being modified asynchronously outside of Terraform.

## Timeouts

Expand Down

0 comments on commit 923fd84

Please sign in to comment.