Практическая шпаргалка для понимания сертификатов, устранения ошибок TLS-рукопожатия и отладки реальных проблем с помощью OpenSSL, curl и Kubernetes.
|
Примечание
|
Ошибки TLS вроде «CERTIFICATE_VERIFY_FAILED» или «unable to get local issuer certificate» — одни из самых неприятных проблем в продакшн-системах. |
🎯 В этом руководстве мы разбираем TLS от основ до реальной отладки с помощью OpenSSL, curl и Kubernetes.
🔎 Что вы узнаете
К концу руководства вы сможете:
-
понять, как работают удостоверяющие центры (Certificate Authorities, CA);
-
эффективно использовать OpenSSL для инспекции и отладки сертификатов;
-
создать собственный корневой CA и подписать им серверные сертификаты;
-
проверять TLS-рукопожатие локально;
-
разбираться в распространённых кодах TLS-оповещений (TLS alert) и кодах возврата x509;
-
работать с TLS в среде Kubernetes.
🔐 Что такое удостоверяющий центр (CA)?
Удостоверяющий центр — это доверенная организация, которая:
-
выдаёт и подписывает цифровые сертификаты (как публичные организации, например DigiCert, так и внутренние корпоративные системы);
-
верифицирует личность (по аналогии с паспортным столом);
-
обеспечивает защищённый обмен данными.
⚠️ Почему ошибки TLS встречаются так часто?
Большинство сбоев TLS происходит по следующим причинам:
-
отсутствие цепочки CA;
-
неправильная запись SAN (Subject Alternative Name);
-
некорректное использование ключа (Key Usage);
-
неверно настроенные секреты Kubernetes;
-
ошибки в ограничениях CA.
Всё это разбирается в руководстве с реальными командами.
🧰 Шпаргалка по командам OpenSSL
1. Команды для инспекции сертификатов
🔹 Просмотр полного сертификата
openssl x509 -in RootCA.pem -text
openssl x509 -in RootCA.pem -text -noout
🔹 Проверка срока действия
openssl x509 -noout -dates -in RootCA.pem
-
Дата начала действия
openssl x509 -startdate -noout -in RootCA.pem
-
Дата окончания действия
openssl x509 -enddate -noout -in RootCA.pem
🔹 Извлечение Subject
openssl x509 -noout -subject -in RootCA.pem
🔹 Извлечение Issuer
openssl x509 -noout -issuer -in RootCA.pem
🔹 Извлечение SAN
openssl x509 -in RootCA.pem -text -noout | grep -A1 "Subject Alternative Name"
🔹 Проверка типа ключа
openssl x509 -in RootCA.pem -text -noout | grep "Public Key Algorithm"
2. Операции с закрытым ключом
🔹 Генерация RSA-ключа длиной 4096 бит
openssl genrsa -out tls.key 4096
🔹 Генерация RSA-ключа с шифрованием AES-256
openssl genrsa -aes256 -out tls.key 4096
🔹 Просмотр сгенерированного RSA-ключа
openssl rsa -in tls.key -text
openssl rsa -in tls.key -text -noout
🔹 Удаление парольной фразы
openssl rsa -in encrypted.key -out decrypted.key
🔹 Проверка сгенерированного RSA-ключа
openssl rsa -check -in tls.key
🔹 Извлечение открытого ключа из закрытого
openssl rsa -in tls.key -pubout -out tls.pub
3. Проверка соответствия сертификата и закрытого ключа
Сравнение модулей (Modulus):
openssl x509 -noout -modulus -in tls.crt | openssl md5
openssl rsa -noout -modulus -in tls.key | openssl md5
|
Примечание
|
Хеши должны совпадать. |
4. Проверка TLS-соединения с удалённым хостом
openssl s_client -connect <fqdn>:<port> -cert <path-to-client-cert> -key <path-to-client-key> -CAfile <path-to-root-ca-cert>
5. Загрузка корневого или серверного сертификата с удалённого хоста
Укажите FQDN или IP-адрес и порт:
openssl s_client -showcerts -connect <fqdn>:<port> </dev/null 2>/dev/null | sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > RootCA.pem
6. Получение дополнительных сведений о корневом или серверном сертификате
openssl s_client -showcerts -connect <fqdn>:<port> </dev/null 2>/dev/null > RootCA.pem
🏛 Создание CA и самоподписанного серверного сертификата
Самоподписанный сертификат (self-signed certificate) — это сертификат, не выданный удостоверяющим центром: в нём поля Subject и Issuer совпадают. Важно отметить, что корневой сертификат тоже является самоподписанным.
-
🔐 Создайте собственный CA.
-
🔑 Сгенерируйте зашифрованный закрытый ключ сервера.
-
🗒 Сгенерируйте CSR (Certificate Signing Request, запрос на подпись сертификата).
-
✍️ Подпишите серверный сертификат с помощью созданного CA.
-
✅ Проверьте цепочку сертификатов.
Создание собственного CA
🔹 Сначала создайте файл rootca.cnf с конфигурацией CA — он используется при генерации корневого сертификата. Секция расширений помечена как критическая (Critical Section):
[ req ]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_ca
[ dn ]
C = IN
ST = GUJARAT
L = Ahmedabad
OU = TechInsightDev
CN = ROOTCA
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
⚠️ Если basicConstraints не помечен как critical, строгие клиенты OpenSSL завершат проверку с ошибкой.
🔹 Генерация закрытого корневого ключа
openssl genrsa -out RootCA.key 4096
🔹 Генерация сертификата CA
openssl req -x509 -new -nodes -key RootCA.key -sha256 -days 1825 -out RootCA.pem -config rootca.cnf
🏁 Срок действия корневого сертификата задаётся флагом -days.
🔹 Конфигурация серверного сертификата с SAN. Файл server.cnf приведён для сервера в США:
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[req_distinguished_name]
CN = techinsight.com
OU = TechInsightDev
L = Sacramento
ST = California
C = US
[req_ext]
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = techinsight.com
DNS.2 = techinsight.dev.com
# IP Address can be mapped as well
# [ alt_names ]
# DNS.1 = localhost
# IP.1 = 127.0.0.1
🔹 Генерация CSR и закрытого ключа сервера
openssl req -nodes -new -keyout tls.key -out tls.csr --config server.cnf
🔹 Подписание серверного сертификата корневым CA
openssl x509 -req -in tls.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -out tls.crt -days 1825 -sha256 -extensions req_ext -extfile server.cnf
🔹 Проверка цепочки сертификатов относительно CA
openssl verify -CAfile RootCA.pem tls.crt
tls.crt: OK
На этом этапе вы успешно создали доверенную цепочку сертификатов, обеспечивающую защищённое TLS-соединение между клиентом и сервером.
🧪 Локальное тестирование CA и серверного сертификата
-
🖥 Один процесс выступает в роли TLS-клиента.
-
💻 Другой процесс выступает в роли TLS-сервера.
-
🔐 Проверяется корректность TLS-рукопожатия.
-
✅ Цепочка сертификатов проверяется с помощью созданного CA.
▪️Способ 1️⃣: Тестирование через командную строку OpenSSL (самый простой вариант)
Запустите TLS-сервер:
openssl s_server -cert tls.crt -key tls.key -CAfile RootCA.pem -accept 8080 -www
Сервер начнёт слушать на localhost:8080.
Откройте второй терминал и подключитесь как TLS-клиент:
openssl s_client -connect localhost:8080 -CAfile RootCA.pem -msg -debug
В консоли должен появиться вывод, подтверждающий ✅ успешное рукопожатие:
SSL-Session:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
....
Start Time: 1774086113
Timeout : 7200 (sec)
Verify return code: 0 (ok)
▪️Способ 2️⃣: Тестирование через веб-браузер
Примечание: требуется установленный nginx.
-
Отредактируйте
nginx.confв секции HTTPS-сервера.
Укажите порт, на котором будет работать сервер, и пути к ssl_certificate и ssl_certificate_key.
-
Добавьте имя хоста в файл
/etc/hosts.
-
Откройте браузер и перейдите по адресу https://localhost:8081.
Браузер выдаст ошибку: ERR_CERT_AUTHORITY_INVALID.
Это происходит по следующим причинам:
-
Созданный приватный CA не является публично доверенным, и его сертификаты не включены в стандартные хранилища браузеров и операционных систем.
-
Браузеры не доверяют ему по умолчанию.
Решения:
-
Импортировать CA в системное хранилище доверия (trust store), или
-
использовать команду
curlс явным указаниемRootCA.pem— она отработает успешно:
curl https://techinsight.dev.com:8081 --cacert RootCA.pem
-
Добавьте приватный CA в системное хранилище доверия.
macOS:
sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" RootCA.pem
Linux/Ubuntu:
sudo cp rootCA.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
После добавления сертификат появится в хранилище системных корневых сертификатов (System Roots). Пример из приложения Keychain Access на macOS:
-
Перейдите по адресу https://techinsight.dev.com:8081 — должна отобразиться стандартная страница nginx.
▪️Способ 3️⃣: Тестирование через командную строку curl
Запустите TLS-сервер:
openssl s_server -cert tls.crt -key tls.key -accept 8080 -www
В другом терминале выполните запрос через curl:
curl https://techinsight.dev.com:8081 --cacert RootCA.pem
🚨 Распространённые коды возврата x509 Verify
🚨 Распространённые коды TLS-оповещений (Protocol Level)
Пример:
sslv3 alert certificate unknown (46)
Означает, что удалённая сторона отклонила ваш сертификат.
Наиболее частые сбои в продакшне
🔴 Несоответствие имени хоста (Hostname mismatch) — в SAN отсутствует нужная запись DNS/IP.
🔴 CA не является доверенным (CA Not Trusted) — у клиента отсутствует файл CA.
🔴 Неверное расширенное использование ключа (Extended Key Usage).
Отсутствует:
extendedKeyUsage = serverAuth
🔴 У CA отсутствует критическое ограничение Basic Constraints.
Должно быть:
basicConstraints = critical, CA:TRUE
🔴 Unable to get local issuer certificate — отсутствует цепочка CA.
🔴 Bad certificate — неверный ключ или несоответствие между ключом и сертификатом.
☸️ Работа с TLS-секретами в Kubernetes
⚠️ Kubernetes не поддерживает закрытые ключи, защищённые парольной фразой, при создании TLS-секретов.
Создание секрета из сертификата:
kubectl create secret tls my-tls \
--key tls.key \
--cert tls.crt \
--dry-run=client -o yaml | kubectl apply -f -
🔴 Создание завершится ошибкой, если ключ зашифрован парольной фразой.
Просмотр секрета:
kubectl get secret my-tls -o jsonpath='{.data.tls\.crt}' | base64 -d > tls.crt
⚙️ Чеклист отладки (реальный инцидент)
-
Проверить срок действия сертификата.
-
Проверить записи SAN.
-
Проверить критический флаг CA.
-
Убедиться, что ключ соответствует сертификату.
-
Проверить полную цепочку.
-
Протестировать с флагом
-verify_return_error. -
Сравнить коды TLS-оповещений и коды возврата x509.
-
Проверить расширенное использование ключа (EKU).
-
Убедиться, что секрет Kubernetes обновлён.
📓 Рекомендации по SAN
Всегда включайте:
DNS.1 = service.namespace.svc.cluster.local
DNS.2 = service
DNS.3 = localhost
IP.1 = 127.0.0.1
Современные реализации TLS полностью игнорируют поле CN.
🏁 Заключение
Отладка TLS поначалу кажется запутанной, но становится предсказуемой, когда вы понимаете:
-
как работают цепочки сертификатов;
-
почему SAN обязателен;
-
как проверяется доверие к CA;
-
в чём разница между TLS-оповещениями и ошибками x509.
С командами и реальными сценариями из этой статьи у вас теперь есть готовый к продакшну инструментарий для отладки:
-
неправильно настроенных сертификатов;
-
проверки TLS/SSL-рукопожатия;
-
проблем с TLS в Kubernetes.
Если это руководство помогло вам разобраться с TLS или устранить ошибки — поставьте 👏 и поделитесь с командой! Возможно, это сэкономит кому-то часы поиска неисправностей.