feat(dns): create BYOC DNS zones only when needed, decided by networks - #380
feat(dns): create BYOC DNS zones only when needed, decided by networks#380defang-sam[bot] wants to merge 1 commit into
Conversation
a209856 to
c2e6f5c
Compare
|
Force-pushed a lint fix (the
Verified locally this time with golangci-lint v2.11.4 ( |
Two related changes to the pulumi-defang providers.
1. Create DNS zones only when a project needs them, instead of always:
- private zone: only when a service is in a private network, has host-mode
ports, or uses managed Postgres/Redis;
- GCP public delegate zone + wildcard cert: only when the project has a
public ingress service. AWS already gated this and its public zone is
config-provided. Resolves the two "TODO: make this optional, save $$".
2. Decide public vs private by Compose networks, not port mode. The default
network is public unless internal:true; any other network, or internal, is
private. Port mode only selects the exposure type (ingress = public load
balancer, host = direct public IP). This stops a service that has an ingress
port but sits in a private/internal network from leaking into the public
zone, routing, and FQDN. Threaded networks through ServiceFQDN, the AWS/GCP
public-routing gates, and the zone gates; also wired real networks into
Azure's ingress External flag (was a nil TODO).
Host-mode ports stay a transitional private trigger, so default-network host
services keep their internal name until public+host DNS exists (pulumi-defang#253).
The common case (no explicit networks -> default -> public) is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
c2e6f5c to
0bf4d5e
Compare
|
Amended per review feedback: public/private is now decided by Compose networks, not port mode (the decided model — defang-mvp#1668 / defang#1105). Port mode is kept only for the exposure type (ingress = public LB, host = direct public IP). Key effect: an ingress service in a private/ |
|
Reviewed head 1. GCP public delegate zone becomes destroyable — delegation-breaking. 2. AWS private-zone removal can hard-fail deploys. 3. Worth fixing in the same PR: the AWS side of "private-network ingress" is silently unreachable — the route53 sidecar is still gated on Follow-ups (separate issues): Also: the PR body needs a "what happens on the next |
lionello
left a comment
There was a problem hiding this comment.
Also see comments from @defangdevs
| func NeedIngress(networks compose.Networks, services compose.Services) bool { | ||
| for _, svc := range services { | ||
| if svc.HasIngressPorts() && svc.Postgres == nil && svc.Redis == nil { | ||
| if svc.HasIngressPorts() && svc.Postgres == nil && svc.Redis == nil && InPublicNetwork(networks, svc) { |
There was a problem hiding this comment.
We should anticipate (future) private ingress. To that extend, after this edit we need to either rename this function now to NeedPublicIngress or move the InPublicNetwork to the caller.
| BuildInfra *BuildInfra // non-nil when at least one service has a build config | ||
| ServiceConnection *servicenetworking.Connection // non-nil when any service uses managed Postgres or Redis | ||
| PrivateZone pulumi.StringOutput // managed zone name for the private google.internal. zone | ||
| PrivateZone pulumi.StringOutput // google.internal. zone; empty when not needed |
There was a problem hiding this comment.
Should this be pulumi.StringPtrOutput then?
| PublicIP *compute.GlobalAddress | ||
| WildcardCertId pulumi.StringInput // non-nil when a domain is configured | ||
| PublicZoneId pulumi.StringInput // managed zone name; non-nil when a domain is configured | ||
| WildcardCertId pulumi.StringInput // set when a domain is configured and the project has ingress |
There was a problem hiding this comment.
Ditto, should this be pulumi.StringPtrInput
| WildcardCertId pulumi.StringInput // non-nil when a domain is configured | ||
| PublicZoneId pulumi.StringInput // managed zone name; non-nil when a domain is configured | ||
| WildcardCertId pulumi.StringInput // set when a domain is configured and the project has ingress | ||
| PublicZoneId pulumi.StringInput // public managed zone name; set alongside WildcardCertId |
There was a problem hiding this comment.
Ditto, should this be pulumi.StringPtrInput now
What
Two related changes to the
pulumi-defangproviders (AWS + GCP + Azure).1. Create BYOC DNS zones only when needed
<project>.internal/ GCPgoogle.internal.) — created only when a service is in a private network, has host-mode ports, or is a managed Postgres/Redis.infra.goNeedIngress) and its public zone is caller-provided. Resolves both// TODO: make this optional, so we can save $$.2. Decide public vs private by Compose networks, not port mode
Per the decided model (defang-mvp#1668 / defang#1105,
defang-docsnetworking.mdx): thedefaultnetwork is public unlessinternal: true; any other network, orinternal, is private. Port mode only selects the exposure type —ingress= public load balancer,host= direct public IP.This fixes a service that has an ingress port but sits in a private/internal network from leaking into the public zone, the public ALB/LB routing, and a public
*.defang.appFQDN. Threadednetworksthrough:common.ServiceFQDN(the shared public/private FQDN chokepoint);common.NeedIngress/common.NeedPrivateZone(the zone gates);ecs.go) and the GCP external-LB filter (alb.go);Externalflag (containerapp.go— was anilTODO).Behavior / compatibility
networks:is implicitly in the non-internaldefaultnetwork → public, exactly as before. Only projects that declare a private/internalnetwork are affected (few, per maintainer guidance)..internalname until public+host DNS is implemented (pulumi-defang#253).InPrivateNetworkis now the networks-based decision; port mode is retained only for the exposure type.Follow-ups (out of scope, per the discussion)
Tests
common:NeedPrivateZone,NeedIngress, andServiceFQDNunit tests extended with network cases (private/internal network overrides port mode).TestConstructProjectPrivateNetworkIngressStaysPrivate— an ingress service in a private network gets no public zone/cert but does get a private zone. Existing zone tests updated for the conditional behavior.Verification (local, bootstrapped Go 1.26.5 + golangci-lint 2.11.4)
go build ./provider/...✅ ·go test ./provider/...✅ ·cd tests && go test -short ./...(AWS+GCP+Azure) ✅ ·golangci-lint run --config=.golangci.yaml ./provider/...→0 issues✅. No provider input/output schema fields changed (only internalSharedInfra+ function params), so no SDK/schema drift is expected; CI's schema/SDK job is the backstop.🤖 Generated with Claude Code