MAATRIX / Блог / IKEv2 с сертификатами для нескольких пользователей на strongSwan

IKEv2 с сертификатами для нескольких пользователей на strongSwan

MAATRIX

Когда VPN использует один человек, пароль в ipsec.secrets — нормальное решение. Но как только к серверу подключается команда из пяти-двадцати человек, схема начинает трещать: пароли расшаривают в чатах, никто не помнит, кому какой выдан, а при увольнении сотрудника приходится либо менять общий секрет для всех, либо надеяться, что человек сам удалит профиль с телефона. Сертификатная PKI решает это иначе — у каждого свой ключ, а отзыв доступа занимает одну команду и не трогает остальных.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Чем сертификатная схема отличается от EAP-паролей

В базовой установке IKEv2 на strongSwan клиенты авторизуются по логину и паролю через EAP-MSCHAPv2. Это быстро настраивается, но с ростом числа пользователей всплывают проблемы: пароль можно скопировать и передать третьему лицу без вашего ведома, а скомпрометированный пароль не отличить от легитимного логина — в логах будет просто «ivan подключился», без привязки к конкретному устройству.

При взаимной сертификатной аутентификации (rightauth=pubkey вместо eap-mschapv2) каждый клиент предъявляет собственный сертификат, подписанный вашим CA. Скопировать его сложнее, чем пароль — это файл .p12 с приватным ключом, который либо экспортируют целиком, либо не работает вовсе. Но главное преимущество в управляемости: у каждого сертификата есть серийный номер, срок действия и CN с именем владельца. Отозвать доступ одному человеку — значит внести его серийный номер в список отзыва (CRL), не трогая сертификаты остальных.

Минус тоже есть: сертификаты сложнее в эксплуатации, чем пароли. Нужно генерировать .p12-файл на каждого пользователя, безопасно передавать его (не почтой в открытом виде), объяснять, как установить сертификат на телефон. Для команды из 3-5 человек, где важна прослеживаемость доступа, оно того стоит. Для личного VPN одного человека — избыточно, там EAP-пароль или вовсе WireGuard быстрее.

Разворачиваем собственный CA

Сервер должен быть уже установлен — strongSwan, ядро с ip_forward=1, открытые порты 500/4500 UDP. Если этого ещё нет, сначала пройдите базовую установку из статьи выше, а сюда возвращайтесь на этапе сертификатов.

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

mkdir -p ~/ca/{cacerts,certs,private,reqs}
chmod 700 ~/ca
cd ~/ca

Генерируем корневой ключ и самоподписанный сертификат CA сроком на 10 лет — CA живёт долго, его не переиздают при каждой ротации клиентских сертификатов:

ipsec pki --gen --type rsa --size 4096 --outform pem > private/ca-key.pem
chmod 600 private/ca-key.pem

ipsec pki --self --ca --lifetime 3650 \
  --in private/ca-key.pem --type rsa \
  --dn "CN=Company VPN Root CA" \
  --outform pem > cacerts/ca-cert.pem

Сертификат сервера подписываем этим же CA — замените vpn.example.com на реальный адрес:

ipsec pki --gen --type rsa --size 4096 --outform pem > private/server-key.pem

ipsec pki --pub --in private/server-key.pem --type rsa | \
ipsec pki --issue --lifetime 1825 \
  --cacert cacerts/ca-cert.pem \
  --cakey private/ca-key.pem \
  --dn "CN=vpn.example.com" \
  --san "vpn.example.com" \
  --flag serverAuth --flag ikeIntermediate \
  --outform pem > certs/server-cert.pem

cp cacerts/ca-cert.pem /etc/ipsec.d/cacerts/
cp certs/server-cert.pem /etc/ipsec.d/certs/
cp private/server-key.pem /etc/ipsec.d/private/
chmod 600 /etc/ipsec.d/private/server-key.pem

Приватный ключ CA (private/ca-key.pem) — самый чувствительный файл во всей схеме. Если он утечёт, злоумышленник сможет подписывать сертификаты от вашего имени, и единственный выход — полная замена CA и переиздание всех клиентских сертификатов. Держите его под chmod 600 и не копируйте на рабочие машины; для организаций с повышенными требованиями к безопасности разумно генерировать его на отдельной изолированной машине, перенося сюда только подписанные сертификаты.

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

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

Для нового сотрудника генерируем ключ и запрос, подписываем его от CA. CN должен быть уникальным — используйте email или логин, это станет идентификатором в логах и в CRL:

