Sysadmin
May 16

Авторизация в Nginx клиентским сертификатом


1. Аутентификация в Nginx при помощи клиентского сертификата

Аутентификация в Nginx предназначена для ограничения доступа к web-ресурсу. Аутентификация бывает Базовая (при помощи пары "логин/пароль"). В статье рассматривается вариант аутентификации сертификатом.

Аутентификация сертификатом

Сертификат клиента (client-side certificate) - это механизм аутентификации транспортного уровня, который позволяет проверить пользователя до перехода на уровень приложений.

Удостоверяющий центр

Для выпуска клиентский сертификатов необходимо создать ключ Удостоверяющего центра (Certificate Authority), который будет использоваться для создания сертификата сервера (server-side certificate):

openssl genrsa -des3 -out ca.key 4096

При создании ключа будет запрошена ключевая фраза, которую необходимо запомнить. Она потребуется каждый раз при создании нового сертификата или подписывании запроса клиентского сертификата.

Сертификат Удостоверяющего центра

Далее необходимо создать сертификат Удостоверяющего центра (CA Certificate) - это серверный сертификат, который будет направляться клиенту через TLS.

Этот сертификат не является заменой TLS сертификата Nginx.
openssl req -new -x509 -days 1095 -key ca.key -out ca.crt

Здесь нужно будет ответить на вопросы: Страна, Область, Город, Организация.
Рекомендуется пропустить общее имя сертификата (Common Name - CN).
Для обновления сертификата необходимо запустить такую же команду и также ответить на вопросы. Чтобы посмотреть, что входит в изданный сертификат, можно воспользоваться командой:

openssl x509 -in ca.crt -noout -text

Сертификат Клиента

Сертификат клиента по сути является "паролем" и выпускается для "устройства". Для выпуска понадобится ключ клиента, сгенерированный также, как ключ Удостоверяющего центра.

openssl genrsa -des3 -out user.key 4096

Из которого сформировать запрос на подпись сертификата (Certificate Signing Request, CSR)

openssl req -new -key user.key -out user.csr

Подпись запроса на сертификат

Сформированный запрос сертификата должен быть подписан Удостоверяющим центром, что подтверждает личность пользователя или устройства:

openssl x509 -req -days 365 -in user.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out user.crt

Обычно лучше увеличивать значения счетчика serial при подписывании каждого нового сертификата.
Когда сертификат заканчивается, не нужно создавать новый запрос на сертификат, тот же запрос можно подписать, что создаст новый сертификат, привязанный к тому же публичному ключу.

Подписанный сертификат необходимо передать пользователю вместе с сертификатом удостоверяющего центра (не приватным ключом!) для установки на устройство пользователя.

Собрать связку PKCS #12 (PFX)

Для установки подписанного сертификата на устройства пользователей, его обычно собирают в связку (bundle), содержащую клиентский сертификат, его ключ, и сертификат удостоверяющего центра.

openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile ca.crt

Здесь появится запрос пароля, который нужно вводить каждый раз при использовании его на устройстве клиента. Можно оставить пустым.

Установка сертификата на устройство клиента

Нажать и Установить.

Настройка Nginx

Для проверки пользователей по сертификатам на обратном прокси необходимо добавить несколько строк в конфигурационный файл.

server {
  listen 80;
  server_name antroot.ru;
  return 301 https://antroot.ru$request_uri;
}

server {
  listen 443 ssl http2;
  server_name antroot.ru;

  access_log /var/log/nginx/antroot.ru.access.log;
  ssl_protocols TLSv1.2 TLSv1.3;

  # letsencrypt certificate
  ssl_certificate /etc/letsencrypt/live/antroot.ru/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/antroot.ru/privkey.pem;

  # client certificate
  ssl_client_certificate /etc/nginx/client_certs/ca.crt;
  # можно включить проверку опционально и обрабатывать далее, возвращая 403
  ssl_verify_client optional;
  # либо обязательная проверка сертификата
  # ssl_verify_client on;

  location / {
    # вывод 403 при ошибке проверки сертификата клиента
    if ($ssl_client_verify != SUCCESS) {
        return 403;
    }

    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-Proto $scheme;

    proxy_pass          http://antroot.local:8080;
    proxy_read_timeout  90;

    # web sockets
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_redirect      http://antroot.local:8080 https://antroot.ru;
  }
}

В целом, готово. Оставляем одну из директив в конфигурации Nginx ssl_verify_client - включено или опционально и пользуемся.


2. Вариант с самоподписанным сертификатом

Создать сертификат Удостоверяющего центра

openssl req -new -newkey rsa:1024 -nodes -keyout ca.key -x509 -days 500 -subj /C=RU/ST=Moscow/L=Moscow/O=antroot/OU=User/CN=etc/emailAddress=support@antroot.ru -out ca.crt

Выпустить сертификат сервера, запрос на подпись, и подписать его

openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

Убрать пароль из ключа

openssl rsa -in server.key -out server.nopass.key

Конфигурация Nginx

ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.nopass.key;
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;

keepalive_timeout 70;
fastcgi_param SSL_VERIFIED $ssl_client_verify;

Для упрощения выпуска клиентских сертификатов сделаем конфиг:

[ ca ]
default_ca = CA_CLIENT # по умолчанию использовать CA_CLIENT

[ CA_CLIENT ]
dir = ./db
certs = $dir/certs
new_certs_dir = $dir/newcerts

database = $dir/index.txt
serial = $dir/serial
certificate = ./ca.crt
private_key = ./ca.key

default_days = 365
default_crl_days = 7
default_md = md5

policy = policy_anything

[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = optional
emailAddress = supplied

Создать клиентский ключ и запрос на сертификат и подписать запрос Удостоверяющим центром (повторяется для каждого следующего сертификата клиента):

openssl req -new -newkey rsa:1024 -nodes -keyout client01.key -subj /C=RU/ST=Moscow/L=Moscow/O=antroot/OU=User/CN=etc/emailAddress=support@antroot.ru -out client01.csr
openssl ca -config ca.config -in client01.csr -out client01.crt -batch

Собрать в связку сертификат, ключ, промежуточный сертификат:

openssl pkcs12 -export -in client01.crt -inkey client01.key -certfile ca.crt -out client01.p12 -passout pass:123456qwerty

Проверка сертификата с помощью curl:

curl -k --key client.key --cert client1.crt --url "https://antroot.ru"