NGINX:客户端证书

时间:2017-01-23 15:58:04

标签: amazon-web-services ssl nginx aws-api-gateway

我的环境

我有带有Elastic Beanstalk的AWS API网关。我想在主机端使用客户端证书验证(Elastic Beanstalk)。 Elastic Beanstalk包含Load Balancer(ELB)和EC2以及NGINX和我的Ruby on Rails应用程序。我在API网关上生成了客户端证书。目前的流程是:

  1. API网关发送请求
  2. 此请求通过Elastic Load Balancer(TCP端口80)并将其发送到端口80(TCP)上的EC2实例
  3. 在EC2实例上我在Docker中运行NGINX。 NGINX容器侦听端口443,它绑定到主机的端口80。
  4. 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​​网关发送Cert进行测试时,它总是返回403 - 它来自以下块:

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

    对我而言,奇怪的是它不会进入任何先前的 if if语句 FAILED NONE

    如果我删除:

     ssl_verify_client on;
    

    它也会进入:

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

    如果我再次将 ssl_verify_client放在上并删除此 if 语句:

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

    一切都向前传递 - 如果我发送带证书或没有证书的请求都无关紧要。

    我的问题

    1. 我的nginx.conf好吗? (也许我用TCP / HTTP混合了一些东西?)
    2. 有没有办法获得NGINX的更多细节(是否有任何证书?),ssl_verify_client的结果是什么以及什么可以帮助检测问题?

1 个答案:

答案 0 :(得分: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端口映射。