USER=ivan
DOMAIN=vpn.example.com

ipsec pki --gen --type rsa --size 4096 --outform pem > private/${USER}-key.pem

ipsec pki --pub --in private/${USER}-key.pem --type rsa | \
ipsec pki --issue --lifetime 730 \
  --cacert cacerts/ca-cert.pem \
  --cakey private/ca-key.pem \
  --dn "CN=${USER}@${DOMAIN}" \
  --san "${USER}@${DOMAIN}" \
  --flag clientAuth \
  --outform pem > certs/${USER}-cert.pem

Срок жизни клиентского сертификата (--lifetime 730 — два года) стоит держать заметно короче, чем у CA — это естественный механизм гигиены: даже если про отзыв забудут, доступ протухнет сам. Для команд с высокой текучкой разумно ставить 365 дней.

Пользователю нужен не набор отдельных файлов, а один .p12-контейнер с ключом, сертификатом и цепочкой до CA — так проще импортировать на телефон одним действием:

openssl pkcs12 -export \
  -inkey private/${USER}-key.pem \
  -in certs/${USER}-cert.pem \
  -certfile cacerts/ca-cert.pem \
  -name "${USER} VPN" \
  -out ${USER}.p12

Утилита запросит пароль на экспорт — отдельный секрет, защищающий сам файл .p12 при передаче (пароля от VPN в этой схеме вообще нет, авторизация только по сертификату). Передавайте .p12 по защищённому каналу — мессенджер с самоуничтожением, Vault, личная встреча — но не почтой в открытом виде.

Настройка ipsec.conf под сертификатную аутентификацию

Ключевое отличие от EAP-схемы — rightauth=pubkey вместо eap-mschapv2, и клиент теперь предъявляет сертификат, а не идентификатор с паролем:

config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

conn ikev2-cert
    auto=add
    compress=no
    type=tunnel
    keyexchange=ikev2
    fragmentation=yes
    rekey=no
    left=%any
    leftid=@vpn.example.com
    leftcert=server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any
    rightid=%any
    rightauth=pubkey
    rightsourceip=10.10.20.0/24
    rightdns=1.1.1.1,8.8.8.8
    rightsendcert=never
    ike=aes256-sha256-modp2048,aes256-sha1-modp2048!
    esp=aes256-sha256,aes256-sha1!

rightid=%any означает, что сервер примет любой сертификат, подписанный доверенным CA (тем, что лежит в /etc/ipsec.d/cacerts/) — не нужно перечислять каждого пользователя в конфиге отдельной строкой, доступ регулируется фактом наличия действующего сертификата плюс CRL для отзыва.

В /etc/ipsec.secrets теперь нужна только строка с ключом сервера — пользовательские пароли из файла убираем совсем:

: RSA server-key.pem

Перезапустите службу:

ipsec restart
ipsec statusall

Если в сети уже есть подключение по паролям (ikev2-vpn из базовой установки), можно оставить оба conn-блока одновременно — strongSwan разберёт входящий IKE_AUTH по типу аутентификации клиента, и старая схема продолжит работать, пока вы поэтапно переводите пользователей на сертификаты.

CRL: список отзыва и его публикация

Отзыв в PKI работает не через удаление сертификата (у пользователя он и так остаётся на устройстве), а через список отозванных серийных номеров — CRL, который сервер проверяет при каждом новом подключении. Генерируем пустой CRL сразу при разворачивании CA, чтобы механизм был готов до того, как понадобится первый отзыв:

mkdir -p ~/ca/crl
cd ~/ca

ipsec pki --signcrl --lifetime 30 \
  --cacert cacerts/ca-cert.pem \
  --cakey private/ca-key.pem \
  --outform pem > crl/ca.crl

cp crl/ca.crl /etc/ipsec.d/crls/

--lifetime 30 — срок действия самого CRL в днях, не сертификатов. По истечении strongSwan перестанет доверять устаревшему CRL, поэтому его нужно перевыпускать регулярно, даже если список отзыва не менялся. Практичнее всего — cron-задача:

cat > /etc/cron.d/ipsec-crl <<'EOF'
0 3 * * * root cd /root/ca && /usr/lib/ipsec/pki --signcrl --lifetime 30 --cacert cacerts/ca-cert.pem --cakey private/ca-key.pem --outform pem > crl/ca.crl && cp crl/ca.crl /etc/ipsec.d/crls/ && ipsec rereadcrls
EOF

