Внутренний private CA на базе OpenSSL — классическое решение для компаний, где нужно массово выдавать TLS‑сертификаты для внутренних сервисов, VPN, mTLS между микросервисами, LDAP, SMTP и т. д. Даже если вы давно ставите Let’s Encrypt на внешний периметр, внутри кластера или корпоративной сети без собственного центра сертификации часто никак.
Ниже — практическое пошаговое руководство в стиле «с нуля до рабочего private CA». Минимум теории, максимум конкретики: структура директорий, конфиг OpenSSL, корневой и промежуточный CA, выпуск и отзыв сертификатов, безопасное хранение ключей, базовая автоматизация.
Что такое private CA и когда он нужен
CA (Certificate Authority) — это доверенный центр, который подписывает и выпускает сертификаты. В случае public CA (коммерческие, Let’s Encrypt и др.) корневые сертификаты уже предустановлены в браузеры и ОС. Private CA — это ваш собственный CA, которому доверяют только ваши клиенты и серверы после ручной или автоматизированной установки корневого сертификата.
Где private CA особенно полезен DevOps и администраторам:
- Внутренний TLS для сервисов: API, internal dashboards, админки, dev/stage окружения.
- mTLS между сервисами и базами (MySQL, PostgreSQL, Kafka, RabbitMQ и т. д.).
- VPN, почтовая инфраструктура (IMAP/SMTP TLS), LDAP, RADIUS.
- Подпись клиентских сертификатов для доступа к сервисам и админке.
Плюсы собственного CA:
- Полный контроль над политиками: алгоритмы, длина ключей, сроки, допустимые SAN, OID.
- Независимость от внешних сервисов и лимитов (rate limits, ACME и т. д.).
- Возможность использовать короткие сроки жизни сертификатов и жёсткий mTLS.
Минусы тоже есть:
- Вы сами отвечаете за безопасность корневого и промежуточных ключей.
- Нужно решать задачу доставки корневого и промежуточного сертификатов на клиентов.
- Нет интеграции с веб‑браузерами вне вашей инфраструктуры.
Дизайн private CA: корневой и промежуточный CA
Фундаментальная рекомендация: не использовать корневой CA напрямую для выдачи сертификатов. Правильная модель:
- Корневой CA (offline или максимально изолированный).
- Один или несколько промежуточных CA (online), которые реально выпускают сертификаты.
Корневой ключ нужен только:
- для создания (подписания) промежуточного CA;
- для редких операций типа перекрестной подписи или ротации цепочки.
Всё остальное — ответственность промежуточных CA. Это снижает риск: даже если скомпрометирован промежуточный ключ, вы отзываете только его, а корень остаётся доверенным (после обновления цепочки).

