Skip to content

feat(api): add NetworkEgressPolicy and NetworkGatewayStatus.EgressAddress - #15

Merged
privateip merged 2 commits into
mainfrom
feat/865-networkegresspolicy-crd
Aug 14, 2026
Merged

feat(api): add NetworkEgressPolicy and NetworkGatewayStatus.EgressAddress#15
privateip merged 2 commits into
mainfrom
feat/865-networkegresspolicy-crd

Conversation

@privateip

Copy link
Copy Markdown
Collaborator

Summary

Phase A of datum-cloud/enhancements#865 (NAT masquerade egress for the edge gateway), per docs/plans/865-edge-gateway-nat66-egress.md §4.1 in the galactic repo.

  • New NetworkEgressPolicy type — namespaced, tenant-writable, gated by the same ownership-verification admission webhook NetworkRule already requires. Carries only vpcRef/vpcAttachmentRef (existence-implies-enabled) — no VIP/backend/port, since egress destinations are arbitrary internet addresses, not a pre-configured backend list.
  • NetworkGatewayStatus.EgressAddress — the publicly-routable masquerade SNAT source, populated/advertised the same way SRv6Address already is. Optional independently of SRv6Address; a gateway node not offering egress leaves it empty.
  • Regenerated deepcopy methods, CRD manifests, and API docs via task generate.
  • Scoped .crd-ref-docs.yaml so the new type renders only into gateway.md, matching how NetworkGateway/NetworkRule are already excluded from bgp.md.

Testing

  • go build ./..., go vet ./..., go test ./api/... — all pass.
  • task lint — 0 issues.

Notes for reviewers

  • config/crd/kustomization.yaml was already missing bgpcommunitysets, bgpprefixlists, networkgateways, and networkrules before this PR — pre-existing gap, not introduced here. I only added my own new entry; happy to fix the rest in a follow-up if wanted.
  • This PR needs to merge and be tagged before datum-cloud/galactic's consuming PR can drop its temporary local replace directive — see that PR's description.

🤖 Generated with Claude Code

…ress

Phase A of datum-cloud/enhancements#865 (NAT masquerade egress for the
edge gateway), per docs/plans/865-edge-gateway-nat66-egress.md in the
galactic repo.

NetworkEgressPolicy is a new namespaced, tenant-writable type enabling
internet egress for a single VPC/VPCAttachment. Unlike NetworkRule it
carries no VIP/backend/port: egress is on or off for a (vpcRef,
vpcAttachmentRef) pair, existence-implies-enabled, mirroring how sparse
NetworkRuleSpec already keeps those two fields as opaque,
unvalidated-by-this-API identifiers gated by the same
ownership-verification admission webhook.

NetworkGatewayStatus gains EgressAddress, the publicly-routable
masquerade SNAT source, populated and advertised the same way
SRv6Address already is. Both fields are optional independently — a
gateway node not offering egress is a valid deployment.

Regenerated deepcopy methods, CRD manifests, and API docs via `task
generate`. Scoped .crd-ref-docs.yaml so NetworkEgressPolicy only
renders into gateway.md, matching how NetworkGateway/NetworkRule are
already excluded from bgp.md.
scotwells
scotwells previously approved these changes Aug 13, 2026
…Status.AssignedGatewayNode

Phase D of #865, per docs/plans/865-edge-gateway-nat66-egress.md §4.4/§4.5.

Neither field is in the plan's own text -- both surfaced as necessary
once Phase D's controller was actually implemented:

- EgressSID publishes a gateway node's egress_sid locator the same way
  SRv6Address/EgressAddress already are. Without it, no compute node
  has a kernel route to encapsulate toward: RouteEgressAdd requires
  one to already exist via BGP/EVPN, the same requirement
  SRv6Address's own advertisement already satisfies.

- AssignedGatewayNode mirrors NetworkRuleStatus.PrimaryNode's set-once
  contract for the identical reason: a route reconciler that
  recomputes AssignPrimaryNode on every pass would flap a tenant's
  egress node whenever the gateway-node pool changes, exactly what
  PrimaryNode's own doc comment warns against for ingress.
@privateip

Copy link
Copy Markdown
Collaborator Author

Added in a follow-up commit (Phase D, #865): NetworkGatewayStatus.EgressSID and NetworkEgressPolicyStatus.AssignedGatewayNode. Neither is in the plan's original text — both surfaced as necessary once Phase D's route reconciler was actually implemented. See that commit message for the full reasoning.

@privateip
privateip merged commit 96677d6 into main Aug 14, 2026
5 checks passed
@privateip
privateip deleted the feat/865-networkegresspolicy-crd branch August 14, 2026 00:19
privateip added a commit to datum-cloud/galactic that referenced this pull request Aug 14, 2026
datum-cloud/network#15 (NetworkEgressPolicy, NetworkGatewayStatus.
EgressAddress) merged to main at 96677d6. Replace the local ../network
replace directive from 35d009c with a real pseudo-version pinned to
that commit; drop the replace now that it's no longer dev-only.

No tag has been cut yet, so this is still a pseudo-version rather than
a semver tag — bump to a tag once one exists.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
privateip added a commit to datum-cloud/galactic that referenced this pull request Aug 14, 2026
Phase E of #865, per docs/plans/865-edge-gateway-nat66-egress.md §6/§8.

Fixed first, found by trying to wire this up: config/gateway/rbac.yaml
and config/router/rbac.yaml never granted access to
networkegresspolicies (or, for galactic-router, networkgateways) --
Phase D's two new reconcilers would hit RBAC-forbidden errors in any
real deployment, not just this lab.

Lab wiring:
- GALACTIC_GATEWAY_EGRESS_ADDRESS/_SID on both gateway nodes.
  egress_sid reuses each node's own ingress locator (only the top 64
  bits are ever compared). masq_addr is a new, dedicated loopback
  address, not a reuse of the node's existing BGP-session address --
  reusing it would make the fail-closed egress-return dispatch also
  claim and drop the node's own inbound BGP TCP traffic.
- NetworkEgressPolicy for ns10's iad attachment (not ns60, the
  ingress canary -- ns60 runs nginx, no ping; ns10 runs netshoot).
  Only ns10's iad pod can egress in this lab: each site is a separate
  Kind cluster, so NetworkGateway/NetworkEgressPolicy only exist
  where iad's own cluster can see them.
- scripts/verify-egress.sh + task verify:egress: pings tr1's own
  loopback (already BGP-announced, outside any SRv6/uSID space) from
  ns10's iad pod.
- deploy-system.sh's CRD-install list was missing
  networkegresspolicies entirely -- fixed.

Telemetry/quota: confirmed, not added. edgemetrics.Collector iterates
DropReasonCount/DropReasonNames generically, so Phase B's new egress
drop reasons are already exposed with no changes here.
QuotaEnforcer/TelemetryEmitter stay Noop per the plan's own Phase E
deferral.

Not run live: bringing up three Kind clusters plus the full FRR/BGP
mesh is a multi-minute operation not attempted in this session.
Validated instead with `kubectl kustomize` against config/gateway/,
config/router/, and (after simulating the deploy-time docker cp step)
the affected lab overlays -- all build clean. The lab also can't
fully deploy until datum-cloud/network#15 merges and tags: deploy-
system.sh pulls CRDs from the tagged upstream repo, not this
session's local checkout.
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.

Design: NetworkEgressPolicy CRD + gateway egress status fields (865 Phase A)

2 participants