nginx-ingress: слишком много перенаправлений при включенном force-ssl

Я настраиваю свой первый вход в кубернетах с помощью nginx-ingress. Я настроил службу балансировки нагрузки ingress-nginx следующим образом:

{
  "kind": "Service",
  "apiVersion": "v1",
  "metadata": {
    "name": "ingress-nginx",
    "namespace": "...",
    "labels": {
      "k8s-addon": "ingress-nginx.addons.k8s.io"
    },
    "annotations": {     
      "service.beta.kubernetes.io/aws-load-balancer-backend-protocol": "tcp",
      "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol": "*",
      "service.beta.kubernetes.io/aws-load-balancer-ssl-cert": "arn....",
      "service.beta.kubernetes.io/aws-load-balancer-ssl-ports": "443"
    }
  },
  "spec": {
    "ports": [
      {
        "name": "http",
        "protocol": "TCP",
        "port": 80,
        "targetPort": "http",
        "nodePort": 30591
      },
      {
        "name": "https",
        "protocol": "TCP",
        "port": 443,
        "targetPort": "http",
        "nodePort": 32564
      }
    ],
    "selector": {
      "app": "ingress-nginx"
    },
    "clusterIP": "...",
    "type": "LoadBalancer",
    "sessionAffinity": "None",
    "externalTrafficPolicy": "Cluster"
  },
  "status": {
    "loadBalancer": {
      "ingress": [
        {
          "hostname": "blablala.elb.amazonaws.com"
        }
      ]
    }
  }
}

Обратите внимание, как порт https имеет свойство targetPort, указывающее на порт 80 (http), чтобы завершить SSL на балансировщике нагрузки.

Мой вход выглядит примерно так:

apiVersion: extensions/v1beta1
kind: Ingress
metadata: 
  name: something
  namespace: ...
  annotations:
    ingress.kubernetes.io/ingress.class: "nginx"
    ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  rules:
    - host: www.exapmle.com
      http:
        paths:
         - path: /
           backend:
            serviceName: some-service
            servicePort: 2100

Теперь, когда я перехожу к URL-адресу, я получаю Too many redirects error. Меня смущает то, что когда я добавляю следующий заголовок «X-Forwarded-Proto: https», я получаю ожидаемый ответ (curl https://www.example.com -v -H "X-Forwarded-Proto: https").

Есть идеи, как я могу решить проблему?

P.S. это прекрасно работает с ingress.kubernetes.io/force-ssl-redirect: "false", и не похоже, что есть какие-либо посторонние перенаправления.


person Jonny    schedule 16.04.2018    source источник


Ответы (3)


Это известная проблема с annotation для SSL-перенаправления в сочетании с прокси-протоколом и завершением SSL-соединений на ELB.

Вопрос об этом был опубликован на GitHub, а здесь fix из этой ветки:

  1. Вам следует создать настраиваемую ConfigMap для Nginx-Ingress вместо использования аннотации force-ssl-redirect, как показано ниже:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        app: ingress-nginx
      name: nginx-ingress-configuration
      namespace: <ingress-namespace>
    data:
      ssl-redirect: "false"
      hsts: "true"
      server-tokens: "false"
      http-snippet: |
        server {
          listen 8080 proxy_protocol;
          server_tokens off;
          return 301 https://$host$request_uri;
        }
    

    Эта конфигурация создаст дополнительный слушатель с простым перенаправлением на https.

  2. Затем примените этот ConfigMap к своему входящему контроллеру, добавьте NodePort 8080 к его определению контейнера и к Сервису.
  3. Теперь вы можете указать порт 80 вашего ELB на порт 8080 службы.

С этим дополнительным слушателем это будет работать.

person Anton Kostenko    schedule 16.04.2018
comment
Зачем слушать 8000 и NodePort 8080? - person Latrova; 26.04.2018
comment
Mistype. Спасибо, в конфиге выставил 8080. - person Anton Kostenko; 27.04.2018
comment
О шаге 2: это должен быть NodePort? Можно мне взамен ClusterIP? - person Latrova; 27.04.2018
comment
На самом деле, это зависит от вашей конфигурации. Дело в том, чтобы заставить его пересылать запросы от клиентов на этот порт с порта http. Это всего лишь небольшой сервер перенаправления, который будет перенаправлять клиента с http://_anything_ на https://the_same_anything_. Больше ничего. - person Anton Kostenko; 27.04.2018
comment
Как мы можем сделать это на уровне входа, только для определенных. Вместо configmap для всего контроллера входа ??? - person Arash; 03.03.2020
comment
как применить это с установкой helm, используя общедоступную диаграмму руля? - person uberrebu; 22.06.2021

Мне пришлось добавить эти аннотации, чтобы он работал без изменения контроллера входа:

    annotations:
      kubernetes.io/ingress.class: nginx-ingress-internal # <- AWS NLB
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/configuration-snippet: |
        if ($http_x_forwarded_proto = 'http') {
          return 301 https://$host$request_uri;
        }
person dpolicastro    schedule 10.12.2020
comment
лучший ответ согласно моему env - person Abdennour TOUMI; 07.03.2021
comment
Это отлично работает и лучше всего подходит для всех сред. - person Vishesh Kumar Singh; 31.03.2021

Другой подход, который работал в моей среде (k8s v1.16.15, rancher / nginx-ingress-controller: nginx-0.32.0-rancher1):

apiVersion: v1
data:
  compute-full-forwarded-for: "true"
  use-forwarded-headers: "true"
kind: ConfigMap
metadata:
  labels:
    app: ingress-nginx
  name: nginx-configuration
  namespace: ingress-nginx

Это работало с force-ssl-redirect при входе приложения. Похоже, что ingress-контроллер из коробки не использует заголовок X-Forwarded-Proto из ELB.

person stipx    schedule 06.10.2020