Lesson 20 of 32 · Level 3 — Application delivery
Ingress & egress gateways
Control how traffic enters and leaves the cluster: an ingress gateway with the Gateway API, default-deny egress with NetworkPolicies, and egress gateways that give outbound traffic a fixed, audited exit point, plus a guide for choosing the right tool at each step.
Entry and exit points
So far, traffic came in through an Ingress (lessons 05–19), and pods could call anything outside. In production you want both directions controlled:
- Ingress gateway: the single, well-configured entry point (TLS, routing, auth, rate limits).
- Egress control: pods may only reach what they need; sensitive destinations go through an egress gateway with a fixed IP and logs.
A school has a main gate where visitors sign in (ingress gateway). Children can't just wander off the grounds either: to go out on a trip, they leave through the school office with a teacher (egress gateway), so the school knows who left, when, and where they went. Side gates stay locked (default-deny egress).
Ingress gateway with the Gateway API
The Gateway API is the successor to Ingress, implemented by many controllers (Envoy Gateway, Istio, Cilium, NGINX Gateway Fabric, Traefik, Kong and others).
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public
namespace: gateway-infra # owned by the platform team
spec:
gatewayClassName: example-gc # provided by your chosen implementation
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs: [ { name: wildcard-example-com } ]
allowedRoutes:
namespaces: { from: All }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: podinfo
namespace: shop-web # owned by the app team
spec:
parentRefs: [ { name: public, namespace: gateway-infra } ]
hostnames: [ "podinfo.example.com" ]
rules:
- matches: [ { path: { type: PathPrefix, value: / } } ]
backendRefs: [ { name: podinfo, port: 80 } ]
The platform owns the Gateway (addresses, certificates, which namespaces may attach); app teams own their HTTPRoutes. Traffic splitting, header matching, redirects and more are part of the standard API. More in Kubernetes Security & Hardening, lesson 08.
Egress, step 1: default-deny with NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: shop-web
spec:
podSelector: {}
policyTypes: [ Egress ]
egress:
- to: # allow DNS, or nothing resolves
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: kube-system }
podSelector:
matchLabels: { k8s-app: kube-dns }
ports:
- { protocol: UDP, port: 53 }
- { protocol: TCP, port: 53 }
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-to-postgres
namespace: shop-web
spec:
podSelector:
matchLabels: { tier: api }
policyTypes: [ Egress ]
egress:
- to:
- namespaceSelector:
matchLabels: { kubernetes.io/metadata.name: shop-data }
podSelector:
matchLabels: { app: postgres }
ports: [ { protocol: TCP, port: 5432 } ]
Standard NetworkPolicies select destinations by pods, namespaces and IP ranges (ipBlock), not by DNS names. To allow api.partner.example by name, you need CNI extensions such as Cilium's toFQDNs rules (or equivalents in other CNIs).
Egress, step 2: an egress gateway
An egress gateway sends selected outbound traffic through specific nodes or proxies:
- a fixed source IP that partners and firewalls can allow-list,
- one place for logging, TLS origination and policy,
- no need to open firewalls for every node.
| Option | How it works | Choose when |
|---|---|---|
| Cilium Egress Gateway | CiliumEgressGatewayPolicy sends matching pod traffic out via chosen gateway nodes with a fixed egress IP |
You run Cilium; need fixed IPs at L3/L4 |
| Istio egress gateway | Mesh traffic to external hosts (declared with ServiceEntry) is routed through an Envoy egress gateway |
You run Istio; want L7 control and logs (see Service Mesh — Istio & Linkerd) |
| Outbound proxy / NAT gateway | Pods use an HTTP(S) proxy, or the network NATs to a fixed IP | Simple, CNI-independent; less per-pod granularity |
A Cilium example (check field names against your Cilium version):
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: partner-api
spec:
selectors:
- podSelector:
matchLabels: { app: payments, io.kubernetes.pod.namespace: shop-web }
destinationCIDRs: [ "198.51.100.0/24" ] # the partner's API range
egressGateway:
nodeSelector:
matchLabels: { egress-gateway: "true" }
egressIP: 10.0.0.250
Where to choose what
| Need | Start with |
|---|---|
| Expose HTTP apps with TLS | Ingress (lesson 05) or, for new platforms, a Gateway API implementation |
| Stop pods calling anything they like | Default-deny egress NetworkPolicies + explicit allows |
| Allow external services by DNS name | CNI FQDN policies (e.g. Cilium) or an egress proxy |
| Fixed source IP for partners/firewalls | Egress gateway (Cilium/Istio) or NAT gateway/proxy |
| L7 control and audit of outbound calls | Istio egress gateway or an outbound proxy |
Try it: in and out
- Install the Gateway API CRDs and one implementation (e.g. Envoy Gateway's quick start), create a Gateway and an HTTPRoute for podinfo, and reach it.
- On a cluster with an enforcing CNI, apply the default-deny egress policy without the DNS rule and watch
nslookupfail; add the DNS rule back. - Allow
tier: apipods to reach only postgres; confirm other egress fails (wgetto an external site). - (Cilium lab) Label a node as egress gateway and apply an egress gateway policy; check the source IP seen by an external echo service.
- For one real app, list every outbound destination it needs, and draft its egress policy.
Going deeper: traffic governance
- Keep ingress and egress policies in Git with the app; review new egress destinations like firewall changes.
- Monitor denied flows (Cilium Hubble, Calico flow logs) to catch missing rules before users do.
- Egress gateways are critical paths: run more than one, and know their failover behaviour.
Recap
- Ingress gateway: one controlled entry point; the Gateway API separates platform-owned Gateways from team-owned Routes.
- Egress: start with default-deny + DNS + explicit allows; standard policies can't match DNS names.
- Egress gateways (Cilium, Istio, proxies/NAT) give a fixed source IP, logging and policy.
- Choose by need: exposure, restriction, FQDN rules, fixed IP, L7 audit.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.