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

Kate

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

ac965f460be383a1626a5aea3e67387c.jpg

В поисках более стабильного решения для нашей проблемы мы наткнулись на статью Авторизация с помощью сертификата 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
В итоге схема создания сертификата выглядит так:

accff5f52081d2e53bae82ceb018d707.png

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

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

  1. Переходим по следующим скриншотам и добавляем сертификат:
c2ac704782022798d1ecfecbec303cc4.png
36a5ba30a162cb1d8da23478603168da.png
c106699e8d110ab51573b2c6a585b9fa.png
2435d0514d56d4d2c6c79ae0ace0e921.png

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

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

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

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

  1. Удалите созданные 4 сертификата пользователя из папки /etc/nginx/example.com/users_certs.
  2. Удалите строчку пользователя из /etc/nginx/example.com/index.txt.
  3. Удалите последний номер из файла /etc/nginx/example.com/serial.
Эти действия тоже можно зашить в скрипт, но данный функционал я не реализовывал.

Итог​

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

 
Сверху