Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions infra/env/prod/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ module "sluice" {
extra_providers = var.extra_providers
enable_router_shim = var.enable_router_shim
router_shim_tokenutil_package = var.router_shim_tokenutil_package

custom_domains = var.custom_domains
}

# Adopt the out-of-band custom-domain binding for sluice.phoenixvc.tech,
# created 2026-07-03 via `az containerapp hostname add` + `az containerapp
# hostname bind --validation-method CNAME` (Azure-managed certificate
# mc-pvc-prod-sluic-sluice-phoenixvc-1673). The first apply after this lands
# should report "1 to import, 0 to add/change/destroy" for this resource;
# once the binding is in state the block is a no-op and may be removed.
#
# Note: the static segment is `containerApps` (capital A) — the azurerm v4
# ID parser is case-sensitive and rejects the all-lowercase form that
# `az containerapp show --query id` returns.
import {
to = module.sluice.azurerm_container_app_custom_domain.custom["sluice.phoenixvc.tech"]
id = "/subscriptions/bb4e3882-2079-4bab-8974-611bc0b8bb58/resourceGroups/pvc-prod-sluice-rg/providers/Microsoft.App/containerApps/pvc-prod-sluice-ca/customDomainName/sluice.phoenixvc.tech"
}

module "state_service" {
Expand Down
6 changes: 6 additions & 0 deletions infra/env/prod/terraform.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,9 @@ enable_litellm_db = true
# # Phase 3 — Kimi K2 direct Moonshot path (optional; Groq path uses GROQ_API_KEY above)
# moonshot = { api_key = "sk-...", env_name = "MOONSHOT_API_KEY" }
# }

# Custom domain for the gateway. DNS (CNAME + asuid TXT) lives in the
# org-owned phoenixvc.tech zone in `mys-global-shared-rg` (a different
# subscription than sluice) and is intentionally not managed by this stack.
# The Azure-managed certificate was bound out-of-band on 2026-07-03.
custom_domains = ["sluice.phoenixvc.tech"]
6 changes: 6 additions & 0 deletions infra/env/prod/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,9 @@ variable "extra_providers" {
default = {}
sensitive = true
}

variable "custom_domains" {
type = list(string)
description = "Pre-verified custom hostnames to bind to the gateway Container App. Each hostname must already have DNS in place (CNAME + asuid TXT in the owning zone) and an Azure-managed certificate provisioned out-of-band via `az containerapp hostname add` + `az containerapp hostname bind` before being listed here."
default = []
}
23 changes: 23 additions & 0 deletions infra/modules/sluice_aca/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1017,3 +1017,26 @@ resource "azurerm_container_app" "ca" {
}
}
}

# Custom domain bindings (e.g. sluice.phoenixvc.tech).
#
# DNS is intentionally NOT managed here: the CNAME + `asuid.<host>` TXT
# records for phoenixvc.tech live in the org-owned DNS zone in
# `mys-global-shared-rg` (a different subscription / ownership boundary than
# sluice). Records must exist — and the Azure-managed certificate must be
# provisioned via `az containerapp hostname add` + `az containerapp hostname
# bind --validation-method CNAME` — before a hostname is added to
# var.custom_domains.
resource "azurerm_container_app_custom_domain" "custom" {
for_each = toset(var.custom_domains)
name = each.value
container_app_id = azurerm_container_app.ca.id

# Azure-managed certificate: provisioned out-of-band by
# `az containerapp hostname bind`. azurerm cannot manage managed
# certs directly; per provider docs these attributes must be
# ignored or every plan tries to unbind the certificate.
lifecycle {
ignore_changes = [certificate_binding_type, container_app_environment_certificate_id]
}
Comment on lines +1039 to +1041
}
5 changes: 5 additions & 0 deletions infra/modules/sluice_aca/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,8 @@ output "application_insights_name" {
description = "Application Insights resource name. Retrieve connection string from Key Vault secret 'appinsights-connection-string'."
value = azurerm_application_insights.ai.name
}

output "custom_domain_fqdns" {
description = "Custom hostnames bound to the gateway Container App (empty when none configured)."
value = [for d in azurerm_container_app_custom_domain.custom : d.name]
}
8 changes: 8 additions & 0 deletions infra/modules/sluice_aca/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,11 @@ variable "otel_service_name" {
description = "OpenTelemetry service name for tracing."
default = "ai-gateway"
}

# Custom domain bindings — see the azurerm_container_app_custom_domain
# resource in main.tf for the out-of-band provisioning contract.
variable "custom_domains" {
type = list(string)
description = "Pre-verified custom hostnames to bind to the gateway Container App. Each hostname must already have DNS in place (CNAME + asuid TXT in the owning zone) and an Azure-managed certificate provisioned out-of-band via `az containerapp hostname add` + `az containerapp hostname bind` before being listed here."
default = []
}
Comment on lines +322 to +326