使用 aws-load-balancer-backend-protocol 时,nginx-ingress 不适用于 AWS ELB:"https"

nginx-ingress doesn't work with AWS ELB when use aws-load-balancer-backend-protocol: "https"

我使用 AWS EKS 作为我的 k8s 控制平面,并部署了一个 3 节点自动缩放组作为我的工作节点(K8s 节点)。这个自动缩放组位于我的 VPC 中。而且我确保安全组至少是开放的,足以让对等节点和 ELB 进行通信。

我正在尝试使用 nginx-ingress 路由来自外部 k8s 集群的流量。我使用 helm 使用 values.yaml.

部署我的 nginx-ingress

我的 values.yaml 看起来像这样:

serviceAccount:
  create: true
  name: nginx-ingress-sa
rbac:
  create: true

controller:
   kind: "Deployment"
   service:
      type: "LoadBalancer"
  # targetPorts:
  #   http: 80
  #   https: http
   loadBalancerSourceRanges: 
      - 1.2.3.4/32
  annotations:
      service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "https"
      service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
      service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789:certificate/my-cert
      service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: sg-12345678
      service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600'
      nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
      nginx.ingress.kubernetes.io/enable-access-log: "true"
  config:
    log-format-escape-json: "true"
    log-format-upstream: '{"real_ip" : "$the_real_ip", "remote_user": "$remote_user", "time_iso8601": "$time_iso8601", "request": "$request", "request_method" : "$request_method", "status": "$status", "upstream_addr": $upstream_addr", "upstream_status": "$upstream_status"}'
  extraArgs:
    v: 3 # NGINX log level

我的入口 yaml:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-1
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/enable-access-log: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  rules:
  - host: "s1.testk8.dev.mydomain.net"
    http:
      paths:
      - path: /
        backend:
          serviceName: s1-service
          servicePort: 443
  - host: "s2.testk8.dev.mydomain.net"
    http:
      paths:
      - path: /
        backend:
          serviceName: s2-service
          servicePort: 443
  tls:
  - hosts:
    - "s1.testk8.dev.mydomain.net"
    - "s2.testk8.dev.mydomain.net"
    secretName: "testk8.dev.mydomain.net"

请注意,此机密是域 *.mydomain.net.

上的自签名 TLS 证书

此设置的当前行为是,如果输入

https://s1.testk8.dev.mydomain.net 在 Chrome 中,它只是挂起。左下角写着waiting for s1.testk8.dev.mydomain.net.

如果我使用:

curl -vk https://s1.testk8.dev.mydomain.net

它returns:

*   Trying x.x.x.x...
* TCP_NODELAY set
* Connected to s1.testk8.dev.mydomain.net (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=*.mydomain.net
*  start date: Apr 25 00:00:00 2018 GMT
*  expire date: May 25 12:00:00 2019 GMT
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: s1.testk8.dev.steelcentral.net
> User-Agent: curl/7.54.0
> Accept: */*
> 

而且它似乎也在等待服务器响应。

我也尝试调整 values.yaml,当我更改

service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http" # instead of https as above

然后我点击 https://s1.testk8.dev.mydomain.net URL,我至少可以看到来自入口控制器 pod 的 HTTP 400 消息(发送到 HTTPS 端口的纯 HTTP 请求)。

如果取消注释 values.yaml 中的这些行:

# targetPorts:
  #   http: 80
  #   https: http

我可以访问我的后端 pod(由 statefulset 控制,此处未列出。),我可以看到我的后端 pod 的访问日志有新条目。

不确定我的用例在这里是否很奇怪,因为我看到很多人在 AWS 上使用 nginx-ingress,他们在 ELB 处终止 TLS。但是我需要让我的后端 pod 终止 TLS。

我也尝试了 ssl-passthrough 标志,但没有帮助。当后端协议是 https 时,我的请求似乎甚至没有到达入口控制器,所以谈论 ssl-passthrough 可能仍然毫无意义。

如果您从头到尾看完这里,先谢谢您!!

我的猜测是您的后端服务使用的是 HTTPS,并且中间流量是通过 HTTP 发送的。 values.yaml 中的这一行看起来很奇怪:

targetPorts:
  http: 80
  https: http

你能试试这样的吗?

targetPorts:
  http: 80
  https: 443

据我所知,即使是现在的nginx-ingress高手,也不可能使用自签名证书。模板 https://github.com/kubernetes/ingress-nginx/blob/master/rootfs/etc/nginx/template/nginx.tmpl 缺少任何需要的指令,例如:

location / {
     proxy_pass                    https://backend.server.ip/;
     proxy_ssl_trusted_certificate /etc/nginx/sslcerts/backend.server.pem;
     proxy_ssl_verify              off;

     ... other proxy settings
}

所以尝试使用例如让我们加密证书。