NGINX:客户端证书

Posted

技术标签:

【中文标题】NGINX:客户端证书【英文标题】:NGINX: Client Side Certificate 【发布时间】:2017-06-08 04:55:39 【问题描述】:

我的环境

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

    API 网关发送请求 此请求通过 Elastic Load Balancer(TCP 端口 80)并将其进一步发送到端口 80 (TCP) 上的 EC2 实例 在 EC2 实例上,我在 Docker 中运行 NGINX。 NGINX 容器监听 443 端口,该端口绑定到主机的 80 端口。

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 网关对其进行测试时,它总是返回 403 - 它来自以下块:

 if ($ssl_client_verify != SUCCESS) 
    return 403;
  

对我来说奇怪的是,它没有进入任何以前的 if 语句 FAILEDNONE

如果我删除:

 ssl_verify_client on;

它也进入:

 if ($ssl_client_verify != SUCCESS) 
    return 403;
  

如果我再次打开 ssl_verify_client 并删除此 if 语句:

 if ($ssl_client_verify != SUCCESS) 
    return 403;
  

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

我的问题

    我的 nginx.conf 可以吗? (也许我在 TCP / HTTP 中混合了一些东西?) 有什么方法可以获取更多关于 NGINX 的详细信息(有证书吗?)、ssl_verify_client 的结果是什么以及有什么可以帮助检测问题的方法?

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

我在这里可能非常错误,但它看起来像你的设置

“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 那你搞定了吗?如果是,最好发布您的配置/设置,以防其他人遇到类似问题。 我已经在本地测试过,但我打算在 EB 上进行测试。然后我将发布完整的答案“应该设置什么和在哪里”:api gateway、elb、eb 和 nginx。 @nicq 当您说I haven't set "ssl on;" and server certificates 我相信您需要从证书颁发机构购买 SSL 证书并在 NGINX 配置中使用密钥和证书文件?如有错误请指正。 @NishutoshSharma,你是对的。您需要从受信任的提供商处购买 SSL 证书(这意味着某些 SSL 证书可能无法使用 - 例如 Let's Encrypt 将无法使用)。您可以使用 AWS 证书,而不是购买新证书,但前提是您在 AWS 上注册了一个域。

以上是关于NGINX:客户端证书的主要内容,如果未能解决你的问题,请参考以下文章

nginx配置https及Android客户端访问自签名证书

nginx和iis下的SSL双向认证教程【ca 自签 ssl证书】

带你使用Nginx实现HTTPS双向验证

Nginx Docker构建https服务

NGINX 配置 SSL 双向认证

centos 7 Nginx ssl证书配置