Аутентификация клиента TLS с веб-приложением Nginx и Tomcat

У меня есть веб-приложение Tomcat 8, оно работает на порту 8080 на сервере. Любой входящий запрос на порт 443 перенаправляется на localhost:8080 с использованием Nginx для обслуживания веб-приложения.

Я пытаюсь настроить взаимную аутентификацию, а затем проанализировать сертификат клиента, который использовался для аутентификации приложением. Затем эта информация будет использоваться приложением, чтобы решить, должен ли пользователь иметь права admin или user. Сертификат клиента будет иметь строку admin или user в поле Common Name (CN).

Я могу добиться взаимной аутентификации, и ниже приведен текущий nginx ssl.conf. Но проблема в том, что информация о сертификате не передается веб-приложению tomcat для анализа данных. Есть ли в nginx способ передачи данных сертификата клиента, чтобы приложение tomcat8 могло его использовать?

server {
    listen       443 default_server;
    server_name  name.domain.com;

    ssl on;
    ssl_certificate /etc/nginx/self-signed.pem;
    ssl_certificate_key /etc/nginx/self-signed.pem;
    ssl_protocols SSLv2 TLSv1 TLSv1.1 TLSv1.2;


    ssl_client_certificate /etc/nginx/ca.cert.pem;
    ssl_verify_client optional;
    ssl_verify_depth  2;
    ssl_session_timeout  5m;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers  on;


    port_in_redirect off;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    #test page for the load balancer
    location /loadbalancer {
      add_header X-Frame-Options "DENY";
      auth_basic off;
      #proxy_pass http://localhost:8080;
      try_files $uri /test.html;
    }

    location /webapi {
      add_header X-Frame-Options "DENY";
      auth_basic off;
      proxy_pass http://localhost:8080;
    }

    location / {
      if ($ssl_client_verify != SUCCESS)

     {
      return 403;
      break;
     }

      add_header X-Frame-Options "DENY";
      proxy_pass http://localhost:8080;
    }


    error_page  404              /404.html;
      location = /404.html {
      root   /usr/share/nginx/html;
    }

    error_page   500 502 503 504  /50x.html;
      location = /50x.html {
      root   /usr/share/nginx/html;
    }
}

person OK999    schedule 05.10.2015    source источник


Ответы (1)


Вы можете использовать директиву proxy_set_header для передачи дополнительных заголовков вашему коту.

Доступные переменные

http://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_cipher

Пример

proxy_set_header SSL_DN $ssl_client_s_dn;

В вашем Java-приложении вы можете прочитать эти заголовки для дальнейшей обработки.

Кстати, я бы сохранял уровень доступа не в сертификате, а в базе данных на стороне сервера, чтобы вы могли проще переназначать / изменять / добавлять роли или отзывать действительный сертификат.

EDIT На самом деле nginx также поддерживает списки отозванных сертификатов: http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_crl

Хорошая статья для nginx + php, которую можно легко адаптировать к вашему варианту использования:

http://nategood.com/client-side-certificate-authentication-in-ngi

person Michel Feldheim    schedule 05.10.2015
comment
Это proxy_set_header SSL_DN $ssl_client_s_dn; действительно сработало! благодарю вас. - person OK999; 06.10.2015
comment
Обратите внимание: если вам нужен полный сертификат, есть две переменные: ssl_client_cert, где Nginx заменит \n вкладками; и ssl_client_raw_cert, который содержит новые строки, но разрывает ваше HTTP-соединение. Использование официального SSL-клапана Tomcat не работает (заменяет только пробелы, а не вкладки) - person lucasvc; 21.06.2016
comment
И в официальном документе Nginx для ssl_client_cert, похоже, не упоминается, что \n заменены. В начало добавляются только упоминания \t (но \n фактически заменяется): http://nginx.org/en/docs/http/ngx_http_ssl_module.html - person Khanna111; 18.07.2017
comment
Это хороший пост по теме (и проблеме \n): blog.perplexedminds.com/2015/04/ - person Martynas Jusevičius; 02.02.2021