feat(net): custom domain for the Fusion-facing API

Fusion couldn't resolve the default *.execute-api.amazonaws.com endpoint, so front
the same HTTP API with hncb-deid.apim-apac-demo.com (ACM DNS-validated cert,
apigatewayv2 REGIONAL custom domain, root api mapping, Route53 A ALIAS). Callers
resolve our hostname straight to IPs and never touch an execute-api name; also
survives API-id churn. Point POLICY_SETUP + README demo at the custom URLs.

Verified live: resolves to IPs, 401 unauthenticated, tokenizes with the key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 11:04:19 +10:00
parent feb44be76b
commit b5de55d4a6
3 changed files with 91 additions and 4 deletions

View File

@@ -84,7 +84,8 @@ in `CLAUDE.md`, which record the exact sequencing and gotchas):
## Demo script (Fusion-less dry run — maps to the 8 steps)
```bash
cd terraform && DEMO=$(terraform output -raw demo_url) && UI=$(terraform output -raw ui_url); cd ..
cd terraform && DEMO=$(terraform output -raw demo_url_custom) && UI=$(terraform output -raw ui_url); cd ..
# (demo_url_custom uses the Route53 custom domain Fusion can resolve; demo_url is the raw execute-api one)
# 1-2, 4-8: advisor query -> tokenize -> agent (on tokens) -> restore, in one call:
curl -s -X POST "$DEMO" -H 'content-type: application/json' \

View File

@@ -35,14 +35,20 @@ advisor ◀────┘
The transforms run **inside the policy boundary**; the raw name never crosses it.
## Backend the policy calls
- `TOKENIZE_URL` = `https://<api-id>.execute-api.<region>.amazonaws.com/tokenize`
`terraform -chdir=terraform output -raw tokenize_url`
- `RESTORE_URL` = `https://<...>/restore``terraform ... output -raw restore_url`
Use the **custom domain** — Fusion could not resolve the default
`*.execute-api.ap-southeast-1.amazonaws.com` endpoint, so the API is fronted by a
Route53-aliased name that resolves straight to IPs (see `terraform/custom_domain.tf`).
- `TOKENIZE_URL` = `https://hncb-deid.apim-apac-demo.com/tokenize`
`terraform -chdir=terraform output -raw tokenize_url_custom`
- `RESTORE_URL` = `https://hncb-deid.apim-apac-demo.com/restore`
`terraform -chdir=terraform output -raw restore_url_custom`
- `AGENT_RUNTIME_ARN` (the route's upstream) = printed by `scripts/agentcore_setup.sh`
- **Auth:** public API Gateway HTTP API; send the shared secret in the **`x-api-key`**
header (`Authorization: Bearer <secret>` also works). The secret is the Terraform
`tokenize_api_key` var (gitignored `terraform/local.auto.tfvars`, never committed) —
hand it to the console operator out of band.
- *Note:* the raw `…execute-api…` URLs (`output -raw tokenize_url` / `restore_url`)
still work for anything that can resolve them; Fusion should use the custom domain.
- *Note:* a Lambda Function URL was the first choice, but this account's SCP blocks
unauthenticated Function URLs, so the public front door is API Gateway.

View File

@@ -0,0 +1,80 @@
# ---------------------------------------------------------------------------
# Custom domain for the Fusion-facing API. Fusion couldn't resolve the default
# *.execute-api.amazonaws.com hostname, so we front the same HTTP API with a
# stable name in a zone we control and point it with a Route53 ALIAS (A record).
# Callers resolve hncb-deid.apim-apac-demo.com -> IPs directly; they never have to
# resolve an execute-api / amazonaws.com name. Also survives API-id churn.
# ---------------------------------------------------------------------------
locals {
api_fqdn = "hncb-deid.apim-apac-demo.com"
}
data "aws_route53_zone" "api" {
name = "apim-apac-demo.com"
private_zone = false
}
# Regional API Gateway custom domains need the ACM cert in the SAME region.
resource "aws_acm_certificate" "api" {
domain_name = local.api_fqdn
validation_method = "DNS"
tags = local.onprem_tag
lifecycle {
create_before_destroy = true
}
}
resource "aws_route53_record" "api_cert_validation" {
for_each = {
for dvo in aws_acm_certificate.api.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
type = dvo.resource_record_type
record = dvo.resource_record_value
}
}
zone_id = data.aws_route53_zone.api.zone_id
name = each.value.name
type = each.value.type
records = [each.value.record]
ttl = 60
allow_overwrite = true
}
resource "aws_acm_certificate_validation" "api" {
certificate_arn = aws_acm_certificate.api.arn
validation_record_fqdns = [for r in aws_route53_record.api_cert_validation : r.fqdn]
}
resource "aws_apigatewayv2_domain_name" "api" {
domain_name = local.api_fqdn
domain_name_configuration {
certificate_arn = aws_acm_certificate_validation.api.certificate_arn
endpoint_type = "REGIONAL"
security_policy = "TLS_1_2"
}
tags = local.onprem_tag
}
# Map the custom domain at the root to the $default stage (routes: /tokenize, etc.)
resource "aws_apigatewayv2_api_mapping" "api" {
api_id = aws_apigatewayv2_api.gateway.id
domain_name = aws_apigatewayv2_domain_name.api.id
stage = aws_apigatewayv2_stage.default.id
}
# ALIAS (IPv4) -> returns IPs directly, so Fusion never resolves an AWS hostname.
resource "aws_route53_record" "api_alias" {
zone_id = data.aws_route53_zone.api.zone_id
name = local.api_fqdn
type = "A"
alias {
name = aws_apigatewayv2_domain_name.api.domain_name_configuration[0].target_domain_name
zone_id = aws_apigatewayv2_domain_name.api.domain_name_configuration[0].hosted_zone_id
evaluate_target_health = false
}
}
output "tokenize_url_custom" { value = "https://${local.api_fqdn}/tokenize" }
output "restore_url_custom" { value = "https://${local.api_fqdn}/restore" }
output "demo_url_custom" { value = "https://${local.api_fqdn}/demo" }