nginx-ingress:启用 force-ssl 时重定向过多
nginx-ingress: Too many redirects when force-ssl is enabled
我正在使用 nginx-ingress 在 kubernetes 中设置我的第一个入口。我像这样设置 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
。让我感到困惑的是,当我添加以下 header "X-Forwarded-Proto: https" 时,我得到了预期的响应 (curl https://www.example.com -v -H "X-Forwarded-Proto: https"
)。
有什么办法可以解决这个问题吗?
P.S。这与 ingress.kubernetes.io/force-ssl-redirect: "false"
一起工作得很好,而且似乎没有任何无关的重定向。
这是 SSL 重定向结合代理协议和 ELB 上 SSL 连接终止的 annotation
的一个已知问题。
关于它的问题已发布在 GitHub and here is a fix 上来自该线程:
您应该为 Nginx-Ingress 创建自定义 ConfigMap,而不是像下面这样使用 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。
- 然后,将该 ConfigMap 应用于您的入口控制器,将
NodePort
8080 添加到其容器定义和服务中。
- 现在,您可以将ELB的80端口指向Service的8080端口。
有了这个额外的监听器,它就可以工作了。
另一种适用于我的环境的方法(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-controller 似乎没有使用开箱即用的 ELB 中的 X-Forwarded-Proto header。
我不得不添加这些注释以使其在不更改入口控制器的情况下工作:
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;
}
为 Too many redirects error
添加另一个原因。
同时使用 ingress-nginx 作为一些 k8s 服务前面的入口控制器。
其中一项服务(在我的例子中是 ArgoCD)自行处理 TLS 终止,并始终将 HTTP 请求重定向到 HTTPS。
问题是 nginx 入口控制器还处理了 TLS 终止 并使用 HTTP 与后端服务通信,结果是 ArgoCD 的服务器总是响应重定向到 HTTPS这是多次重定向的原因。
任何将相关值传递给入口的尝试下面的注释都无济于事:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: false/true
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"/"HTTPS"
解决方案是通过将 --insecure
标志传递给 argocd-server 部署来确保服务不处理 TLS:
规格:
template:
spec:
containers:
- name: argocd-server
command:
- argocd-server
- --repo-server
- argocd-repo-server:8081
- --insecure # <-- Here
我正在使用 nginx-ingress 在 kubernetes 中设置我的第一个入口。我像这样设置 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
。让我感到困惑的是,当我添加以下 header "X-Forwarded-Proto: https" 时,我得到了预期的响应 (curl https://www.example.com -v -H "X-Forwarded-Proto: https"
)。
有什么办法可以解决这个问题吗?
P.S。这与 ingress.kubernetes.io/force-ssl-redirect: "false"
一起工作得很好,而且似乎没有任何无关的重定向。
这是 SSL 重定向结合代理协议和 ELB 上 SSL 连接终止的 annotation
的一个已知问题。
关于它的问题已发布在 GitHub and here is a fix 上来自该线程:
您应该为 Nginx-Ingress 创建自定义 ConfigMap,而不是像下面这样使用
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。
- 然后,将该 ConfigMap 应用于您的入口控制器,将
NodePort
8080 添加到其容器定义和服务中。 - 现在,您可以将ELB的80端口指向Service的8080端口。
有了这个额外的监听器,它就可以工作了。
另一种适用于我的环境的方法(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-controller 似乎没有使用开箱即用的 ELB 中的 X-Forwarded-Proto header。
我不得不添加这些注释以使其在不更改入口控制器的情况下工作:
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;
}
为 Too many redirects error
添加另一个原因。
同时使用 ingress-nginx 作为一些 k8s 服务前面的入口控制器。
其中一项服务(在我的例子中是 ArgoCD)自行处理 TLS 终止,并始终将 HTTP 请求重定向到 HTTPS。
问题是 nginx 入口控制器还处理了 TLS 终止 并使用 HTTP 与后端服务通信,结果是 ArgoCD 的服务器总是响应重定向到 HTTPS这是多次重定向的原因。
任何将相关值传递给入口的尝试下面的注释都无济于事:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: false/true
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"/"HTTPS"
解决方案是通过将 --insecure
标志传递给 argocd-server 部署来确保服务不处理 TLS:
规格:
template:
spec:
containers:
- name: argocd-server
command:
- argocd-server
- --repo-server
- argocd-repo-server:8081
- --insecure # <-- Here