Проверьте фактический путь до бинарника pki в вашей системе (which ipsec) — в некоторых сборках он вызывается напрямую как ipsec pki, без отдельного пути /usr/lib/ipsec/pki.

В ipsec.conf включите проверку CRL явно, если она не включена по умолчанию в вашей сборке strongSwan:

config setup
    charondebug="ike 1, knl 1, cfg 0, cfg 2"
    strictcrlpolicy=no

strictcrlpolicy=no — сознательный выбор для большинства сценариев: если CRL временно недоступен (например, ошибка cron-задачи), подключения не должны массово падать из-за отсутствия свежего списка. yes жёстче — без валидного CRL никто не подключится, — оправдано только там, где отзыв доступа критичнее доступности сервиса.

Отзыв доступа: пошагово

Когда сотрудник увольняется или теряет устройство, вам нужен серийный номер его сертификата. Посмотреть его можно прямо в файле сертификата:

openssl x509 -in ~/ca/certs/ivan-cert.pem -noout -serial

Добавьте сертификат в CRL, переиздав список с указанием отзываемого файла:

cd ~/ca
ipsec pki --signcrl --lifetime 30 \
  --cacert cacerts/ca-cert.pem \
  --cakey private/ca-key.pem \
  --cert certs/ivan-cert.pem --reason superseded \
  --outform pem > crl/ca.crl

cp crl/ca.crl /etc/ipsec.d/crls/
ipsec rereadcrls

Если у отозванного пользователя уже была активная сессия, rereadcrls не разорвёт её мгновенно — CRL проверяется при установлении нового соединения, а не постоянно во время работы туннеля. Чтобы завершить сессию сразу, найдите имя соединения и оборвите его вручную:

ipsec statusall | grep -i ivan
ipsec down ikev2-cert[<номер-сессии>]

Для срочных случаев (утеря устройства, подозрение на компрометацию) не полагайтесь только на CRL — сразу выполняйте оба шага: обновление CRL и принудительный разрыв активной сессии. Отдельно стоит вести реестр выданных сертификатов вне сервера (пользователь, CN, серийный номер, даты выдачи и истечения) — без него через год-два вы не вспомните, кому какой сертификат принадлежит.

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

.p12-файл содержит всё нужное для подключения — отдельно передавать ca-cert.pem не требуется, он уже упакован внутрь контейнера.

iOS / macOS. Отправьте .p12 на устройство, откройте файл — система запросит пароль экспорта и предложит установить профиль (на Mac — через Связку ключей). Далее в Настройки → VPN → Добавить конфигурацию → IKEv2 выберите установленный сертификат вместо ввода логина/пароля.

Windows. Импортируйте .p12 через certmgr.msc в «Личное» хранилище текущего пользователя (не в «Доверенные корневые», это ключ пользователя, а не CA). При создании VPN-подключения тип аутентификации — «Сертификат компьютера/пользователя».

Android. В приложении strongSwan (Google Play) — «Импортировать сертификат» с указанием .p12 и пароля, затем профиль с типом «IKEv2 Certificate».

ПлатформаКуда импортировать .p12Тип аутентификации в профиле
iOS / macOSПрофиль/Связка ключейСертификат (автоматически)
Windows 10/11certmgr.msc → ЛичноеСертификат компьютера/пользователя
AndroidПриложение strongSwanIKEv2 Certificate
Linux/etc/ipsec.d + swanctlpubkey

Арендуйте сервер под свои задачи!

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли совмещать EAP-пароли и сертификаты на одном сервере?

Да, достаточно держать два разных conn-блока в ipsec.conf с разными именами и разными rightauth — удобно на переходный период, пока не все пользователи переведены на сертификаты.

Что если пользователь потерял .p12, но устройство не скомпрометировано?

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

Нужно ли публиковать CRL на внешнем URL (CDP), как у публичных CA?

Нет, strongSwan проверяет CRL из локального файла /etc/ipsec.d/crls/, внешний Distribution Point не обязателен для одиночного сервера.

Что будет, если забыть продлить CRL при strictcrlpolicy=yes?

Все новые подключения начнут получать отказ, пока не появится свежий CRL — поэтому cron-задача на переиздание становится критичной инфраструктурой.

Команды выпуска и отзыва можно выполнить вручную, срочно, в обход cron?

Да, cron нужен только для регулярного переиздания CRL по сроку, а сам выпуск и отзыв — обычные команды ipsec pki, их можно запускать руками в любой момент.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →