Защита сайта сертификатом p12
Задача: обеспечить вход на сайт только при наличии действующего сертификата формата p12.
Решение:
Инструкция создана на основе нескольких источников, в т.ч. этого и этого, но с внесением поправок что год уже конец 2022, и появились некоторые нюансы, что старые инструкции не работают по умолчанию для новых дистрибутивов.
Сначала создадим корневой сертификат сервера и необходимые для дальнейшей работы файлы и папки. Для этого создадим в любой папке файл root_cer.sh с содержимым вида:
1 2 3 4 5 6 7 8 9 10 11 |
mkdir db # БД сертификатов mkdir certs # ключ и сертификат сервера mkdir db/certs # пользовательские сертификаты mkdir db/newcerts # новые сертификаты mkdir p12 # сертификаты для передачи клиентам (p12) touch db/index.txt echo "01" > db/serial openssl req -new -newkey rsa:2048 -nodes -keyout certs/server.key -x509 -days 1024 \ -subj /C=RU/ST=Vol/L=Vol/O=LTD\ ElkiPalki/OU=Sale/CN=zz/emailAddress=wefwerfwe@gmail.com \ -out certs/server.crt |
, где:
rsa:2048- длина ключа, -days — сколько дней действителен сертификат, -x509 — создаём самоподписаный сертификат, /C — страна, /ST — область, /L — город, /O — организация, /OU — отдел,
Результатом работы будут два файла в папке certs: servert.crt (сертификат) и serverk.key (закрытый ключ). Данные закрытого ключа можно посмотреть при помощи:
1 2 |
openssl rsa -noout -text -in server.key openssl x509 -noout -text -in server.crt |
В файле db/serial записывается текущий серийный номер
подписываемого сертификата в шестнадцатиричном формате.
В файл db/index.txt сохраняются данные о подписываемых сертификатах.
Далее необходимо создать файл с настройками для генерации пользовательских сертификатов ca.config:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[ 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 = ./certs/server.crt # Файл сертификата CA private_key = ./certs/server.key # Файл закрытого ключа CA default_days = 365 # Срок действия подписываемого # сертификата default_crl_days = 7 # Срок действия CRL (см. $4) default_md = sha256 # Алгоритм подписи policy = policy_anything # Название секции с описанием политики в отношении данных сертификата [ policy_anything ] countryName = optional # Код страны - не обязателен stateOrProvinceName = optional # ...... localityName = optional # ...... organizationName = optional # ...... organizationalUnitName = optional # ...... commonName = supplied # ...... - обязателен emailAddress = optional # ...... |
Для автоматизации генерации клиентских сертификатов можно собрать небольшой bash скрипт:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/bin/bash NO_ARGS=0 BASE_DIR="" P12_DIR="$BASE_DIR/p12" CA_CFG="$BASE_DIR/ca.config" # Конфигурационный файл для подписи CERTS="$BASE_DIR/db/certs" # Каталог для хранения сертификатов CA_FILE="$BASE_DIR/certs/server.crt" # Доверенный сертификат (Им подписывам) usage () { echo "Скрипт `basename $0` предназначен для создания клиентских SSL сертификатов." echo "" echo "Использование: `basename $0` email name password" } if [ $# -eq "$NO_ARGS" ] # Сценарий вызван без аргументов? then usage # Если запущен без "аргуменотов" - вывести справку exit $E_OPTERROR # и выйти с кодом ошибки fi EMAIL=$1 echo "Email:$EMAIL" NAME=$2 echo "Name:$NAME" PASSWORD=$3 echo "Password:$PASSWORD" # создаём запрос на клиентский сертификат openssl req -new -newkey rsa:2048 -nodes -keyout "$CERTS/$NAME.key" \ -subj /C=RU/CN=usr/emailAddress="$EMAIL" \ -out "$CERT/$NAME.csr" # подписываем запрос на сертификат при помощи доверенного сертификата openssl ca -config "$CA_CFG" -in "$CERT/$NAME.csr" -out "$CERT/$NAME.crt" -batch # создаём файл p12 для передачи клиенту openssl pkcs12 -export -in "$CERT/$NAME.crt" -inkey "$CERTS/$NAME.key" \ -certfile "$CA_FILE" -out "$P12_DIR/$NAME.p12" -passout pass:"$PASSWORD" |
На входе скрипта необходимо задать email, имя пользователя без пробелов и пароль на установку сертификата. На выходе будет запись в БД сертификатов и непосредственно сам контейнер p12 в папке p12 для передачи клиенту.
И ещё один полезный скрипт, для автоматизации отзыва сертификатов revote.sh:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#!/bin/bash NO_ARGS=0 BASE_DIR="" CA_CFG="$BASE_DIR/ca.config" CERTS="$BASE_DIR/db/newcerts" usage () { echo "Скрипт `basename $0` предназначен для отзыва клиентских SSL сертификатов." echo "" echo "Использование: `basename $0` serial" } if [ $# -eq "$NO_ARGS" ] # Сценарий вызван без аргументов? then usage # Если запущен без "аргуменотов" - вывести справку exit $E_OPTERROR # и выйти с кодом ошибки fi SERIAL=$1 echo "Отзываю сертификат: $CERTS/$SERIAL.pem" openssl ca -config "$CA_CFG" -revoke "$CERTS/$SERIAL.pem" # составим список отозваных в файл revoked.crl openssl ca -gencrl -config "$CA_CFG" -out revoked.crl |
Посмотреть список отозваных сертификатов можно при помощи команды:
1 |
openssl crl -in revoked.crl -text -noout |
Осталось только настроить apache для того что бы он пускал на сайт, только при наличии сертификата, добавив:
1 2 |
SSLCACertificateFile /path/to/server.crt SSLVerifyClient require |