Skip to content

fix(nginx_gateway_fabric_aws): auto-issue ACM cert for base domain in acm_mode#376

Open
sanmesh-kakade wants to merge 1 commit into
mainfrom
fix/nginx-gwf-aws-base-domain-acm
Open

fix(nginx_gateway_fabric_aws): auto-issue ACM cert for base domain in acm_mode#376
sanmesh-kakade wants to merge 1 commit into
mainfrom
fix/nginx-gwf-aws-base-domain-acm

Conversation

@sanmesh-kakade

Copy link
Copy Markdown
Contributor

Problem

In acm_mode — an ACM ARN is supplied as a domain's certificate_reference and no ACK ACM controller is present — TLS terminates at the NLB and the wrapper sets external_tls_termination=true, which disables cert-manager in the base module.

The base domain carries no certificate_reference, so it contributed no ARN to the service.beta.kubernetes.io/aws-load-balancer-ssl-cert annotation. Result: base-domain HTTPS fell back to the NLB default certificate (first ARN in the list) and failed hostname validation unless a user-supplied ACM cert coincidentally SAN'd the base domain.

Two independent code paths caused it:

  • certmanager_managed_domains = var.external_tls_termination ? {} : {...} (base module) → cert-manager issues nothing in acm_mode.
  • The wrapper's acm_cert_arns only scanned spec.domains (user overrides). The base domain is injected inside the base module, so the wrapper never saw it.

Fix

Port the base-domain ACM handling from the capillary flavour (Facets-cloud/ingress-migration@init/nginx_gateway_fabric_capillary). When acm_mode is active and the base domain is enabled on AWS:

  1. Issue an ACM certificate covering base_domain + *.base_domain (DNS validation).
  2. Publish its validation records to the tooling-account Route53 zone.
  3. Append the validated ARN to local.acm_cert_arns → always lands in the ssl-cert annotation.

base_domain is derived in the wrapper from the same control-plane metadata the base module uses (data.external.cc_env), not the base module's output — this avoids a dependency cycle (base_domain → ssl-cert annotation → base module input).

Provider split (cross-account) — reviewer note

Matches capillary:

  • aws_acm_certificate / aws_acm_certificate_validationdefault aws provider (workload account + region; an ACM cert attached to an NLB must be in the same account/region as the NLB).
  • aws_route53_record (DNS validation) + data.aws_route53_zoneaws3tooling (tooling-account Route53 zone).

Both providers are injected at deploy time by the iac-generator (same as nginx_k8s and the base module) — no required_providers in module source, per repo convention (facets_default_providers).

Guards

  • Fires only when acm_mode == true, disable_base_domain != true, and tenant_provider == "aws".
  • When acm_mode is false, the base domain keeps using cert-manager (unchanged).
  • disable_base_domain = true → zero base-ACM resources.

Validation

  • terraform fmt clean.
  • raptor ... --dry-run terraform init fails on aws3toolingpre-existing and inherent to deploy-time provider injection; the pristine module fails identically (verified). Real validation happens on CP upload where providers are injected.

⚠️ Not yet applied against the Control Plane. Needs a real plan/apply in a sandbox to confirm: base-ACM cert issued, ssl-cert annotation shows ≥2 ARNs incl. base, and curl https://<base_domain> returns a valid cert.

Follow-up / maintenance note

base_domain derivation is now duplicated in the wrapper and the base module and must stay byte-for-byte in sync (flagged in a code comment). Worth considering a shared source later.

🤖 Generated with Claude Code

… acm_mode

In acm_mode (an ACM ARN is supplied as a domain's certificate_reference and no
ACK ACM controller is present), TLS terminates at the NLB and cert-manager is
disabled (external_tls_termination=true). The base domain carries no
certificate_reference, so it contributed no ARN to the aws-load-balancer-ssl-cert
annotation. Base-domain HTTPS then fell back to the NLB default certificate and
failed hostname validation unless a user-supplied ACM cert happened to SAN it.

Port the base-domain ACM handling from the capillary flavour: when acm_mode is
active and the base domain is enabled on AWS, issue an ACM certificate covering
base_domain + *.base_domain, DNS-validate it via the tooling-account Route53
zone, and append its validated ARN to local.acm_cert_arns so it always lands in
the ssl-cert annotation.

base_domain is computed in this wrapper from the same control-plane metadata the
base module uses (data.external.cc_env), rather than the base module's output, to
avoid a cycle (base_domain -> ssl-cert annotation -> base module input).

Provider split matches capillary: the certificate is issued in the default aws
provider (workload account/region, where the NLB lives) while its DNS validation
records are written via aws3tooling (tooling-account Route53 zone).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant