Назад | Перейти на главную страницу

nginx use-proxy-protocol с кластером Kubernetes

У меня есть кластер Kubernetes с внешним балансировщиком нагрузки на собственном сервере под управлением NGINX. Я пытался активировать proxy_protocol чтобы получить real_ip клиентов, но журналы NGINX

2020/05/11 14:57:54 [error] 29614#29614: *1325 broken header: "▒▒▒▒▒▒▒Ωߑa"5▒li<c▒*▒ ▒▒▒s▒       ▒6▒▒▒▒▒X▒▒o▒▒▒E▒▒i▒{ ▒/▒0▒+▒,̨̩▒▒ ▒▒
▒▒/5▒" while reading PROXY protocol, client: 51.178.168.233, server: 0.0.0.0:443

Вот мой файл конфигурации NGINX:

worker_processes 4;
worker_rlimit_nofile 40000;

events {
    worker_connections 8192;
}

stream {

    upstream rancher_servers_http {
        least_conn;
        server <IP_NODE_1>:80 max_fails=3 fail_timeout=5s;
        server <IP_NODE_2>:80 max_fails=3 fail_timeout=5s;
        server <IP_NODE_3>:80 max_fails=3 fail_timeout=5s;
    }
    server {
        listen     80;
        proxy_protocol on;
        proxy_pass rancher_servers_http;
    }

    upstream rancher_servers_https {
        least_conn;
        server <IP_NODE_1>:443 max_fails=3 fail_timeout=5s;
        server <IP_NODE_2>:443 max_fails=3 fail_timeout=5s;
        server <IP_NODE_3>:443 max_fails=3 fail_timeout=5s;
    }

    server {
        listen     443 ssl proxy_protocol;
        ssl_certificate /certs/fullchain.pem;
        ssl_certificate_key /certs/privkey.pem;
        proxy_pass rancher_servers_https;
        proxy_protocol on;
    }
}

Вот мой configmap для ingress-контроллера:

apiVersion: v1
data:
  compute-full-forwarded-for: "true"
  proxy-body-size: 500M
  proxy-protocol: "true"
  use-forwarded-headers: "true"
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: '{"apiVersion":"v1","data":null,"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app":"ingress-nginx"},"name":"nginx-configuration","namespace":"ingress-nginx"}}'
  creationTimestamp: "2019-12-09T13:26:59Z"
  labels:
    app: ingress-nginx
  name: nginx-configuration
  namespace: ingress-nginx

Все работало нормально, прежде чем я добавил proxy_protocol директива, но теперь я получил все эти broken headers ошибок, и я не могу получить доступ к службам за входящими данными, не получив connection reset ошибка.

Что может быть не так с моей конфигурацией?

Должен ли я использовать обратный прокси-сервер http вместо обратного прокси-сервера tcp?

Спасибо.


редактировать:

Я также должен сказать, что у меня нет службы типа LoadBalancer в моем кластере. Должен ли я иметь один? Я думаю о Metallb, но не уверен, что он добавит в мою конфигурацию, поскольку я уже балансирую нагрузку на узлы с помощью nginx.

Nginx позволяет указать, использовать ли proxy_protocol во входящих или исходящих запросах, и вы их запутаете.

Чтобы использовать proxy_protocol в входящий соединения, вы должны добавить proxy_protocol к listen строка вроде этой:

listen     443 ssl proxy_protocol;

Чтобы использовать proxy_protocol в исходящий подключений, вы должны использовать автономный proxy_protocol директива, например:

proxy_protocol on;

Они есть не тот же самый. В балансировщике нагрузки входящий подключения происходят из браузеров, которые не поддерживают протокол прокси. Вам нужен протокол прокси только в исходящих запросах к nginx-ingress в вашем кластере kubernetes.

Поэтому удалите proxy_protocol аргумент от listen директива, и она должна работать.

Кроме того, вы хотите use-forwarded-headers: "false" в вашей конфигурации nginx-ingress. Это контролирует, использовать ли X-Forwarded-For & co. заголовки в входящий подключения (с точки зрения nginx-ingress, т.е. исходящий из вашего балансировщика нагрузки), и вы используете в них протокол прокси вместо заголовков. Если он включен, ваши пользователи могут иметь возможность подделывать IP-адреса, указав X-Forwarded-For, что может быть проблемой безопасности. (только если nginx-ingress отдает приоритет заголовкам над протоколом прокси, в чем я не уверен)

Замечу: сам nginx-ingress уже распределяет нагрузку между всеми модулями. В вашей архитектуре вы используете два «уровня» балансировщиков нагрузки, что, вероятно, не нужно. Если вы хотите упростить, принудительно запускайте nginx-ingress на одном узле (с nodeSelector например) и просто отправьте весь свой трафик на этот узел. Если вы хотите сохранить балансировщик нагрузки на выделенной машине, вы можете присоединить 4-ю машину к кластеру и убедиться, что она просто запускает nginx-ingress (с ошибками и допусками).

Кроме того, убедитесь, что вы запускаете nginx-ingress с hostNetwork: true, иначе у вас может быть еще один уровень балансировки (kube-proxy, прокси-сервер kubernetes)