Защита административных панелей веб-приложений (WordPress, Django, Laravel, 1С-Битрикс), дашбордов мониторинга (Grafana, Kibana, Uptime Kuma) и внутренних API-эндпоинтов традиционно возлагается на связку логина, пароля и двухфакторной аутентификации (2FA). Однако классическая модель авторизации на уровне прикладного уровня (HTTP) оставляет веб-сервер открытым для сканирования: боты и сканеры уязвимостей непрерывно брутфорсят формы входа, эксплуатируют 0-day уязвимости в CMS и анализируют HTTP-заголовки.
Архитектурно безупречным решением этой проблемы является **mTLS (Mutual TLS, взаимная аутентификация TLS)**. Если при обычном одностороннем HTTPS только сервер подтверждает свою подлинность браузеру через SSL-сертификат, то при двухстороннем mTLS веб-сервер требует предъявить доверенный клиентский криптографический сертификат еще на этапе установки шифрованного соединения (TLS Handshake).
Если у клиента нет закрытого ключа и сертификата, подписанного вашим доверенным удостоверяющим центром (CA), веб-сервер мгновенно сбрасывает TCP/TLS-соединение. Запрос злоумышленника или поискового робота даже физически не доходит до бэкенда приложения, защищая базу данных и код сайта от любых веб-атак.
1. Принцип работы mTLS: почему взаимная аутентификация надежнее паролей и 2FA
В стандартном протоколе HTTPS (One-Way TLS) процесс рукопожатия односторонний: клиент проверяет сертификат сервера, сверяет доменное имя и шифрует трафик. При включении **mTLS** процедура расширяется шагом взаимной аутентификации согласно стандарту RFC 8446 (TLS 1.3):
- Server Hello & CertificateRequest: Сервер отправляет клиенту свой SSL-сертификат и передает запрос
CertificateRequestс перечнем доверенных удостоверяющих центров (Distinguished Names). - Client Certificate & CertificateVerify: Браузер или клиент
curlвыбирает соответствующий локальный клиентский сертификат, подписывает случайный набор данных своим закрытым ключом и отправляет ответ серверу. - Криптографическая валидация: Веб-сервер (Nginx или Caddy) проверяет цифровую подпись клиента открытым ключом локального CA. Если проверка успешна — соединение устанавливается, а метаданные клиента (Common Name, email, организация) передаются в заголовках бэкенду.
🛡️ Архитектурное сравнение: mTLS против VPN и паролей (L7 vs L3/L4)
Важно понимать сетевую границу решений: VPN (WireGuard, OpenVPN, IPsec) работает на сетевом и транспортном уровнях (L3/L4), создавая маршрутизируемый туннель к внутренним подсетям, портам и DNS-серверам приватной инфраструктуры. Если скомпрометирован узел с VPN-клиентом, атакующий получает сетевую видимость всей внутренней сети (Lateral Movement).
mTLS реализует парадигму Zero Trust на прикладном уровне (L7): он не создает сетевой туннель и не дает доступа к подсетям. Клиент получает доступ строго к конкретному веб-сервису или API-эндпоинту на порту 443, даже если сервер находится в публичном интернете без VPN.
Границы применимости: mTLS является идеальным решением для межсервисной интеграции (Microservices, B2B API), распределенных команд без общего офисного VPN и защиты критических панелей на публичных VDS. Однако для персонального блога на одного автора mTLS может быть избыточен в эксплуатации — там вполне достаточно связки Cloudflare Zero Trust или надежного 2FA.
| Критерий безопасности | Пароль + 2FA (TOTP) | IP-Whitelist (Фаервол) | Двухсторонний mTLS |
|---|---|---|---|
| Точка отсечения атаки | Прикладной код (PHP / Node.js) | Сетевой фильтр ядра (iptables) | TLS-рукопожатие веб-сервера |
| Уязвимость к 0-day в CMS | Высокая (до авторизации) | Отсутствует (доступ ограничен) | Отсутствует (запрос не доходит) |
| Устойчивость к фишингу | Уязвимо (MITM-перехват токена) | Зависит от статики IP | Абсолютная (асимметричный ключ) |
| Удобство для мобильных | Ввод кода из приложения | Сложно (динамический 4G/5G IP) | Профиль сертификата (.p12) |
2. Развертывание собственного центра сертификации (CA) в OpenSSL
Для работы mTLS нам потребуется собственный изолированный удостоверяющий центр (Certificate Authority, CA). Попытка использовать публичные сертификаты от бесплатных сервисов вроде Let's Encrypt или коммерческих вендоров для клиентской аутентификации технически невозможна по двум фундаментальным причинам:
- Стандарты CA/Browser Forum и отсутствие
clientAuth EKU: Согласно базовым требованиям CAB Forum (Baseline Requirements) и политикам корневых хранилищ (Mozilla, Google Chrome, Apple), публичные WebPKI-сертификаты выпускаются со строгим ограничением назначения ключа — толькоid-kp-serverAuth(RFC 5280). Включение расширенияid-kp-clientAuthв публичные TLS-сертификаты прекращено. При попытке предъявить такой сертификат в mTLS-соединении криптографический стек веб-сервера немедленно отклонит рукопожатие из-за несоответствия Extended Key Usage (EKU). - Семантика доверия: Публичный CA подтверждает владение доменным именем (Domain Validation), а не личность сотрудника или сервиса. Для mTLS необходим контроль над субъектом сертификата (
Common Name, email, подразделение).
Именно поэтому единственно правильным решением является развертывание собственного автономного Root CA на базе OpenSSL 3.0+.
Подключитесь к вашему VDS по SSH и создайте изолированный каталог с ограниченными правами доступа:
# Создаем структуру каталогов для удостоверяющего центра
sudo mkdir -p /etc/ssl/local-ca/{private,certs,newcerts,crl}
sudo chmod 700 /etc/ssl/local-ca/private
cd /etc/ssl/local-ca
Сгенерируем защищенный закрытый ключ корневого сертификата длиной 4096 бит (или на эллиптических кривых Ed25519) и выпустим самоподписанный корневой сертификат со сроком действия 10 лет:
# 1. Генерируем мастер-ключ Root CA
openssl genrsa -out private/ca.key 4096
chmod 400 private/ca.key
# 2. Выпускаем самоподписанный корневой сертификат CA
openssl req -x509 -new -nodes -key private/ca.key -sha256 -days 3650 -subj "/C=RU/ST=Moscow/O=SysKit Secure Infrastructure/CN=SysKit Internal Root CA" -out certs/ca.crt
# Проверяем параметры созданного сертификата CA
openssl x509 -in certs/ca.crt -text -noout | grep -E "(Issuer|Subject|Not After)"
Файл certs/ca.crt содержит открытый ключ вашего CA. Именно его мы скормим Nginx и Caddy для валидации входящих клиентских подключений. Файл private/ca.key является секретным: любой, кто завладеет этим файлом, сможет выпускать валидные клиентские сертификаты для обхода вашей аутентификации.
3. Выпуск клиентских сертификатов и упаковка в формат PKCS#12 для браузеров
Теперь сгенерируем персональный клиентский сертификат для конкретного сотрудника (например, системного администратора). Каждый сертификат должен быть уникальным и содержать идентификатор пользователя в поле Common Name (CN).
cd /etc/ssl/local-ca
# 1. Генерируем закрытый ключ пользователя
openssl genrsa -out certs/alexey_client.key 2048
chmod 400 certs/alexey_client.key
# 2. Создаем запрос на подпись сертификата (CSR)
openssl req -new -key certs/alexey_client.key -subj "/C=RU/O=SysKit Engineering/CN=alexey.ivanov/emailAddress=alexey@example.com" -out certs/alexey_client.csr
# 3. Подписываем клиентский сертификат нашим Root CA со сроком 365 дней
openssl x509 -req -in certs/alexey_client.csr -CA certs/ca.crt -CAkey private/ca.key -CAcreateserial -out certs/alexey_client.crt -days 365 -sha256
Браузеры (Google Chrome, Яндекс Браузер, Mozilla Firefox, Safari) не умеют напрямую подключать пару отдельных файлов .key и .crt. Для импорта в системное хранилище сертификатов операционной системы требуется контейнер стандарта **PKCS#12 (.p12 или .pfx)**, защищенный транспортным паролем.
Упакуем сертификат пользователя, его закрытый ключ и открытый сертификат CA в единый файл .p12:
# Создаем контейнер PKCS#12 (система запросит пароль для защиты файла)
openssl pkcs12 -export -out certs/alexey_client.p12 -inkey certs/alexey_client.key -in certs/alexey_client.crt -certfile certs/ca.crt
🔑 Пароль защиты файла сертификата
При экспорте OpenSSL запросит пароль (Export Password). Обязательно задайте стойкий пароль, чтобы в случае случайного перехвата файла .p12 злоумышленник не смог извлечь закрытый ключ. Для создания стойких кодов воспользуйтесь инструментом Генератор надежных паролей онлайн.
Установка сертификата на клиентское устройство:
- Windows: Дважды щелкните по файлу
alexey_client.p12, запустится «Мастер импорта сертификатов». Выберите расположение «Текущий пользователь», введите пароль и поместите сертификат в хранилище «Личное» (Personal). - macOS: Откройте приложение «Связка ключей» (Keychain Access), перетащите файл
.p12в раздел «Вход» (login) → «Мои сертификаты». - Linux (curl / автоматизация): Передавайте сертификат напрямую через параметры командной строки:
curl --cert alexey_client.crt --key alexey_client.key --cacert ca.crt https://admin.example.com/api/status
4. Настройка mTLS в Nginx: глобальная и выборочная защита разделов сайта
В веб-сервере Nginx (версии 1.24+ / 1.26 LTS) за двухстороннюю валидацию TLS отвечают директивы ssl_client_certificate и ssl_verify_client. Существует два основных архитектурных сценария применения mTLS:
- Глобальный mTLS: Весь виртуальный хост (например, отдельный поддомен
admin.example.comилиapi-internal.example.com) требует сертификат. Без сертификата сервер даже не отдает код 403, а сбрасывает рукопожатие на уровне SSL. - Выборочный mTLS (Гибридный): Публичный сайт (
https://example.com) открыт всем посетителям, но административная панель (/admin,/wp-login.php) доступна строго при предъявлении валидного клиентского сертификата.
Разберем наиболее популярный гибридный сценарий. Скопируем сертификат нашего CA в каталог Nginx:
sudo mkdir -p /etc/nginx/certs
sudo cp /etc/ssl/local-ca/certs/ca.crt /etc/nginx/certs/ca.crt
sudo chmod 644 /etc/nginx/certs/ca.crt
Перед активацией SSL-директив в виртуальном хосте убедитесь, что публичные SSL-сертификаты для вашего сайта уже выпущены через утилиту certbot (если домен новый, предварительно получите сертификаты: sudo certbot certonly --webroot -w /var/www/html -d example.com -d admin.example.com). Если пути к /etc/letsencrypt/live/... отсутствуют на диске, проверка синтаксиса Nginx завершится с ошибкой.
Создадим конфигурацию виртуального хоста в /etc/nginx/sites-available/secure-site.conf:
# /etc/nginx/sites-available/secure-site.conf
server {
listen 80;
server_name example.com admin.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name example.com admin.example.com;
# Сертификаты самого сайта (выпущенные через Certbot / Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 1. Подключаем Root CA для проверки клиентских сертификатов
ssl_client_certificate /etc/nginx/certs/ca.crt;
# 2. Режим 'optional' позволяет запрашивать сертификат без разрыва обычных соединений
ssl_verify_client optional;
ssl_verify_depth 2;
# Публичный контент сайта доступен всем посетителям
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Закрытый административный раздел — пускаем только с валидным сертификатом!
location /admin {
# Если клиентский сертификат не прошел проверку CA — доступ заблокирован
if ($ssl_client_verify != SUCCESS) {
return 403 "Forbidden: Valid Client SSL Certificate Required
";
}
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Пробрасываем имя и почту аутентифицированного инженера в бэкенд
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
}
}
Для быстрой сборки готовых шаблонов веб-сервера воспользуйтесь нашим онлайн генератором конфигураций Nginx.
Проверим синтаксис и перезагрузим веб-сервер:
sudo nginx -t && sudo systemctl reload nginx
Теперь при попытке открыть https://example.com/admin обычный пользователь увидит статус 403 Forbidden, а владелец сертификата alexey.ivanov мгновенно подтвердит авторизацию во всплывающем окне браузера в один клик.
📊 Мониторинг и специализированное логирование mTLS
Для аудита безопасности критически важно фиксировать в логах Nginx, кто именно и с каким сертификатом совершал запросы. Добавьте в блок http файла /etc/nginx/nginx.conf расширенный формат логов:
log_format mtls_combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'client_verify="$ssl_client_verify" '
'client_dn="$ssl_client_s_dn" '
'client_serial="$ssl_client_serial"';
access_log /var/log/nginx/admin_access.log mtls_combined;
При жестком режиме (ssl_verify_client on;) Nginx генерирует специфические внутренние коды ошибок, которые полезно перехватывать для понятных сообщений пользователю:
- 495 (SSL Certificate Error): Клиент предоставил невалидный, поврежденный или отозванный сертификат.
- 496 (No SSL Certificate): Браузер или API-клиент вообще не прислал сертификат.
- 497 (HTTP to HTTPS): Обычный незашифрованный HTTP-запрос отправлен на порт HTTPS.
5. Выбор VDS для защищенной инфраструктуры и влияние TLS-рукопожатия на производительность
Внедрение двухсторонней аутентификации неизбежно увеличивает объем вычислений при установке соединений. Если при обычном TLS сервер только передает открытый сертификат и генерирует ключи Диффи-Хеллмана, то в mTLS сервер обязан асимметрично проверить цифровую подпись каждого клиентского запроса.
Чтобы шифрование не вызывало задержек и не создавало очередей, серверная инфраструктура должна отвечать следующим требованиям:
- Высокочастотные процессоры (3.3+ ГГц): Проверка подписей RSA-4096 и вычисление кривых ECDSA выполняются синхронно в потоке воркера Nginx. Чем выше тактовая частота ядра vCPU, тем быстрее завершается фаза TLS Handshake (типичное время проверки подписи составляет 1.5–3 мс на современных ядрах против 15–20 мс на перегруженных эконом-тарифах).
- Аппаратные инструкции AES-NI: Убедитесь, что гипервизор вашего хостинга пробрасывает аппаратные инструкции шифрования в виртуальную машину (проверяется командой
grep -m1 -o aes /proc/cpuinfo). - Кэширование TLS-сессий (Session Resumption): Включение
ssl_session_cache shared:SSL:10m;иssl_session_timeout 1d;позволяет повторным запросам от одного клиента использовать быстрый resumption без повторной валидации всей цепочки сертификата.
🔍 Экспресс-диагностика TLS-инфраструктуры
После включения защищенных протоколов протестируйте корректность серверных сертификатов через Проверку SSL / TLS сертификата, а также проверьте отсутствие утечек открытых портов панели через Сканер портов онлайн.
Рекомендуемые VDS-провайдеры
Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с
Timeweb Cloud — Быстрые NVMe VDS
Высокочастотные процессоры 3.3+ ГГц для мгновенной обработки криптографических TLS-рукопожатий, быстрые NVMe-диски и стабильный сетевой канал 1 Гбит/с.
Selectel — Надежные облачные серверы
Отказоустойчивая инфраструктура в сертифицированных дата-центрах Tier III для размещения корпоративных CA и закрытых внутренних API.
Beget — Простота для веб-разработчиков
Удобное управление веб-серверами Nginx, автоматические ежедневные бэкапы конфигураций и отзывчивая техническая поддержка 24/7.
6. Реализация mTLS в современном веб-сервере Caddy 2
Для веб-сервера Caddy 2 (актуальная стабильная ветка 2.8+) двухсторонняя аутентификация настраивается с помощью встроенного модуля client_auth блока tls. Caddy автоматически выпускает и обновляет публичные сертификаты Let's Encrypt для домена, одновременно валидируя входящие клиентские ключи по вашему локальному Root CA.
Скопируем сертификат CA в каталог Caddy:
sudo mkdir -p /etc/caddy/certs
sudo cp /etc/ssl/local-ca/certs/ca.crt /etc/caddy/certs/ca.crt
sudo chmod 644 /etc/caddy/certs/ca.crt
Отредактируем конфигурационный файл /etc/caddy/Caddyfile:
# /etc/caddy/Caddyfile
admin.example.com {
tls {
# Настраиваем двухстороннюю аутентификацию
client_auth {
mode require_and_verify
trusted_ca_cert_file /etc/caddy/certs/ca.crt
}
}
# Проксируем проверенные запросы на внутренний сервис
reverse_proxy 127.0.0.1:8080 {
header_up X-Client-Subject {http.request.tls.client.san.emails}
header_up X-Client-Issuer {http.request.tls.client.issuer}
}
}
В Caddy доступны несколько режимов mode:
require_and_verify: жесткий режим. Подключение обрывается на этапе TLS-рукопожатия, если клиент не предоставил сертификат или подпись не сошлась с CA.verify_if_given: мягкий аналог Nginxoptional. Если клиент прислал сертификат — он валидируется, если нет — запрос пропускается дальше для обработки на прикладном уровне.
Применим конфигурацию Caddy без простоя соединений:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo caddy reload --config /etc/caddy/Caddyfile
⚠️ Защита от режима «fail-open» в Caddy и Go crypto/tls
При эксплуатации Caddy системному администратору необходимо учитывать архитектурную особенность стандартной библиотеки Go crypto/tls: если пул доверенных клиентских сертификатов ClientCAs не инициализирован (файл trusted_ca_cert_file не существует, поврежден или недоступен для чтения пользователю caddy), Go в определенных конфигурациях может откатиться к системному хранилищу ОС (x509.SystemCertPool()). В результате веб-сервер переходит в опаснейший режим fail-open, начиная принимать клиентские сертификаты от любых публичных CA.
Как гарантировать fail-closed:
- Всегда проверяйте валидность конфига через
caddy validateперед перезагрузкой службы. - Проверяйте права на файл CA:
sudo chown -R caddy:caddy /etc/caddy/certs && sudo chmod 644 /etc/caddy/certs/ca.crt. - Используйте стабильные актуальные сборки Caddy (ветки 2.8+ / 2.9+ / 2.11+) и проверяйте журнал
journalctl -u caddy -eна отсутствие предупреждений загрузки TLS. - Защита от спуфинга заголовков: Директивы
header_upпринудительно перезаписывают клиентские заголовки. Даже если злоумышленник отправит поддельный заголовокX-Client-Subjectв открытом HTTP-запросе, Caddy полностью сотрет его и передаст в бэкенд строго валидированный субъект из криптографического сертификата.
7. Отзыв скомпрометированных сертификатов через списки CRL
Один из главных практических вопросов при эксплуатации mTLS: что делать, если сотрудник уволился или потерял ноутбук с закрытым ключом? Перевыпускать корневой сертификат CA и обновлять ключи всем остальным сотрудникам нельзя.
Для точечной блокировки используется механизм **CRL (Certificate Revocation List)** — криптографически подписанный список отозванных серийных номеров сертификатов.
Инициализируем базу данных учета сертификатов OpenSSL в каталоге CA:
cd /etc/ssl/local-ca
touch index.txt
echo 1000 > crlnumber
Создадим минимальный конфигурационный файл /etc/ssl/local-ca/crl.cnf:
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /etc/ssl/local-ca
database = $dir/index.txt
crlnumber = $dir/crlnumber
certificate = $dir/certs/ca.crt
private_key = $dir/private/ca.key
default_md = sha256
default_crl_days = 30
При необходимости отозвать сертификат сотрудника выполните:
# 1. Отзываем скомпрометированный сертификат
openssl ca -config crl.cnf -revoke certs/alexey_client.crt
# 2. Генерируем обновленный файл списка отзыва
openssl ca -config crl.cnf -gencrl -out crl/crl.pem
# 3. Копируем файл CRL в Nginx и перезагружаем веб-сервер
sudo cp crl/crl.pem /etc/nginx/certs/crl.pem
sudo systemctl reload nginx
В конфигурационный блок Nginx добавляется всего одна директива:
# Подключаем список отозванных сертификатов
ssl_crl /etc/nginx/certs/crl.pem;
После перезагрузки Nginx клиент с отозванным сертификатом немедленно получит ошибку рукопожатия TLS, даже если срок действия его файла формально еще не истек.
⚡ CRL против OCSP: почему не бывает «Client OCSP Stapling»
Среди инженеров нередко возникает путаница вокруг технологий CRL, OCSP и OCSP Stapling применительно к mTLS. Разберем технические стандарты:
- OCSP Stapling (RFC 6066 / TLS 1.3): Применяется исключительно для серверных сертификатов. Веб-сервер опрашивает публичный CA (например, Let's Encrypt), получает подписанную метку времени о валидности своего доменного сертификата и «прикрепляет» (staples) её к ответу клиенту, избавляя браузер от лишнего сетевого запроса. Для клиентских сертификатов механизма stapling в веб-серверах и браузерах не существует.
- Серверная проверка OCSP (
ssl_ocsp on): Начиная с Nginx 1.19+, сервер может в реальном времени обращаться по протоколу HTTP к внешнему OCSP-ответчику для проверки присланного клиентского сертификата. Однако это требует развертывания и непрерывного мониторинга выделенного сервиса OCSP Responder с поддержкой 99.99% SLA. Если responder упадет — аутентификация всех администраторов заблокируется. - Списки CRL (
ssl_crl): Локальный статический файл отзыва. Не создает задержек на сетевые запросы при рукопожатии, работает автономно даже при полной изоляции сети и является стандартом надежности для частных локальных CA.
8. Эксплуатация в Production: аппаратная защита ключей (YubiKey / TPM) и автоматизация ротации
Для перевода архитектуры mTLS на уровень зрелой промышленной эксплуатации (Production-ready) сисадмину необходимо закрыть вопросы управления жизненным циклом ключей:
1. Аппаратная защита закрытых ключей (Hardware Tokens & TPM)
Хранение файла .p12 на диске ноутбука несет остаточный риск компрометации в случае вредоносного ПО. Максимальный класс безопасности достигается генерацией закрытого ключа непосредственно внутри аппаратного криптографического чипа:
- Аппаратные токены (YubiKey / JaCarta): Через стандарт PIV (PKCS#11) ключевая пара генерируется на самом ключе. Закрытый ключ физически невозможно скопировать или извлечь из чипа; каждое рукопожатие требует физического касания сенсора токена (Touch Policy).
- Встроенные модули TPM 2.0 / Apple Secure Enclave: Корпоративные MDM-системы позволяют выпускать клиентские сертификаты напрямую в криптографический анклав операционной системы без возможности экспорта закрытого ключа в виде открытого файла.
2. Автоматизация ротации: переход на Short-Lived сертификаты
Выпуск клиентских сертификатов на 1–2 года создает проблему накопления списков отзыва CRL. Передовой практикой 2026 года является автоматический выпуск короткоживущих сертификатов (сроком от 7 до 30 дней):
- Срок действия сертификата истекает сам по себе, что снижает потребность в ручном отзыве уволенных сотрудников.
- Инструменты автоматизации 2026 года: Для автоматического выпуска и ротации клиентских mTLS-сертификатов в масштабе инфраструктуры применяются Step-CA (Smallstep) или модуль HashiCorp Vault PKI Secrets Engine с интеграцией в CI/CD, ACME и Kubernetes cert-manager.
9. Обязательное негативное тестирование (Negative Testing) перед запуском
Перед открытием боевого доступа к панели или API сисадмин обязан провести серию негативных тестов. Архитектура mTLS считается надежно внедренной только тогда, когда сервер безошибочно блокирует все виды нелегитимных подключений:
| Тестовый сценарий | Команда проверки (curl) | Ожидаемый результат |
|---|---|---|
| 1. Запрос без сертификата | curl -s -o /dev/null -w "%{http_code}" https://admin.example.com |
403 Forbidden (в гибридном Nginx) или сброс TLS SSL_ERROR_BAD_CERT_ALERT |
| 2. Запрос с чужим/левым сертификатом | curl --cert /tmp/untrusted.crt --key /tmp/untrusted.key https://admin.example.com |
Разрыв рукопожатия TLS (сервер отвергает подпись стороннего CA) |
| 3. Запрос с отозванным сертификатом | curl --cert certs/alexey_client.crt --key certs/alexey_client.key https://admin.example.com |
Разрыв соединения TLS с ошибкой проверки списка отзыва CRL |
| 4. Легитимный запрос инженера | curl --cert certs/alexey_client.crt --key certs/alexey_client.key https://admin.example.com |
200 OK — авторизация подтверждена без ввода логина и пароля |
10. Итоговый чек-лист сисадмина по внедрению mTLS
📋 Чек-лист проверки и ввода в эксплуатацию mTLS
- Безопасность ключа CA: Закрытый ключ
ca.keyзащищен правамиchmod 400и хранится в изолированной среде. - Защита Caddy от fail-open: Конфиг проверен командой
caddy validate, права на чтениеca.crtпользователемcaddyподтверждены. - Сетевое разграничение: mTLS защищает вход на уровне L7, а внутренние порты (8080, 3000) жестко привязаны к
127.0.0.1(проверено через Сканер портов). - Мониторинг логов: В Nginx включен формат
mtls_combinedс фиксацией$ssl_client_s_dnи кодов 495/496. - Экспорт сертификатов: Клиентские файлы упакованы в контейнер PKCS#12 со стойким транспортным паролем или привязаны к аппаратному токену (YubiKey).
- Регламент отзыва (CRL): Создан и протестирован скрипт отзыва сертификатов при компрометации устройства.
- Негативное тестирование: Выполнены все 3 негативных теста curl (без сертификата, с чужим CA, с отозванным ключом).
- Резервное копирование CA: Каталог
/etc/ssl/local-caзабэкаплен в зашифрованное хранилище по правилу 3-2-1.