Two correctness fixes for multi-tenant Gateway ACME, plus a small
default-tightening.
1. Per-tenant Issuer (child-tenant ACME closes)
packages/extra/gateway/templates/issuer.yaml (new): render a
cert-manager.io/v1 Issuer named 'gateway' in the tenant's own
namespace. It carries its own ACME account (privateKeySecretRef
'gateway-acme-account') and an http01.gatewayHTTPRoute solver whose
parentRef points to the local Gateway 'cozystack' at sectionName http
— no namespace on parentRef, so it attaches in-namespace only.
packages/extra/gateway/templates/gateway.yaml: the wildcard
Certificate now references issuerRef kind: Issuer, name: gateway
(namespace-scoped) instead of the previous cluster-scoped
letsencrypt-prod. The result: every tenant that enables
tenant.spec.gateway=true gets a fully self-contained ACME flow —
its own account, its own HTTPRoute, its own Gateway, no cross-
namespace dependency on the publishing tenant. Child tenants with
gateway: true now work end-to-end for ACME HTTP-01.
The template maps 'publishing.certificates.issuerName' to a
concrete ACME server URL: letsencrypt-prod →
acme-v02.api.letsencrypt.org/directory, letsencrypt-stage →
acme-staging-v02.api.letsencrypt.org/directory. Any other value
fails the render with an explicit error pointing at the file to
extend.
Three new helm-unittest cases cover Certificate→Issuer linkage,
staging-server selection, and the unknown-issuer fail path.
2. Hostname VAP installs unconditionally
packages/system/cozystack-basics/templates/gateway-hostname-policy.yaml:
drop the 'eq gateway-enabled true' guard. The ValidatingAdmissionPolicy
now installs whenever publishing.host is set, regardless of whether
gateway.enabled is flipped. Rationale: Gateway CRDs ship
unconditionally (gateway-api-crds is loaded in every bundle), so a
tenant could create a Gateway manually even with gateway.enabled=false.
The VAP must guard that path too.
3. Restore opt-in default in e2e
hack/e2e-install-cozystack.bats: revert the gateway.enabled: true
line so the default e2e platform configuration matches production
defaults. Gateway API remains strictly opt-in. The
'exposed services render HTTPRoute/TLSRoute but not Ingress' test
(which required platform-wide gateway.enabled=true) is removed; the
VAP cross-tenant reject test stays and now works against the
unconditionally-installed policy.
Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>