Okt 14, 2020 | Kubernetes, Tutorial

X-Forwarded-For und Proxy-Protocol

von

Du willst wissen wie Du in Deinem Kubernetes Cluster an die IP-Adressen Deiner Clients kommst? In fünf Minuten hast Du den Überblick!

Vom HTTP-Client zur Anwendung

Im Tutorial zum nginx-Ingress-Controller zeigen wir wie man eine Anwendung öffentlich erreichbar macht. Im Fall der NETWAYS Cloud bedient sich dein Kubernetes Cluster an einem Openstack-Loadbalancer, welcher die Client-Anfragen an einen nginx-Ingress-Controller im Kubernetes Cluster weitersendet. Dieser verteilt dann alle Anfragen an die entsprechenden Pods. Bei all dem Herumschieben und Weiterleiten der Anfragen gehen ohne weitere Konfiguration die Verbindungsdetails der Clients verloren. Da das Problem nicht erst seit Kubernetes auftritt, wird auf die alt bewährten Lösungen X-Forwarded-For oder Proxy-Protocol zurückgegriffen. Um im Buzzword-Bingo zwischen Service, Loadbalancer, Ingress, Proxy, Client und Anwendung nicht die Übersicht zu verlieren, kannst Du Dir im folgenden Beispiel den Weg einer HTTP-Anfrage vom Client bis zur Anwendung durch die Komponenten eines Kubernetes Clusters ansehen. Der Weg vom HTTP-Request zur Anwendung im Kubernetes-Cluster  

Client IP-Adressen mit X-Forwarded-For

Verwendest Du HTTP, kann die Client IP-Adresse im X-Forwarded-For (XFF) gespeichert und weiter transportiert werden. XFF ist ein Eintrag im HTTP-Header und wird von den meisten Proxy-Servern unterstützt. Im Beispiel setzt der Loadbalancer dazu die Client-IP-Adresse in den XFF-Eintrag und schickt die Anfrage weiter. Alle weiteren Proxy-Server und die Anwendungen können dadurch im XFF-Eintrag erkennen, von welcher Adresse die Anfrage ursprünglich gesendet wurde. In Kubernetes konfiguriert man den Loadbalancer über Annotations im Service Objekt. Setzt man dort loadbalancer.openstack.org/x-forwarded-for: true wird der Loadbalancer entsprechend konfiguriert. Wichtig ist jetzt natürlich auch noch, dass der nächste Proxy den X-Forwarded-For Header nicht wieder überschreibt. Im Fall eines nginx kann man dazu die Option use-forwarded-headers in dessen ConfigMap setzen.  

---
# Service
kind: Service
apiVersion: v1
metadata:
  name: loadbalanced-service
  annotations:
    loadbalancer.openstack.org/x-forwarded-for: "true"
spec:
  selector:
    app: echoserver
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
---
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx
data:
  use-forwarded-headers: "true"

 

 

Da der HTTP-Header verwendet wird, ist es nicht möglich HTTPS-Verbindungen mit der Client-IP-Adresse anzureichern. Hier muss man entweder das TLS/SSL-Protokoll am Loadbalancer terminieren oder auf das Proxy-Protocol zurückgreifen.  

Client-Informationen mit Proxy-Protocol

Verwendet man X-Forwarded-For ist man offensichtlich auf HTTP beschränkt. Um auch HTTPS und anderen Anwendungen hinter Loadbalancern und Proxys den Zugriff auf die Verbindungsoption der Clients zu ermöglichen, wurde das sogenannte Proxy-Protocol erfunden. Technisch wird dazu vom Loadbalancer ein kleiner Header mit den Verbindungsinformationen des Clients hinzugefügt. Der nächste Hop (hier nginx) muss natürlich ebenfalls das Protokoll verstehen und entsprechend behandeln. Neben klassischen Proxys unterstützten auch andere Anwendungen wie MariaDB oder postfix das Proxy-Protocol. Um das Proxy-Protocol zu aktivieren, musst Du das Service Objekt mit der Annotation loadbalancer.openstack.org/proxy-protocol versehen. Für den annehmenden Proxy muss das Protocol ebenfalls aktiviert werden. 

---
# Service Loadbalancer
kind: Service
apiVersion: v1
metadata:
  name: loadbalanced-service
  annotations:
    loadbalancer.openstack.org/proxy-protocol: "true"
spec:
  selector:
    app: echoserver
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
---
# NGINX ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx
data:
  use-proxy-protocol: "true"

 

In den meisten Fällen wirst Du aber auf das Helm-Chart des nginx-Ingress-Controller zurückgreifen. Dort ist eine entsprechende Konfiguration sogar noch einfacher.  

nginx-Ingress-Controller und Helm

Benutzt man Helm, um den nginx-ingress-controller zu installieren, ist die Konfiguration sehr übersichtlich. Das Proxy-Protocol wird über die eine Helm-Values-Datei sowohl für den nginx als auch für den Loadbalancer aktiviert: nginx-ingress.values: 

---
controller:
  config:
    use-proxy-protocol: "true"
  service:
    annotations:
      loadbalancer.openstack.org/proxy-protocol: true
    type: LoadBalancer 
$ helm install my-ingress stable/nginx-ingress -f nginx-ingress.values

 

Ob alles so funktioniert wie erwartet, kannst Du am einfachsten mit Hilfe des Google Echoserver testen. Dabei handelt sich um eine kleine Anwendung, die den HTTP-Request einfach an den Client zurück gibt. Wie im Tutorial zum nginx-Ingress-Controller beschrieben, benötigen wir dazu ein Deployment mit Service und Ingress. Ersteres startet den Echoserver, der Service macht diesen im Cluster erreichbar und der Ingress konfiguriert den nginx so, dass die Requests an das Deployment weitergeleitet werden. 

