Skip to content

Commit e1e6bbc

Browse files
feat(nginx_gateway_fabric): drop bootstrap TLS placeholders, let cert-manager shim issue
The per-hostname self-signed placeholder secrets (6 blocks x N hostnames) worked around the cert-manager HTTP-01 + Gateway API bug (cert-manager/cert-manager#7337: broken 1.16.0, fixed 1.18.1). The bundled cert-manager is past that fix, so the gateway/listenerset-shim creates each listener's TLS secret on its own. Removes tls_private_key/tls_self_signed_cert/kubernetes_secret_v1 bootstrap resources + the bootstrap_tls_domains local + the helm_release depends_on on them. Listeners still reference the same secret names (strings); the shim now fills them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8e45a8d commit e1e6bbc

1 file changed

Lines changed: 4 additions & 111 deletions

File tree

nginx_gateway_fabric/main.tf

Lines changed: 4 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -187,16 +187,6 @@ locals {
187187
local.gateway_api_crd_labels
188188
)
189189

190-
# Domains that need bootstrap TLS certificates so the HTTPS listener is valid before
191-
# cert-manager issues. Without a placeholder secret the listener is rejected
192-
# (InvalidCertificateRef) and never accepted, so the gateway-shim never issues the
193-
# real cert — a deadlock. cert-manager overwrites this secret once HTTP-01 succeeds.
194-
bootstrap_tls_domains = var.external_tls_termination ? {} : {
195-
for domain_key, domain in local.domains :
196-
domain_key => domain
197-
if can(domain.domain) && lookup(domain, "certificate_reference", "") == ""
198-
}
199-
200190
# Domains that need cert-manager to issue certificates
201191
# Only domains WITHOUT certificate_reference
202192
# Not needed when TLS is terminated externally
@@ -1088,103 +1078,10 @@ locals {
10881078
)
10891079
}
10901080

1091-
# Bootstrap TLS for the base domain — placeholder self-signed cert so the HTTPS
1092-
# listener is valid and accepted before cert-manager issues the real cert (breaks
1093-
# the listener-invalid / cert-not-issued deadlock). cert-manager overwrites it.
1094-
resource "tls_private_key" "bootstrap" {
1095-
for_each = local.bootstrap_tls_domains
1096-
algorithm = "RSA"
1097-
rsa_bits = 2048
1098-
}
1099-
1100-
resource "tls_self_signed_cert" "bootstrap" {
1101-
for_each = local.bootstrap_tls_domains
1102-
private_key_pem = tls_private_key.bootstrap[each.key].private_key_pem
1103-
1104-
subject {
1105-
common_name = each.value.domain
1106-
}
1107-
1108-
validity_period_hours = 8760 # 1 year
1109-
1110-
dns_names = [
1111-
each.value.domain,
1112-
"*.${each.value.domain}"
1113-
]
1114-
1115-
allowed_uses = [
1116-
"key_encipherment",
1117-
"digital_signature",
1118-
"server_auth"
1119-
]
1120-
}
1121-
1122-
resource "kubernetes_secret_v1" "bootstrap_tls" {
1123-
for_each = local.bootstrap_tls_domains
1124-
1125-
metadata {
1126-
name = "${local.name}-${each.key}-tls-cert"
1127-
namespace = var.environment.namespace
1128-
}
1129-
1130-
data = {
1131-
"tls.crt" = tls_self_signed_cert.bootstrap[each.key].cert_pem
1132-
"tls.key" = tls_private_key.bootstrap[each.key].private_key_pem
1133-
}
1134-
1135-
type = "kubernetes.io/tls"
1136-
1137-
lifecycle {
1138-
ignore_changes = [data, metadata[0].annotations, metadata[0].labels]
1139-
}
1140-
}
1141-
1142-
# Bootstrap TLS for additional hostnames (from domain_prefix in rules)
1143-
# Only for additional hostnames that did NOT inherit a certificate_reference from parent domain
1144-
resource "tls_private_key" "bootstrap_additional" {
1145-
for_each = local.additional_hostname_configs
1146-
algorithm = "RSA"
1147-
rsa_bits = 2048
1148-
}
1149-
1150-
resource "tls_self_signed_cert" "bootstrap_additional" {
1151-
for_each = local.additional_hostname_configs
1152-
private_key_pem = tls_private_key.bootstrap_additional[each.key].private_key_pem
1153-
1154-
subject {
1155-
common_name = each.value.hostname
1156-
}
1157-
1158-
validity_period_hours = 8760 # 1 year
1159-
1160-
dns_names = [each.value.hostname]
1161-
1162-
allowed_uses = [
1163-
"key_encipherment",
1164-
"digital_signature",
1165-
"server_auth"
1166-
]
1167-
}
1168-
1169-
resource "kubernetes_secret_v1" "bootstrap_tls_additional" {
1170-
for_each = local.additional_hostname_configs
1171-
1172-
metadata {
1173-
name = each.value.secret_name
1174-
namespace = var.environment.namespace
1175-
}
1176-
1177-
data = {
1178-
"tls.crt" = tls_self_signed_cert.bootstrap_additional[each.key].cert_pem
1179-
"tls.key" = tls_private_key.bootstrap_additional[each.key].private_key_pem
1180-
}
1181-
1182-
type = "kubernetes.io/tls"
1183-
1184-
lifecycle {
1185-
ignore_changes = [data, metadata[0].annotations, metadata[0].labels]
1186-
}
1187-
}
1081+
# Bootstrap TLS placeholder secrets removed: cert-manager's gateway/listenerset-shim creates the
1082+
# listener's TLS secret itself. The old placeholder worked around the cert-manager HTTP-01 + Gateway
1083+
# API bug (cert-manager/cert-manager#7337, broken 1.16.0, fixed 1.18.1); the bundled cert-manager
1084+
# is past that fix, so no placeholder is needed.
11881085

11891086
# Helm release name - keep under 34 chars so that fullname (release + "-" + chart name = 34+1+20 = 55)
11901087
# plus the longest suffix (-certgen, 8 chars) stays within the 63-char k8s label value limit.
@@ -1424,10 +1321,6 @@ resource "helm_release" "nginx_gateway_fabric" {
14241321
yamlencode(local.base_helm_values)
14251322
]
14261323

1427-
depends_on = [
1428-
kubernetes_secret_v1.bootstrap_tls,
1429-
kubernetes_secret_v1.bootstrap_tls_additional
1430-
]
14311324
}
14321325

14331326
# Deploy all Gateway API resources using facets-utility-modules

0 commit comments

Comments
 (0)