Базовая структура директорий для OpenSSL CA
Классическая структура каталога CA (по мотивам официальной документации OpenSSL, но немного упрощённая):
mkdir -m 700 /opt/ca
cd /opt/ca
# Общие файлы
mkdir certs crl newcerts private csr
chmod 700 private
# Файлы базы CA
touch index.txt
echo 1000 > serial
# Для CRL (список отозванных сертификатов)
echo 1000 > crlnumber
Смысл директорий:
private— закрытые (приватные) ключи CA, самый чувствительный контент.certs— выданные сертификаты (для CA и для конечных сущностей).csr— запросы на сертификаты (CSR); не обязательно сохранять, но удобно.newcerts— каталог с выданными сертификатами по серийным номерам.index.txt— база выданных и отозванных сертификатов.serialиcrlnumber— текущие серийные номера сертификатов и CRL.
Для root CA и для intermediate CA структуру лучше разделить на разные каталоги, например /opt/ca/root и /opt/ca/intermediate — с такими же поддиректориями внутри.
Создаём конфиг OpenSSL для CA
Одна из типичных проблем — использование системного /etc/ssl/openssl.cnf, который не адаптирован под ваш private CA. Лучше создать отдельный конфиг, заточенный под CA.
Пример минимального openssl.cnf для root CA (расположим его в /opt/ca/root/openssl.cnf):
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /opt/ca/root
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/ca.cert.pem
private_key = $dir/private/ca.key.pem
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 3650
preserve = no
policy = policy_strict
[ policy_strict ]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 4096
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
string_mask = utf8only
x509_extensions = v3_ca
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = RU
organizationName = Organization Name
organizationName_default = Example LLC
commonName = Common Name
commonName_default = Example Root CA
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, keyCertSign, cRLSign
[ crl_ext ]
authorityKeyIdentifier = keyid:always
Ключевые моменты:
dirуказывает на каталог CA — все пути задаём относительно него.policy_strictопределяет, какие поля DN должны совпадать с DN CA, а какие — просто присутствовать.v3_caописывает расширения для корневого CA:CA:true,keyCertSign,cRLSign.
Для промежуточного CA будет похожий конфиг, но с отличиями в профилях расширений (наборы для server/client/mTLS и т. д.).
Создание корневого CA (root CA)
Генерируем ключ корневого CA
Переходим в каталог root CA и создаём структуру директорий аналогично базовому примеру. Далее генерируем приватный ключ:
cd /opt/ca/root
openssl genrsa -aes256 -out private/ca.key.pem 4096
chmod 400 private/ca.key.pem
Параметр -aes256 шифрует ключ паролем. Для root CA это оправдано: вы используете его редко, лучше в безопасном офлайн‑месте, и пароль вводите вручную.
Создаём самоподписанный корневой сертификат
Создаём сертификат корневого CA (чаще всего на 10–20 лет, но в современных практиках всё чаще берут 5–10 лет):
openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 3650 -sha256 -extensions v3_ca -out certs/ca.cert.pem
chmod 444 certs/ca.cert.pem
Стоит внимательно заполнить DN (особенно Common Name) — это имя потом будут видеть админы, пользователи, иногда и приложения.
Проверяем, что получилось:
openssl x509 -noout -text -in certs/ca.cert.pem
Создание промежуточного CA (intermediate CA)
Теперь создадим intermediate CA, который будет выпускать реальные серверные и клиентские сертификаты.
Структура и конфиг для intermediate CA
Создадим каталог и базовую структуру:
mkdir -m 700 -p /opt/ca/intermediate/certs
mkdir -m 700 -p /opt/ca/intermediate/crl
mkdir -m 700 -p /opt/ca/intermediate/csr
mkdir -m 700 -p /opt/ca/intermediate/newcerts
mkdir -m 700 -p /opt/ca/intermediate/private
chmod 700 /opt/ca/intermediate/private
cd /opt/ca/intermediate
touch index.txt
echo 1000 > serial
echo 1000 > crlnumber
Пример упрощённого /opt/ca/intermediate/openssl.cnf (фрагмент):
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /opt/ca/intermediate
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/certs/intermediate.cert.pem
private_key = $dir/private/intermediate.key.pem
crlnumber = $dir/crlnumber
crl = $dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 7
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 825
preserve = no
policy = policy_loose
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 4096
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
string_mask = utf8only
x509_extensions = v3_intermediate_ca
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = RU
organizationName = Organization Name
organizationName_default = Example LLC
commonName = Common Name
commonName_default = Example Intermediate CA
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, keyCertSign, cRLSign
[ server_cert ]
basicConstraints = CA:false
nsCertType = server
nsComment = "Example internal TLS server cert"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[ client_cert ]
basicConstraints = CA:false
nsCertType = client
nsComment = "Example internal client cert"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
[ crl_ext ]
authorityKeyIdentifier = keyid:always
Здесь задаём профили сертификатов:
v3_intermediate_ca— профиль для сертификата самого промежуточного CA.server_cert— профиль для TLS‑сертификатов серверов.client_cert— профиль для клиентских сертификатов (для mTLS).
Генерируем ключ и CSR для intermediate CA
cd /opt/ca/intermediate
openssl genrsa -aes256 -out private/intermediate.key.pem 4096
chmod 400 private/intermediate.key.pem
openssl req -config openssl.cnf -new -sha256 -key private/intermediate.key.pem -out csr/intermediate.csr.pem
CSR промежуточного CA должен подписать root CA. Поэтому переносим файл на машину или в каталог root CA (надёжным способом) и там выдаём сертификат.
Подписываем intermediate CA корневым CA
cd /opt/ca/root
openssl ca -config openssl.cnf -extensions v3_ca -days 3650 -notext -md sha256 -in /opt/ca/intermediate/csr/intermediate.csr.pem -out /opt/ca/intermediate/certs/intermediate.cert.pem
chmod 444 /opt/ca/intermediate/certs/intermediate.cert.pem
В реальных конфигурациях часто используют отдельный профиль для промежуточного CA (например, v3_intermediate_ca) и более короткий срок жизни (например, 5–7 лет).
Собираем и проверяем цепочку:
cat /opt/ca/intermediate/certs/intermediate.cert.pem /opt/ca/root/certs/ca.cert.pem > /opt/ca/intermediate/certs/ca-chain.cert.pem
openssl verify -CAfile /opt/ca/root/certs/ca.cert.pem /opt/ca/intermediate/certs/intermediate.cert.pem
Выпуск TLS‑сертификатов с помощью private CA
Теперь, когда у нас есть рабочий intermediate CA, можно выпускать обычные серверные и клиентские сертификаты.
Генерация ключа и CSR для сервера
Генерируем приватный ключ для, скажем, api.internal.example:
cd /opt/ca/intermediate
openssl genrsa -out private/api.internal.example.key.pem 2048
chmod 400 private/api.internal.example.key.pem
Создаём CSR. Чтобы не редактировать конфиг CA каждый раз под свои SAN, проще использовать отдельный временный конфиг или файл с секцией [ req ] и [ alt_names ].
Пример временного конфига csr_api.cnf:
[ req ]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
[ dn ]
CN = api.internal.example
O = Example LLC
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = api.internal.example
DNS.2 = api
IP.1 = 10.0.0.10
Генерируем CSR:
openssl req -new -sha256 -key private/api.internal.example.key.pem -out csr/api.internal.example.csr.pem -config csr_api.cnf
Подписываем CSR intermediate CA
Используем профиль server_cert из конфига intermediate CA:
cd /opt/ca/intermediate
openssl ca -config openssl.cnf -extensions server_cert -days 365 -notext -md sha256 -in csr/api.internal.example.csr.pem -out certs/api.internal.example.cert.pem
chmod 444 certs/api.internal.example.cert.pem
Проверяем сертификат:
openssl x509 -noout -text -in certs/api.internal.example.cert.pem
Стандартный комплект для установки на сервер:
- приватный ключ:
api.internal.example.key.pem; - сертификат сервера:
api.internal.example.cert.pem; - цепочка CA:
ca-chain.cert.pem(intermediate + root в правильном порядке).
Если вы поднимаете TLS на веб‑серверах, пригодятся и публичные CA. Для внешних сайтов вместо собственного private CA лучше использовать полноценные SSL-сертификаты, а внутреннюю цепочку оставить только для приватной инфраструктуры.
Развёртывание корневого CA на клиентах
Чтобы TLS‑соединения, подписанные вашим private CA, считались доверенными, нужно установить корневой сертификат на клиентов (серверы, рабочие станции, контейнеры, микросервисы).
Подходы зависят от платформы:
- Linux‑серверы: установка в системное хранилище (Debian/Ubuntu — через
/usr/local/share/ca-certificates, командуupdate-ca-certificates; RHEL/AlmaLinux — через/etc/pki/ca-trust/source/anchors, командуupdate-ca-trust). - Контейнеры: bake корневого CA в образ или монтирование в контейнер плюс обновление trust store при старте.
- Windows/MacOS: групповые политики (GPO), MDM или ручной импорт для тестовых окружений.
Важно: на серверах, где работают ваши приложения, обновление хранилища доверенных корней зачастую нужно совместить с перезапуском приложений или библиотек, если они кэшируют список CA при старте.
Отзыв сертификатов и CRL
Даже во внутреннем private CA важно уметь корректно отзывать скомпрометированные или ненужные сертификаты. Базовый механизм — CRL (Certificate Revocation List).
Отзыв сертификата
Допустим, нужно отозвать сертификат api.internal.example:
cd /opt/ca/intermediate
openssl ca -config openssl.cnf -revoke certs/api.internal.example.cert.pem
OpenSSL отметит его как отозванный в index.txt.
Генерация CRL
cd /opt/ca/intermediate
openssl ca -config openssl.cnf -gencrl -out crl/intermediate.crl.pem
Теперь вы можете раздавать CRL через внутренний репозиторий, а также указывать URL CRL в расширениях сертификатов (через crlDistributionPoints в конфиге). Многие серверы и клиенты TLS умеют проверять CRL автоматически.
При построении mTLS вокруг баз данных полезно продумать, как хосты будут получать актуальный CRL. Подробный пример mTLS для БД разобран в материале о настройке TLS и собственного CA для MySQL и PostgreSQL.
Безопасность private CA: ключевые практики
Основные угрозы для собственного CA:
- компрометация корневого или промежуточного ключа;
- несанкционированный выпуск сертификатов;
- утечка приватных ключей конечных сущностей (серверов и клиентов).
Практические меры:
- Храните root CA offline: отдельная машина, аппаратный токен или как минимум зашифрованный диск/LUKS, строгий физический доступ.
- Используйте сильные пароли и шифрование для приватных ключей, особенно для корня.
- Ограничьте доступ к каталогу CA (
chmod 700, отдельный системный пользователь). - Логируйте операции выпуска и отзыва сертификатов (audit trail).
- Делайте резервные копии ключей и базы
index.txtс шифрованием и периодически проверяйте восстановление. - Рассмотрите использование HSM или хотя бы аппаратных токенов для ключей CA, если позволяет бюджет.
Если вы сомневаетесь, достаточно ли надёжно защищён ключ CA, исходите из худшего сценария: компрометация ключа = компрометация всего доверия во внутреннем TLS, с последующей перевыпуском всей цепочки.
Автоматизация выдачи сертификатов
Ручной выпуск сертификатов через openssl ca подходит для первых экспериментов, но в реальной DevOps‑среде быстро надоедает. Варианты автоматизации:
- Обёртка на shell, Python или Go вокруг OpenSSL, которая принимает запросы (например, через HTTP API) и вызывает команды CA.
- Интеграция с уже готовыми решениями: HashiCorp Vault PKI, Smallstep CA, cfssl и др. как front‑end к вашему root CA.
- Использование ACME‑совместимых решений (internal ACME‑сервер) для автоматизации выдачи и ротации TLS‑сертификатов на серверах.
При этом ваш private CA остаётся источником доверия (root или intermediate), а автоматика просто управляет выпуском, утверждением политик и ротацией.
Отдельно стоит продумать автоматическую ротацию сертификатов для SMTP и почтовой инфраструктуры — примеры настройки TLS для Postfix и связанных сервисов можно посмотреть в статье о Submission, SMTP AUTH и TLS для Postfix.

