NGINX:客户端证书

4

我的环境

我在AWS API网关上使用了Elastic Beanstalk。我希望在主机端(Elastic Beanstalk)使用客户端证书验证。Elastic Beanstalk由负载均衡器(ELB)和带有NGINX和Ruby on Rails应用程序的EC2组成。我已经在API Gateway上生成了客户端证书。目前的流程如下:

  1. API网关发送请求
  2. 此请求通过负载均衡器(TCP端口80)并将其发送到EC2实例上的端口80(TCP)
  3. 在EC2实例上,我运行Docker中的NGINX。NGINX容器监听绑定到主机端口80的端口443。

API网关 -> (TCP 80) ELB (TCP 80) -> (端口80) 主机 -> (端口443) NGINX容器

我的问题

我使用以下nginx.conf文件,尝试进行客户端证书验证:

user  root;

error_log  /var/log/app-nginx-error.log debug;
pid        /var/run/app-nginx.pid;

events {
    worker_connections  8096;
    multi_accept        on;
    use                 epoll;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$ssl_client_cert"';

    access_log /var/log/app-nginx-access.log  main;

    sendfile           on;
    tcp_nopush         on;
    tcp_nodelay        on;
    keepalive_timeout  10;

    upstream appserver {
      server unix:///var/run/puma.sock;
    }

    server {
      listen 443 default_server;
      root /var/www/public;
      client_max_body_size  16m;

      ssl_trusted_certificate /etc/nginx/ssl/api-gateway.pem;
      ssl_client_certificate /etc/nginx/ssl/api-gateway.pem;
      ssl_verify_client on;

      ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
      ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
      ssl_prefer_server_ciphers on;

      if ($ssl_client_verify = FAILED) {
        return 495;
      }

      if ($ssl_client_verify = NONE) {
        return 402;
      }

      if ($ssl_client_verify != SUCCESS) {
        return 403;
      }

      location ^~ /assets/ {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
      }

      try_files $uri/index.html $uri @appserver;
      location @appserver {
        proxy_set_header  Host $host;
        proxy_set_header  X-Real-IP $remote_addr;
        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Host $server_name;
        proxy_set_header  Client-IP $remote_addr;
        proxy_pass        http://appserver;
        proxy_set_header X-Client-Verify $ssl_client_verify;
      }

      access_log    /var/log/app-nginx-access.log;
      error_log     /var/log/app-nginx-error.log debug;
      error_page    500 502 503 504 /500.html;
    }
}

然而,当我使用 API Gateway 发送证书进行测试时,它总是返回 403 错误 - 这是由以下代码块引起的:
 if ($ssl_client_verify != SUCCESS) {
    return 403;
  }

对我来说奇怪的是,它没有进入任何先前的 if 语句中,其中包含 FAILEDNONE

如果我删除:

 ssl_verify_client on;

它还涉及以下内容:
 if ($ssl_client_verify != SUCCESS) {
    return 403;
  }

如果我再次使用ssl_verify_client on并删除这个if语句:
 if ($ssl_client_verify != SUCCESS) {
    return 403;
  }

一切都向前传递-无论我是带证书还是不带证书发送请求都没有关系。

我的问题

  1. 我的nginx.conf文件是否正确?(也许我在TCP / HTTP方面混淆了些什么?)
  2. 有没有办法获取更多关于NGINX的详细信息(是否有证书?),ssl_verify_client的结果以及任何可以帮助检测问题的内容?
2个回答

1
我可能非常错误,但看起来您的设置是这样的:
API网关 ->(TCP 80)ELB(TCP 80) ->(端口80)主机 ->(端口443)NGINX容器
也许应该是这样的:
API网关 ->(TCP 80)ELB(TCP 443) ->(端口443)NGINX容器 ->(端口80)主机
也就是说,nginx 应该坐在您的应用程序前面,而不是在其后面。
另外,在您的配置文件中,似乎您实际上没有将 nginx 的端口443 代理到应用程序的端口80。您的配置文件中缺少一个proxy_pass或类似的内容。
您还提到了 Docker,您是使用多容器环境还是单容器环境?如果是前者,您应该在 Dockerrun.aws.json 文件中指定 nginx-app 端口映射。

我已经进行了一些测试。我的问题是我没有设置“ssl on;”和服务器证书。没有它,我得到了空的$ssl_client_verify - 我用条件检查了它:if ($ssl_client_verify = "")。我正在运行多容器,nginx也在容器中运行。然后将流量传递到另一个包含我的应用程序的容器中。 - nicq
@nicq 当你说“我没有设置“ssl on;”和服务器证书”时,我相信你需要从证书颁发机构购买SSL证书,并在NGINX配置中使用密钥和证书文件?如果我错了,请纠正我。 - Nishutosh Sharma
1
@NishutoshSharma,你说得对。你需要从可信的提供商购买SSL证书(这意味着某些SSL证书可能无法使用-例如Let's Encrypt将无法使用)。如果您在AWS上注册了域名,可以使用AWS证书而不是购买新证书。 - nicq
@nicq,这就归结于如果您希望测试API Gateway,则在QA上也需要有一个HTTPS环境! - Nishutosh Sharma
如果你问我,那不是一个坏的限制。 - joakim
显示剩余2条评论

0

我目前正在尝试构建一个设置,其中我的API网关终止SSL并将客户端证书发送到nginx。经过大量实验和找到这个答案后,我同意@joakim答案中的评论,您需要配置SSL才能在nginx中传递客户端证书。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接