Настройка авторизации через ssl сертификат на уровне nginx

от автора

Привет уважаемые, хабровчане!

Иногда возникает потребность выдать доступ пользователям только к одному веб ресурсу в компании. Самый очевидный вариант сделать это через урезанный VPN, но тут возникают препятствия в виде девайсов, с которых подключаются пользователи, и качество интернета, которым они пользуются. OpenVPN, который мы пробовали использовать для этих целей, не дал желаемого результата, подключение было медленным и нестабильным.

В поисках более стабильного решения для нашей проблемы мы наткнулись на статью Авторизация с помощью сертификата ssl на nginx + Let’s Encrypt.

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

После анализа обнаружили проблему, что алгоритм шифрования который используется в статье, не подходит для нашей конфигурации nginx 1.18.0 + Ubuntu 20.04.4 LTS + Let`s Encrypt, он считается небезопасным. Решением этой ситуации было использование шифрования на эллиптических кривых.

Собственно сама настройка

  1. Перед началом настройки стоит создать следующую структуру конфиг-файлов:

Лучше ограничить доступ к папке с конфигами, чтобы кто угодно не мог сгенерировать сертификат, поломать настроенный функционал

mkdir /etc/nginx/example.com #создаем папку, в которой будут лежать наши кофиги и сертификаты cd /etc/nginx/example.com #переходим в нее mkdir users_certs certs newcerts #создаем необходимые поддиректории touch index.txt root.config serial #создаем необходимые кофиг-файлы echo "01" > serial #записываем первое значение в serial от него система начнет отсчет номеров сертификатов chmod 700 ./
Итоговая файловая структура

Итоговая файловая структура
  1. Создаем собственный самоподписанный доверенный сертификат (в командах отмечены поля которые нужно заполнить), с алгоритмом шифрования на эллиптических кривых:

openssl ecparam -out /etc/nginx/example.com/certs/root.key -name secp384r1 -genkey openssl req -new -x509 -days 500 -sha512 -key /etc/nginx/example.com/certs/root.key -subj /O={Название вашей компании}/emailAddress={email создателя сертификата} -out /etc/nginx/example.com/certs/root.crt
  1. В nginx добавляем строки с корневым сертификатом для агентов:

Строки добавляются в конфигурацию nginx целевого ресурса, которая обычно лежит в папке /etc/nginx/sites‑enabled/имя_веб_ресурса.
Данные добавляются в раздел server, где слушается 443 https порт.

ssl_client_certificate /etc/nginx/example.com/certs/root.crt; #путь до корневого сертификата  ssl_verify_client on; keepalive_timeout 70; #ниже необязательные параметры, можно их не указывать fastcgi_param SSL_VERIFIED $ssl_client_verify;  fastcgi_param SSL_CLIENT_SERIAL $ssl_client_serial; fastcgi_param SSL_CLIENT_CERT $ssl_client_cert; fastcgi_param SSL_DN $ssl_client_s_dn;
  1. В папке /etc/nginx/ssl/ открываем root.config, созданный ранее с необходимыми параметрами для автоматического выпуска сертификатов:

[ ca ]         default_ca             = CA_CLIENT                                  [ CA_CLIENT ]         dir                    = /etc/nginx/example.com/                     certs                  = /etc/nginx/example.com/certs               new_certs_dir          = /etc/nginx/example.com/newcerts             database               = $dir/index.txt                    serial                 = $dir/serial                                certificate            = $dir/certs/root.crt                 private_key            = $dir/certs/root.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 = supplied                 commonName             = supplied                 emailAddress           = supplied
  1. На этом настройка аутентификации закончена.

Создание пользовательского сертификата

  1. Создаем закрытый ключ пользователя (нужно заполнить параметры в скобках):

openssl ecparam -out /etc/nginx/example.com/users_certs/{email пользователя}.key -name secp384r1 -genkey
  1. Создаем CSR сертификат пользователя (нужно заполнить параметры в скобках):

openssl req -new -key /etc/nginx/example.com/users_certs/{email пользователя}.key -subj /C={аббревиатура вашей страны}/ST={название вашего региона}/L={название вашего города}/OU={имя фамилия пользователя}/CN={название компании}/emailAddress={email пользователя} -out /etc/nginx/example.com/users_certs/{email пользователя}.csr
  1. Создаем CRT сертификат пользователя (нужно заполнить параметры в скобках):

openssl ca -config /etc/nginx/example.com/root.config -in /etc/nginx/example.com/users_certs/{email пользователя}.csr -out /etc/nginx/example.com/users_certs/{email пользователя}.crt -batch
  1. Создаем P12 сертификат, который непосредственно будем передавать пользователю ( (нужно заполнить параметры в скобках и задать пароль, который будет использоваться для установки сертификата пользователем):

Если не переживаете, что кто-то случайно удалит сертификаты пользователей, то вывод можно настроить сразу в общую папку, из которой будете их забирать по SFTP. Для этого можете подкорректировать следующий параметр:

-out /etc/nginx/example.com/agent/{email пользователя}.p12

openssl pkcs12 -export -clcerts -in /etc/nginx/example.com/users_certs/{email пользователя}.crt -inkey /etc/nginx/example.com/users_certs/{email пользователя}.key -out /etc/nginx/example.com/users_certs/{email пользователя}.p12 -passout pass:{пароль который хотите задать для сертификата}
  1. Готово. Теперь подключаемся к серверу любым SFTP клиентом и скачиваем сертификат с расширением .p12 и передаем его и пароль пользователю.

Чтобы было проще вот весь этот функционал в одном bash-скрипте, который нужно положить в директорию /etc/nginx/example.com:

#!/bin/bash   echo "Please, enter user name:" read A   Q=$(grep -rn $A index.txt | awk '{print $5}' | awk -F/ '{print $6}' | sed  's/OU=//g')  echo "Please, enter user email:" read B  echo "Please, enter key pass:" read P  if [[ "$A" = "$Q" ]] then echo "this user is already exist" else  openssl ecparam -out /etc/nginx/example.com/users_certs/$B.key -name secp384r1 -genkey &&  openssl req -new -key /etc/nginx/example.com/users_certs/{email пользователя}.key -subj /C={аббревиатура вашей страны}/ST={название вашего региона}/L={название вашего города}/OU={имя фамилия пользователя}/CN={название компании}/emailAddress={email пользователя} -out /etc/nginx/example.com/users_certs/{email пользователя}.csr &&  openssl ca -config /etc/nginx/example.com/root.config -in /etc/nginx/example.com/users_certs/$B.csr -out /etc/nginx/example.com/users_certs/$B.crt -batch &&  openssl pkcs12 -export -clcerts -in /etc/nginx/example.com/users_certs/$B.crt -inkey /etc/nginx/example.com/users_certs/$B.key -out /etc/nginx/example.com/users_certs/$B.p12 -passout pass:$P  fi

В итоге схема создания сертификата выглядит так:

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

Покажу на примере Google Chrome

  1. Переходим по следующим скриншотам и добавляем сертификат:

  1. Вводим пароль и нажимаем ОК:

  1. Переходим на целевой сайт, выбираем нужный сертификат в выпадающем окне и нажимаем ОК:

  1. Проверяем что все открылось:

Удаление сертификата

  1. Удалите созданные 4 сертификата пользователя из папки /etc/nginx/example.com/users_certs.

  2. Удалите строчку пользователя из /etc/nginx/example.com/index.txt.

  3. Удалите последний номер из файла /etc/nginx/example.com/serial.

Эти действия тоже можно зашить в скрипт, но данный функционал я не реализовывал.

Итог

Аутентификация готова, главное не забывать отзывать сертификаты, если пользователю они больше не нужны.


ссылка на оригинал статьи https://habr.com/ru/articles/762676/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *