You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在AWS NLB后的NGINX Ingress中实现客户端证书认证

解决NLB终止TLS时NGINX Ingress的客户端证书认证问题

问题背景

我在EKS中部署了NGINX Ingress Controller,前端使用AWS NLB完成TLS终止,NGINX负责路由到后端服务。之前通过Ingress注解成功实现了HTTP基本认证,但切换到客户端证书认证时,配置的注解完全不生效:

生效的HTTP基本认证注解

nginx.ingress.kubernetes.io/auth-realm: Authentication Required
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/proxy-body-size: 8m
nginx.ingress.kubernetes.io/rewrite-target: /loki/$1text

不生效的客户端证书认证注解

nginx.ingress.kubernetes.io/auth-tls-error-page: http://www.example.com/error-cert.html
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: false
nginx.ingress.kubernetes.io/auth-tls-secret: default/ca-secret
nginx.ingress.kubernetes.io/auth-tls-verify-client: on
nginx.ingress.kubernetes.io/auth-tls-verify-depth: 1

问题核心:NGINX的auth-tls-*注解依赖自身完成TLS握手以获取客户端证书,但当前TLS终止在NLB,NGINX接收的是明文HTTP请求,自然无法执行证书验证。同时我既不能在NLB层面配置客户端证书认证,也无法将TLS终止转移到NGINX Ingress。


可行解决方案:NLB转发客户端证书+NGINX自定义Lua验证

步骤1:配置NLB转发客户端证书

在AWS控制台或CLI中修改NLB的HTTPS监听:

  • 找到对应HTTPS端口的监听配置
  • 开启Forward client certificates选项,选择Forward to target as HTTP header
  • 保留默认头名称X-Forwarded-Client-Cert(自定义头需同步修改后续NGINX配置)
  • 保存配置后,NLB会将客户端证书的PEM编码通过该HTTP头传递给后端NGINX

步骤2:修改Ingress配置,添加Lua验证逻辑

放弃原有的auth-tls-*注解,改用server-snippet注入自定义NGINX配置,通过Lua脚本解析并验证NLB转发的证书:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: your-ingress-name
  annotations:
    # 保留原有业务必要注解
    nginx.ingress.kubernetes.io/proxy-body-size: 8m
    nginx.ingress.kubernetes.io/rewrite-target: /loki/$1text
    # 添加客户端证书验证的自定义Lua配置
    nginx.ingress.kubernetes.io/server-snippet: |
      # 预加载CA证书到共享内存
      lua_shared_dict ca_certs 1m;
      init_by_lua_block {
        local f = assert(io.open("/etc/nginx/ssl/default/ca-secret/tls.crt", "r"))
        local ca_cert_data = f:read("*a")
        f:close()
        local ssl = require "ngx.ssl"
        local ca_cert, err = ssl.parse_pem_cert(ca_cert_data)
        if not ca_cert then
          ngx.log(ngx.ERR, "Failed to parse CA certificate: ", err)
          return
        end
        ngx.shared.ca_certs:set("ca_cert", ca_cert)
      }
      # 访问阶段验证客户端证书
      access_by_lua_block {
        local client_cert_header = ngx.var.http_x_forwarded_client_cert
        -- 无证书直接拒绝
        if not client_cert_header then
          ngx.exit(403)
        end
        local ssl = require "ngx.ssl"
        -- 解析头中的客户端证书
        local client_cert, err = ssl.parse_pem_cert(client_cert_header)
        if not client_cert then
          ngx.log(ngx.ERR, "Failed to parse client certificate: ", err)
          ngx.exit(403)
        end
        -- 获取预加载的CA证书
        local ca_cert = ngx.shared.ca_certs:get("ca_cert")
        if not ca_cert then
          ngx.log(ngx.ERR, "CA certificate not found")
          ngx.exit(500)
        end
        -- 验证证书签名合法性
        local ok, err = ssl.verify_client_cert(client_cert, {ca_cert})
        if not ok then
          ngx.log(ngx.ERR, "Client certificate verification failed: ", err)
          ngx.exit(403)
        end
      }
spec:
  tls:
    # 此处TLS配置仅用于Ingress资源标识,实际TLS终止在NLB
    - hosts:
        - your-domain.com
      secretName: dummy-tls-secret # 任意存在的TLS Secret即可(无需有效证书)
  rules:
    - host: your-domain.com
      http:
        paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: your-service-name
                port:
                  number: 80

关键说明

  • /etc/nginx/ssl/default/ca-secret/tls.crt是NGINX Ingress自动挂载Secret的路径,格式为/etc/nginx/ssl/<namespace>/<secret-name>/tls.crt,需根据你的ca-secret所在命名空间调整
  • 官方NGINX Ingress镜像默认已包含ngx_http_lua_module,无需额外编译
  • 测试时使用带有合法客户端证书的请求,无证书或非法证书的请求会返回403

内容的提问来源于stack exchange,提问作者alarobric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 14:54:49