Типичные ошибки при настройке private CA на OpenSSL
По опыту, DevOps и админы чаще всего спотыкаются на следующих моментах:
- Использование одного и того же конфига
openssl.cnfдля всего подряд, хаос в профилях и путях. - Отсутствие отдельного intermediate CA — всё делает root CA, который постоянно включён на сервере.
- Неправильные или отсутствующие
subjectAltName, из‑за чего современные клиенты не доверяют сертификату (игнорируют CN). - Неверные расширения: забыли
basicConstraintsилиkeyUsage, и приложения отклоняют сертификат. - Непоследовательная политика DN (поле
organizationNameто совпадает, то нет, полисиmatchломает выдачу). - Слишком большие сроки жизни сертификатов без механизма отзыва, что создаёт риск при утечке ключей.
Хорошее правило: если вы не уверены, смотрели ли на это поле современные клиенты TLS — лучше включите его явно и строго в профиль. Особенно это касается
subjectAltName,basicConstraintsиkeyUsage.
Интеграция private CA с инфраструктурой Dev/Test/Prod
Практическая модель для типичной DevOps‑среды:
- Единый root CA для всей организации.
- Отдельные intermediate CA для разных доменов ответственности: например,
Infra Intermediate CA(внутренние сервисы),VPN Intermediate CA,Client Auth CA. - В dev/test окружениях можно использовать отдельную цепочку (dev‑root + dev‑intermediate), чтобы эксперименты не влияли на prod‑доверие.
При этом на серверах prod‑окружения устанавливается только корневой CA (и нужные цепочки intermediate), а сами сертификаты автоматически выпускаются и ротируются через ваши инструменты управления конфигурацией и CI/CD.
Если у вас уже подняты внешние сервисы на виртуальном хостинге или на собственном кластере на VDS, полезно выработать единый подход к именованию, срокам жизни и автоматической ротации сертификатов, чтобы не городить зоопарк политик между внешним и внутренним периметром.
Выводы
Свой private CA на базе OpenSSL — не «чёрная магия», а вполне приземлённый набор шагов:
- спроектировать иерархию CA (root + intermediate);
- подготовить структуру директорий и отдельные конфиги OpenSSL для каждого CA;
- создать и надёжно защитить ключи и сертификаты root и intermediate;
- организовать выпуск, установку и ротацию TLS‑сертификатов для сервисов и клиентов;
- настроить отзыв (CRL) и процедуры резервного копирования;
- автоматизировать жизненный цикл сертификатов в рамках DevOps‑процессов.
Как только вы пройдёте первый круг — станет ясно, где нужно ужесточить политики, где упростить, какие расширения добавить и как лучше встроить private CA в существующий стек инструментов. Зато взамен вы получаете полный контроль над внутренним TLS, mTLS и безопасной коммуникацией между сервисами.


