Lesson 07 of 15 · Traffic Security
Ingress controllers & TLS
Expose HTTP services securely with Ingress: controllers and IngressClasses, TLS termination with cert-manager certificates, passthrough and re-encryption, secure defaults, and choosing a maintained controller.
Ingress in one picture
An Ingress is a set of HTTP routing rules (host + path → Service). An ingress controller (a reverse proxy running in the cluster) reads them and does the actual work: accepting traffic, terminating TLS, and forwarding to pods.
client ──HTTPS──► load balancer ──► ingress controller (TLS, routing) ──► Service ──► pods
The Ingress controller is the receptionist of a large office building with one front door. Visitors say who they're visiting ("shop.example.com, the orders department"), the receptionist checks the building's security badge (the TLS certificate) and walks them to the right office (the Service). The Ingress rules are the receptionist's directory.
Choosing a controller
Many controllers implement Ingress: Traefik, HAProxy, NGINX-based controllers from vendors, Contour, cloud load-balancer controllers, and service meshes. The Ingress API itself is stable but frozen: new features go into the Gateway API (next lesson).
Check your controller is maintained
The community ingress-nginx controller, long the most common choice, was retired after an announcement in late 2025. If you run it, plan a migration to a maintained controller or a Gateway API implementation. For new platforms, prefer Gateway API where your controller supports it.
A secure Ingress with cert-manager
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
namespace: shop
annotations:
cert-manager.io/cluster-issuer: platform-ca # or letsencrypt-prod (lesson 02)
spec:
ingressClassName: traefik
tls:
- hosts: [ "shop.example.com" ]
secretName: shop-example-com-tls # cert-manager creates and renews it
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
Most controllers redirect HTTP → HTTPS when TLS is configured, or offer a setting or middleware for it. Also enable HSTS (Strict-Transport-Security) for public sites, via your controller's middleware or annotations.
Termination, passthrough, re-encryption
| Mode | TLS ends at | Routing by | Use when |
|---|---|---|---|
| Termination | Ingress controller | Host + path | Most web apps |
| Re-encryption | Controller, then TLS again to the backend | Host + path | Traffic inside the cluster must stay encrypted |
| Passthrough | The backend pod | Host only (SNI) | The backend must hold the key (e.g. strict compliance) |
Passthrough and backend-TLS settings are controller-specific (annotations, or CRDs such as Traefik's IngressRouteTCP). Gateway API standardises these (TLSRoute, backend TLS policy).
Secure defaults to check
- TLS 1.2+ only, modern cipher suites (controller defaults are usually good; verify with a TLS scanner).
- Certificates from cert-manager, monitored for expiry.
- Request size and timeout limits to reduce abuse.
- Only the controller is exposed publicly; backends are ClusterIP Services.
- The controller's own admin dashboard or metrics endpoint is not exposed publicly.
Try it: HTTPS on kind with Traefik
- Install Traefik:
helm repo add traefik https://traefik.github.io/charts && helm install traefik traefik/traefik -n traefik --create-namespace. - Deploy the
webapp and Service from Kubernetes Administration (lessons 03–04) in namespaceshop. - With cert-manager and the
platform-caissuer from lesson 02, apply the Ingress above (hostshop.example.com). - Port-forward the controller:
kubectl -n traefik port-forward svc/traefik 8443:443, then test:curl -vk --resolve shop.example.com:8443:127.0.0.1 https://shop.example.com:8443/. Which certificate subject do you see? - Delete the TLS Secret and watch cert-manager recreate it; confirm the served certificate's dates changed.
Going deeper: ingress in production
- Run the controller with multiple replicas, a PodDisruptionBudget, and anti-affinity across nodes and zones. It's in the path of every request.
- Put a WAF or cloud edge (DDoS protection, bot filtering) in front of public ingress where risk justifies it.
- Rate limiting and authentication (OIDC via an auth proxy) can be added at the ingress layer for internal tools.
- Keep a clear ownership split: the platform team runs controllers and certificates; app teams own their Ingress or Route objects. Gateway API makes this split explicit.
Recap
- Ingress = routing rules; the controller does the work; IngressClass decides which controller.
- TLS: termination (common), re-encryption, or passthrough; certificates from cert-manager.
- Test with
--resolveandopenssl s_client -servernameto see what each host serves. - Pick a maintained controller; prefer Gateway API for new designs.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.