Задача: обеспечить вход на сайт только при наличии действующего сертификата формата p12.
Решение:
Инструкция создана на основе нескольких источников, в т.ч. этого и этого, но с внесением поправок что год уже конец 2022, и появились некоторые нюансы, что старые инструкции не работают по умолчанию для новых дистрибутивов.
Сначала создадим корневой сертификат сервера и необходимые для дальнейшей работы файлы и папки. Для этого создадим в любой папке файл root_cer.sh с содержимым вида:
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 (закрытый ключ). Данные закрытого ключа можно посмотреть при помощи:
openssl rsa -noout -text -in server.key
openssl x509 -noout -text -in server.crt
В файле db/serial записывается текущий серийный номер
подписываемого сертификата в шестнадцатиричном формате.
В файл db/index.txt сохраняются данные о подписываемых сертификатах.
Далее необходимо создать файл с настройками для генерации пользовательских сертификатов ca.config:
[ 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 скрипт:
#!/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:
#!/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
Посмотреть список отозваных сертификатов можно при помощи команды:
openssl crl -in revoked.crl -text -noout
Осталось только настроить apache для того что бы он пускал на сайт, только при наличии сертификата, добавив:
SSLCACertificateFile /path/to/server.crt
SSLVerifyClient require