---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echoserver
spec:
  selector:
    matchLabels:
      app: echoserver
  replicas: 1
  template:
    metadata:
      labels:
        app: echoserver
    spec:
      containers:
      - name: echoserver
        image: gcr.io/google-containers/echoserver:1.8
        ports:
          - containerPort: 8080
---
# Service
apiVersion: v1
kind: Service
metadata:
  name: echoserver-svc
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: echoserver
---
# Ingress
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: echoserver-ingress
spec:
  rules:
  - host: echoserver.nws.netways.de
    http:
      paths:
        - backend:
            serviceName: echoserver-svc
            servicePort: 80

Zum Testen fakest Du am besten noch deine /etc/hosts damit echoserver.nws.netways.de auf die öffentlichen IP-Adresse deines nginx-Ingress-Controller deutet. curl echoserver.nws.netways.de zeigt dir dann alles an, was der Echoserver von Deinem Client weiß, inklusive der IP-Adresse im X-Forwarded-For Header.  

Fazit

Im Kubernetes Cluster ist das Proxy-Protocol für die meisten Anwendungsfälle wohl die bessere Wahl. Die bekannten Ingress-Controller unterstützen das Proxy-Protocol und TLS/SSL-Verbindungen können im K8s-Cluster konfiguriert und terminiert werden. Welche Informationen bei Deiner Anwendung ankommen, findest Du am schnellsten mit Googles Echoserver raus.

Erhalte den nächsten Artikel

Mehr Artikel in Kubernetes | Tutorial
Ingress-NGINX mit Cert-Manager absichern

Ingress-NGINX mit Cert-Manager absichern

In einem der ersten Tutorials auf unserer Seite haben wir dir gezeigt, wie du Ingress-NGINX in deinem Cluster installieren und einrichten kannst. Heute gehen wir einen Schritt weiter und schauen uns an, wie du Ingress-NGINX und deine Services mit Hilfe von...

Migration von Servern auf VMware zu OpenStack

Migration von Servern auf VMware zu OpenStack

In diesem Tutorial befassen wir uns mit der Migration von Servern auf VMware zu OpenStack. Nach der kürzlichen Übernahme VMwares durch Broadcom haben in den vergangenen Wochen viele kleinere Cloud Service Provider (CSPs) Mitteilung zur Kündigung ihrer Mitgliedschaft...

Meistere Kubernetes mit Cilium: Traffic Filterung auf L7 Basis

Meistere Kubernetes mit Cilium: Traffic Filterung auf L7 Basis

Mit der neuen Version des Cilium CNI auf unserem Kubernetes-Service erhältst Du die Möglichkeit, den Datenverkehr anhand von L7-Eigenschaften zu filtern. Das ist normalerweise Service-Meshes vorbehalten und kann bei der Sicherheit deiner Dienste sehr hilfreich sein....

Terraform und OpenStack

Terraform und OpenStack

Viele von Euch sind vermutlich bereits mit der Verwendung von Terraform in Kombination mit Azure oder AWS vertraut. Und obwohl dies die am häufigsten verwendeten Plattformen sind, gibt es - oftmals im Bezug auf Datenschutz (DSGVO) - Unwägbarkeiten und somit weiterhin...

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Dynamic Inventory – Eine Ansible und OpenStack Lovestory

Für diejenigen unter euch, die mit Ansible möglicherweise nicht allzu vertraut sind: Es ist ein großartiges Tool, um in die Welt der Automatisierung einzusteigen und erleichtert euer Leben im Konfigurationsmanagement erheblich.   Die Kennenlernphase In diesem Tutorial...

ReadWriteMany (RWX) mit dem NFS Ganesha Provisioner

ReadWriteMany (RWX) mit dem NFS Ganesha Provisioner

Einführung Du hast die Anforderung, dass Deine Anwendung für eine Lastverteilung über mehrere Nodes skalieren muss, aber Zugriff auf ein gemeines PVC benötigt? Zu diesem Zweck benötigst Du ein PVC welches RWX-fähig ist. Im Rahmen unserer Managed Kubernetes Cluster ist...

Persistente Volumes in Kubernetes vergrößern

Persistente Volumes in Kubernetes vergrößern

Du willst ein PersistentVolume (PV) in Kubernetes vergrößern? In diesem Blogeintrag erfährst du wie das funktioniert. Was PVs sind und wie man diese anlegt wird im Tutorial Persistente Volumes in Kubernetes erstellen erklärt, auf welchem das vorliegende Tutorial...

Wie Du Deine NETWAYS Managed Database startest

Wie Du Deine NETWAYS Managed Database startest

Im ersten Tutorial hat Sebastian bereits erklärt, was es mit Vitess auf sich hat und welche Möglichkeiten es Dir beim Betrieb Deiner Anwendung, im Vergleich zu einer gewöhnlichen Datenbank, bietet. Im folgenden Text möchte ich nun darauf eingehen, wie Du Dir in...

Was ist Vitess?

Was ist Vitess?

Im Jahr 2010 wurde eine Lösung entwickelt, um die massiven Skalierbarkeitsprobleme von MySQL bei YouTube zu lösen - und somit war Vitess geboren. Später - im Jahr 2018 - wurde das Projekt Teil der Cloud Native Computing Foundation und ist seit 2019 als eines der...