Kubernetes changes three things about the call from your server: where the API key lives, how the visitor's address survives the load balancer and the ingress, and whether the pod may reach korzen.dev at all. The call itself is your framework's: take it from the guide for your stack.
The key
Keep the API key in a Secret, never in the image or a ConfigMap, and hand it to the container as an environment variable:
kubectl create secret generic korzen --from-literal=api-key=ak_your_key
# deployment.yaml, in your app's container env: - name: KORZEN_API_KEY valueFrom: secretKeyRef: name: korzen key: api-key
The visitor's IP
By default a cloud load balancer hides the visitor behind its own address, and so does the ingress. Two settings keep it: externalTrafficPolicy: Local on the ingress controller's Service, and ingress-nginx trusting the header the load balancer adds. Your application then reads X-Real-IP, or the last entry of X-Forwarded-For, which ingress-nginx sets; behind Cloudflare, CF-Connecting-IP.
# The ingress controller's Service: keep the visitor's address on the way in. apiVersion: v1 kind: Service metadata: name: ingress-nginx-controller namespace: ingress-nginx spec: type: LoadBalancer externalTrafficPolicy: Local
# ingress-nginx's ConfigMap: trust the load balancer in front, pass the address on. apiVersion: v1 kind: ConfigMap metadata: name: ingress-nginx-controller namespace: ingress-nginx data: use-forwarded-headers: "true" # only if a load balancer you control is in front compute-full-forwarded-for: "true" # use-proxy-protocol: "true" # instead, if your cloud's load balancer speaks PROXY protocol
Egress
If the cluster blocks traffic out of a namespace by default, the pod must be allowed to reach port 443:
# Only if your cluster blocks egress by default: let the app reach HTTPS. # A plain NetworkPolicy matches addresses, not names, and korzen.dev answers from # Cloudflare's ranges; with Cilium, an FQDN rule can name korzen.dev itself. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: app-egress-https spec: podSelector: matchLabels: app: shop policyTypes: [Egress] egress: - ports: - port: 443 protocol: TCP - ports: - port: 53 protocol: UDP
Running it
- One HTTP client per pod, kept open; every replica opens its own connection, which is fine.
- Never make a readiness or liveness probe depend on Bot Protection: when it is slow, the pods must stay in service and fail open.
- Your SDK's timeout counts from where the cluster runs: a cluster in the US west needs about 300 ms.
Common mistakes
- The ingress's own address sent as the visitor's: every decision then shares one IP, and Bot Protection sees one very busy visitor.
use-forwarded-headerson with nothing in front that you control: a visitor writesX-Forwarded-Forand picks their address.- The key in a ConfigMap or baked into the image, where anyone with read access to the namespace or the registry sees it.