Korzen
Bot Protection

Kubernetes

Bot Protection vanuit een app op Kubernetes: de API key als Secret, het IP-adres van de bezoeker via de load balancer en ingress-nginx, en egress.

Kubernetes verandert drie dingen aan de call vanaf je server: waar de API key staat, hoe het adres van de bezoeker de load balancer en de ingress overleeft, en of de pod korzen.dev überhaupt mag bereiken. De call zelf is die van je framework: neem hem over uit de gids voor jouw stack.

De key

Bewaar de API key in een Secret, nooit in de image of een ConfigMap, en geef hem als omgevingsvariabele aan de container:

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

Het IP-adres van de bezoeker

Standaard verbergt een cloud load balancer de bezoeker achter zijn eigen adres, en de ingress doet hetzelfde. Twee instellingen houden het adres vast: externalTrafficPolicy: Local op de Service van de ingress controller, en ingress-nginx die de header vertrouwt die de load balancer toevoegt. Je applicatie leest dan X-Real-IP, of de laatste entry van X-Forwarded-For, die ingress-nginx zet; achter 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

Blokkeert het cluster standaard uitgaand verkeer vanuit een namespace, dan moet de pod poort 443 mogen bereiken:

# 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

In productie

  • Eén HTTP-client per pod, die openblijft; elke replica opent zijn eigen verbinding, en dat is prima.
  • Laat een readiness- of liveness-probe nooit afhangen van Bot Protection: als dat traag is, moeten de pods in dienst blijven en fail-open werken.
  • De timeout van je SDK rekent vanaf waar het cluster draait: een cluster in het westen van de VS heeft ongeveer 300 ms nodig.

Veelgemaakte fouten

  • Het eigen adres van de ingress doorsturen als dat van de bezoeker: alle beslissingen delen dan één IP-adres, en Bot Protection ziet één heel drukke bezoeker.
  • use-forwarded-headers aan zonder dat er iets voor staat dat jij beheert: een bezoeker schrijft X-Forwarded-For en kiest zijn eigen adres.
  • De key in een ConfigMap of ingebakken in de image, waar iedereen met leestoegang tot de namespace of de registry hem ziet.