OpenSSL — это отраслевой стандартный набор инструментов для управления TLS/SSL-сертификатами. Независимо от того, генерируете ли вы самоподписанные сертификаты для разработки, создаёте Certificate Signing Requests для production или отлаживаете проблемы с сертификатами, OpenSSL незаменим. В этом руководстве рассматривается практическое управление SSL/TLS-сертификатами с точки зрения senior-разработчика.
Зачем понимать OpenSSL
Каждому разработчику следует знать OpenSSL, потому что:
- Локальная разработка: самоподписанные сертификаты для тестирования HTTPS
- Развёртывания в production: генерация CSR для сертификатов от CA
- Отладка: проверка сертификатов и соединений
- Аудиты безопасности: анализ цепочек сертификатов и сроков действия
- Автоматизация: написание скриптов для управления сертификатами
Основы сертификатов
Ключевые понятия
- Private Key: секретный ключ, никогда не передавайте (
.key) - Public Key: производный от private key, безопасно передавать
- CSR: Certificate Signing Request, отправляется в CA (
.csr) - Certificate: подписанный public key с метаданными (
.crt, .pem) - CA: Certificate Authority, доверенный подписант
- Chain: сертификаты CA, связывающие с root CA
Форматы файлов
| Extension | Format | Contains |
|---|
.pem | Base64 encoded | Keys, certs, or both |
.crt | Usually PEM | Certificate only |
.key | Usually PEM | Private key only |
.der | Binary | Certificate |
.p12/.pfx | Binary | Key + cert bundle |
Генерация самоподписанных сертификатов
Быстрый самоподписанный сертификат
# Сгенерировать ключ и сертификат одной командой
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout server.key \
-out server.crt \
-days 365 \
-subj "/CN=localhost/O=Development/C=US"
С Subject Alternative Names (SAN)
Современные браузеры требуют SAN для localhost:
# Создать файл конфигурации
cat > san.cnf << 'EOF'
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = localhost
O = Development
C = US
[v3_req]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
DNS.3 = myapp.local
IP.1 = 127.0.0.1
IP.2 = ::1
EOF
# Сгенерировать сертификат
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout server.key \
-out server.crt \
-days 365 \
-config san.cnf \
-extensions v3_req
Создание локального Certificate Authority
Для сред разработки, где требуется несколько сертификатов:
Шаг 1: Создать CA
##!/bin/bash
OUTPUT_FOLDER=./certs
CA_DOMAIN="ca.local"
COMPANY="MyCompany"
COUNTRY="US"
mkdir -p $OUTPUT_FOLDER
# Конфигурация CA
cat > $OUTPUT_FOLDER/ca.cnf << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_req
prompt = no
encrypt_key = no
[req_distinguished_name]
CN = $CA_DOMAIN
O = $COMPANY
C = $COUNTRY
[v3_req]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical, CA:TRUE, pathlen:3
keyUsage = critical, cRLSign, keyCertSign
nsCertType = sslCA, emailCA
EOF
# Сгенерировать сертификат CA
openssl req -x509 -sha256 -days 3650 -newkey rsa:4096 -nodes \
-config $OUTPUT_FOLDER/ca.cnf \
-keyout $OUTPUT_FOLDER/ca.key \
-out $OUTPUT_FOLDER/ca.crt
echo "CA certificate created: $OUTPUT_FOLDER/ca.crt"
Шаг 2: Подписать сертификаты с помощью CA
##!/bin/bash
DOMAIN=$1 # Например, myapp.local
OUTPUT_FOLDER=./certs
# Конфигурация серверного сертификата
cat > $OUTPUT_FOLDER/$DOMAIN.cnf << EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_ca
prompt = no
encrypt_key = no
default_bits = 4096
[req_distinguished_name]
CN = $DOMAIN
O = MyCompany
C = US
[v3_req]
basicConstraints = critical, CA:FALSE
[v3_ca]
basicConstraints = critical, CA:FALSE
authorityKeyIdentifier = keyid:always, issuer:always
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:$DOMAIN, DNS:*.$DOMAIN
EOF
# Сгенерировать CSR
openssl req -new -sha256 \
-keyout $OUTPUT_FOLDER/$DOMAIN.key \
-out $OUTPUT_FOLDER/$DOMAIN.csr \
-config $OUTPUT_FOLDER/$DOMAIN.cnf
# Подписать с помощью CA
openssl x509 -req -sha256 -days 365 \
-in $OUTPUT_FOLDER/$DOMAIN.csr \
-CA $OUTPUT_FOLDER/ca.crt \
-CAkey $OUTPUT_FOLDER/ca.key \
-CAcreateserial \
-out $OUTPUT_FOLDER/$DOMAIN.crt \
-extensions v3_ca \
-extfile $OUTPUT_FOLDER/$DOMAIN.cnf
# Создать полную цепочку
cat $OUTPUT_FOLDER/$DOMAIN.crt $OUTPUT_FOLDER/ca.crt > $OUTPUT_FOLDER/$DOMAIN.fullchain.crt
# Очистка
rm $OUTPUT_FOLDER/$DOMAIN.csr $OUTPUT_FOLDER/$DOMAIN.cnf
echo "Certificate created: $OUTPUT_FOLDER/$DOMAIN.crt"
Шаг 3: Доверять сертификату CA
Linux (CentOS/RHEL):
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/myca.crt
sudo update-ca-trust
Linux (Ubuntu/Debian):
sudo cp ca.crt /usr/local/share/ca-certificates/myca.crt
sudo update-ca-certificates
Linux (openSUSE):
sudo cp ca.crt /usr/share/pki/trust/anchors/myca.crt
sudo update-ca-certificates --force
macOS:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.crt
Firefox: Перейдите в about:preferences → Privacy & Security → View Certificates → Authorities → Import
Chrome: Перейдите в chrome://settings/certificates → Authorities → Import
Генерация CSR для production
Создать CSR для подписания CA
# Сгенерировать private key
openssl genrsa -out example.com.key 4096
# Сгенерировать CSR
openssl req -new -key example.com.key -out example.com.csr \
-subj "/CN=example.com/O=My Company/L=New York/ST=NY/C=US"
# Проверить CSR
openssl req -text -noout -verify -in example.com.csr
CSR с SAN
# Создать конфигурацию
cat > csr.cnf << 'EOF'
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = example.com
O = My Company
L = New York
ST = NY
C = US
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
EOF
# Сгенерировать CSR с SAN
openssl req -new -key example.com.key -out example.com.csr -config csr.cnf
Проверка сертификатов
Просмотр сведений о сертификате
# Просмотреть локальный сертификат
openssl x509 -text -noout -in certificate.crt
# Просмотреть удалённый сертификат
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -text -noout
# Проверить дату истечения срока действия
openssl x509 -enddate -noout -in certificate.crt
# Просмотреть цепочку сертификатов
openssl s_client -connect example.com:443 -showcerts
Проверка соответствия сертификата и ключа
# Сравнить modulus
openssl x509 -modulus -noout -in certificate.crt | md5sum
openssl rsa -modulus -noout -in private.key | md5sum
# Оба должны совпадать
Проверка цепочки сертификатов
# Проверить относительно CA
openssl verify -CAfile ca.crt server.crt
# Проверить полную цепочку
openssl verify -CAfile ca-bundle.crt -untrusted intermediate.crt server.crt
Конвертация между форматами
PEM в DER
openssl x509 -outform der -in certificate.pem -out certificate.der
DER в PEM
openssl x509 -inform der -in certificate.der -out certificate.pem
Создать PKCS12 bundle
# Объединить ключ и сертификат в .p12
openssl pkcs12 -export \
-out certificate.p12 \
-inkey private.key \
-in certificate.crt \
-certfile ca.crt
# Извлечь из .p12
openssl pkcs12 -in certificate.p12 -out extracted.pem -nodes
Тестирование SSL-соединений
Тест HTTPS-сервера
# Базовый тест соединения
openssl s_client -connect example.com:443
# С SNI (требуется для большинства серверов)
openssl s_client -connect example.com:443 -servername example.com
# Проверить конкретную версию TLS
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
# Проверить поддерживаемые cipher suites
openssl s_client -connect example.com:443 -cipher 'ECDHE-RSA-AES256-GCM-SHA384'
Тест SMTP с STARTTLS
openssl s_client -connect mail.example.com:587 -starttls smtp
Использование сертификатов
Nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.fullchain.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
}
Node.js
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt'),
ca: fs.readFileSync('ca.crt') // Опционально: для проверки client cert
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Secure!');
}).listen(443);
Docker Compose
services:
nginx:
image: nginx:alpine
volumes:
- ./certs/server.crt:/etc/nginx/ssl/server.crt:ro
- ./certs/server.key:/etc/nginx/ssl/server.key:ro
environment:
- NODE_TLS_REJECT_UNAUTHORIZED=0 # Только для разработки!
Ключевые выводы
- SAN обязателен: современным браузерам нужны Subject Alternative Names
- Локальный CA для команд: используйте один CA совместно, генерируйте несколько сертификатов
- Никогда не коммитьте ключи: добавьте
*.key в .gitignore - Тестируйте соединения: используйте
openssl s_client для отладки - Сопоставляйте ключ и сертификат: проверяйте modulus перед развёртыванием
- Автоматизируйте продление: отслеживайте срок действия, автоматизируйте регенерацию скриптами
OpenSSL — основа управления TLS/SSL; владение этими командами экономит часы отладки и обеспечивает безопасные рабочие процессы разработки.