简体   繁体   中英

NGINX: Client Side Certificate

My environment

I have AWS API Gateway with Elastic Beanstalk. I want to use Client Side Certificate validation on host side (Elastic Beanstalk). Elastic Beanstalk consists of Load Balancer (ELB) and EC2 with NGINX and my Ruby on Rails app. I've generated client side certificate on API Gateway. The current flow is:

  1. API Gateway sends request
  2. this request goes through Elastic Load Balancer (TCP port 80) and sends it futher to EC2 instance on port 80 (TCP)
  3. on EC2 instance I have NGINX running in Docker. NGINX container listens on port 443, which is bind to host's port 80.

API Gateway -> (TCP 80) ELB (TCP 80) -> (port 80) host -> (port 443) NGINX container

My problem

I use following nginx.conf, where I try to make client side certificate verification:

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;
    }
}

However, when I test it with API Gateway sending Cert it always returns 403 - it comes from following block:

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

Strange thing for me is that it doesn't go into any previous if statement with FAILED or NONE .

If I remove:

 ssl_verify_client on;

It also goes into:

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

If I put again ssl_verify_client on and remove this if statement:

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

Everything is passed forward - it doesn't matter if I send request with certificate or without certificate.

My questions

  1. Is my nginx.conf OK? (Maybe I've mixed something with TCP / HTTP ?)
  2. Is there any way to get more details what comes to NGINX (is there any certificate?), what is the result of ssl_verify_client and anything what could help to detect the problem?

I could be very wrong here but it looks like your setup

"API Gateway -> (TCP 80) ELB (TCP 80) -> (port 80) host -> (port 443) NGINX container"

maybe should be

API Gateway -> (TCP 80) ELB (TCP 443 ) -> (port 443) NGINX container -> (port 80) host

That is, nginx should be sitting in front of your app, not behind it.

It also looks like you are not actually proxying nginx's port 443 to your app's port 80 in your config file. You're missing a proxy_pass or similar in there somewhere.

You also mentioned docker, are you using a multicontainer environment or a single container one? If the former, you should (could?) specify the nginx-app port mappings in your Dockerrun.aws.json file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM