Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

TLS до базы данных: шифрование MySQL/PostgreSQL с валидацией CA

Подключения к БД часто ходят по внутренним сетям — и потому их шифрованием пренебрегают. Разбираем, как включить TLS для MySQL и PostgreSQL, обеспечить строгую проверку CA и имени хоста, настроить клиентов и безопасную ротацию сертификатов.
TLS до базы данных: шифрование MySQL/PostgreSQL с валидацией CA

Шифрование трафика до базы данных — базовая гигиена безопасности, которая часто откладывается «на потом». Пока запросы ходят внутри одного дата-центра или private VPC, риски кажутся низкими. Но именно в таких сегментах встречаются прослойки, прокси, бэкапные агенты и админские ноутбуки, создающие поверхность атаки: ARP-спуфинг, несанкционированное прослушивание зеркалируемых портов, утечки дампов. TLS закрывает эти классы проблем и облегчает соответствие внутренним политикам и требованиям безопасности.

Модель и термины

Наша цель — включить TLS на стороне сервера базы данных и заставить клиентов проверять цепочку доверия (CA) и имя хоста из сертификата. В идеале — ограничить протоколы до TLS 1.2+ и современные шифросuites. Такой подход предотвращает «тихий» даунгрейд и MITM внутри сети. Дополнительно, при необходимости, можно включить взаимную аутентификацию (mTLS), когда клиент тоже предъявляет сертификат, а сервер проверяет его по CA.

TLS против mTLS

Обычный TLS защищает канал и подтверждает личность сервера: клиент проверяет, что сертификат выпущен доверенным CA и что имя хоста совпадает с SAN сертификата. mTLS добавляет проверку клиента, полезен в сервис-сервис коммуникациях, когда не хочется полагаться только на пароль/токен. Но mTLS требует дистрибуции и ротации клиентских сертификатов — это сложнее в эксплуатации.

Валидация CA и имени хоста

Просто «включить SSL» недостаточно. Клиент обязан проверять корневой/промежуточный CA и сопоставлять FQDN сервера с полями Subject Alternative Name (SAN) сертификата. Игнорирование проверки имени делает шифрование уязвимым для MITM. В современных клиентах MySQL это режим VERIFY_IDENTITY, а в PostgreSQL — sslmode=verify-full.

Где брать сертификаты

Внутренние БД чаще обслуживаются частным (внутренним) центром сертификации. Это удобно: вы контролируете выпуск, сроки годности и отзыв. Публичные CA уместны, если БД или прокси доступны из внешних сетей: в таком случае используйте проверенные SSL-сертификаты. При этом важно грамотно хранить корневой ключ, подписывать промежуточный и соблюдать процесс ротации.

Если вы только строите процесс, начните с собственного внутреннего CA и коротких сроков жизни серверных сертификатов (90–180 дней). Так проще привыкнуть к ротации и выработать автоматизацию.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Выпуск внутреннего CA и серверных сертификатов

Минимально жизнеспособная схема — корневой CA (оффлайн) и один промежуточный CA (онлайн), которым подписываются серверные и, при mTLS, клиентские сертификаты. Для простоты ниже показан один CA, но производственно лучше разделять.

Создание корневого CA (пример OpenSSL)

# 1) Генерируем ключ и самоподписанный сертификат CA
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -days 3650 -sha256 -subj "/CN=Fastfox Internal DB Root CA" -out ca.crt

Храните ca.key в изолированном месте, с резервным копированием и строгими правами. Для продакшна сделайте оффлайн-CA и рабочий промежуточный CA, чтобы ежедневные операции не затрагивали корневой ключ.

Конфиг SAN и выпуск серверного сертификата

# 2) Конфиг для SAN (server-openssl.cnf)
[ req ]
distinguished_name = dn
req_extensions = v3_req
prompt = no

[ dn ]
CN = db01.internal.local

[ v3_req ]
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = db01.internal.local
DNS.2 = db-read.internal.local
IP.1 = 10.10.10.21
# 3) Ключ и CSR
openssl genrsa -out db01.key 2048
openssl req -new -key db01.key -out db01.csr -config server-openssl.cnf

# 4) Подпись CSR CA
openssl x509 -req -in db01.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out db01.crt -days 180 -sha256 -extfile server-openssl.cnf -extensions v3_req

В SAN обязательно укажите реальный FQDN, по которому клиенты подключаются. Если клиент использует IP, добавьте его в SAN как IP. Не полагайтесь на устаревший CN без SAN.

MySQL/MariaDB: включаем TLS и проверку

Современный MySQL 8.0 и MariaDB умеют TLS 1.2/1.3 «из коробки». Мы включим TLS, ограничим протоколы и потребуем защищённый транспорт для любых подключений.

Серверная конфигурация

# /etc/my.cnf или /etc/mysql/my.cnf
[mysqld]
ssl_ca = /etc/mysql/tls/ca.crt
ssl_cert = /etc/mysql/tls/db01.crt
ssl_key = /etc/mysql/tls/db01.key
require_secure_transport = ON
# Ограничим версии протоколов
# Для MySQL 8.0: список через запятую
tls_version = TLSv1.2,TLSv1.3
# Опционально указать шифросьюты TLS 1.3
tls_ciphersuites = TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384

Ключевые моменты эксплуатации: права на db01.key — 600, владелец системный пользователь MySQL. Каталог с сертификатами должен быть доступен только службе базы данных. После внесения изменений перезапустите или выполните безостановочный reload/refresh, если поддерживается вашей сборкой. В MariaDB для обновления цепочки можно использовать FLUSH SSL, в MySQL — перезапуск либо мягкая перезагрузка службы.

Проверка со стороны сервера

# Проверим статус шифрования сессии
mysql -u root -p -e "SHOW SESSION STATUS LIKE 'Ssl_cipher';"
mysql -u root -p -e "SHOW VARIABLES LIKE 'tls_version';"

Если Ssl_cipher пусто — ваше подключение без TLS. Проверьте require_secure_transport и что клиент действительно запрашивает TLS.

Клиент MySQL CLI с проверкой CA и имени

mysql --host=db01.internal.local --user=app --password --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/mysql/tls/ca.crt

VERIFY_IDENTITY включает проверку имени хоста по SAN. Без корректного SAN подключение упадёт с ошибкой несовпадения имени — и это правильное поведение. Если вы используете промежуточный CA, удостоверьтесь, что в --ssl-ca лежит файл с полной цепочкой, которую понимает клиент.

Интеграция в приложения

PHP (PDO MySQL): укажите режим проверки и путь к CA. Важно: не отключайте проверку имени ради «быстро починить» — лучше выпустите корректный сертификат.

// PHP PDO (mysql)
$pdo = new PDO(
    'mysql:host=db01.internal.local;dbname=app;charset=utf8mb4',
    'app',
    'secret',
    [
        PDO::MYSQL_ATTR_SSL_CA => '/etc/mysql/tls/ca.crt',
        PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true,
    ]
);

Java (JDBC Connector/J): добавьте параметры в URL, импортируйте CA в truststore, если требуется корпоративной политикой. Node.js (mysql2) принимает объект ssl с ca.

PostgreSQL: TLS с проверкой CA

PostgreSQL включает TLS через OpenSSL. Мы активируем TLS, ограничим протоколы, пропишем CA и убедимся, что клиенты используют verify-full. При необходимости зафиксируем политику в pg_hba.conf.

Серверная конфигурация

# postgresql.conf
ssl = on
ssl_cert_file = '/etc/postgresql/tls/db01.crt'
ssl_key_file = '/etc/postgresql/tls/db01.key'
ssl_ca_file = '/etc/postgresql/tls/ca.crt'
ssl_min_protocol_version = 'TLSv1.2'
# Дополнительно можно сузить шифросьюты для версий ниже TLS 1.3
ssl_ciphers = 'HIGH:!aNULL:!MD5'

Права на db01.key — только у пользователя postgres, режим 600. Для принудительного TLS используйте pg_hba.conf с записями hostssl. Например, запретите незашифрованные маршруты, оставив только hostssl для нужных подсетей.

# pg_hba.conf
# Разрешаем TLS-подключения из приватной подсети, без клиентских сертификатов
hostssl all all 10.10.10.0/24 scram-sha-256
# При mTLS (опционально):
# hostssl all all 10.10.10.0/24 cert clientcert=verify-full

Примените изменения через перезагрузку конфигурации. Сертификаты и CRL в PostgreSQL можно перечитать сигналом SIGHUP либо pg_ctl reload. Если меняется структура ключа или его парольная фраза, может потребоваться рестарт.

Проверка со стороны сервера

# Показать активные TLS-сессии
SELECT pid, usename, client_addr, ssl, version, cipher
FROM pg_stat_ssl JOIN pg_stat_activity USING (pid)
WHERE ssl;

Если вы видите ssl = t и заполненные version/cipher — соединение защищено. Убедитесь, что незашифрованные маршруты отсутствуют или запрещены политиками в pg_hba.conf.

Клиент PostgreSQL с verify-full

# psql
psql "host=db01.internal.local dbname=app user=app sslmode=verify-full sslrootcert=/etc/postgresql/tls/ca.crt"

verify-full одновременно требует защищённого канала, валидного CA и соответствия имени хоста SAN. Если DNS-имя отличается от того, что в сертификате, подключение будет отклонено.

Выпуск внутреннего CA и серверного сертификата для БД

Нужен ли mTLS к БД

mTLS уместен в Zero Trust-сегментах и для межсервисных взаимодействий, где нельзя доверять только паролям. Он позволяет ограничить доступ на уровне сертификатов и отзывом быстро «выключать» компрометированные инстансы. Но дистрибуция и ротация клиентских сертификатов повышают цену владения. Для классических веб-приложений достаточно TLS с проверкой CA и имени, плюс сильная аутентификация (SCRAM для PostgreSQL, учетные данные с ротацией для MySQL).

Если всё же решитесь: выпустите клиентский сертификат с extendedKeyUsage = clientAuth, настройте pg_hba.conf с clientcert=verify-full или в MySQL используйте плагин X509 и соответствующие GRANT-правила для субъектов сертификата.

Хранение ключей и права

Приватные ключи серверов — самый чувствительный артефакт. Положите их в выделенный каталог, доступный только пользователю СУБД. На Linux это обычно /etc/mysql/tls и /etc/postgresql/tls с правами каталога 700 и файла ключа 600. Не используйте парольные фразы на серверных ключах, если это приведёт к интерактивному вводу при перезапуске демона. Следите за бэкапами: ключи не должны утекать в объёмные бэкапы, которыми часто делятся команды. Для инфраструктуры на VDS дополнительно проверьте шифрование дисков и политику доступа к снапшотам.

Ротация и оперативное обновление

Сертификаты с коротким сроком жизни снижают боль отзывов, но требуют автоматизации. Выберите процесс: конфигурационный менеджмент, Secret-хранилище, пайплайн CI для выпусков и выкладки. Важно обеспечить перекрытие сроков действия: разложите новые сертификаты заранее, перезагрузите службы, проверьте, что клиенты принимают новую цепочку CA, и лишь затем отзывайте старую.

MySQL: обновление сертификатов зачастую требует перезапуска службы, хотя часть сборок поддерживает мягкую перезагрузку цепочки. MariaDB умеет FLUSH SSL. PostgreSQL перечитывает сертификаты по SIGHUP; при смене ключа или пароля ключа возможен рестарт. Планируйте окна обслуживания и убедитесь, что пулы соединений переносят обрывы. Для надёжной стратегии восстановления пригодится наше практическое руководство по offsite-бэкапам в S3 — см. статью «S3-бэкапы с restic/borg» по ссылке S3-бэкапы с restic/borg.

Клиентские настройки TLS и проверка имени хоста для MySQL и PostgreSQL

Типовые ошибки и их диагностика

Несовпадение имени хоста. Клиент жалуется на hostname mismatch — проверьте, что FQDN клиента совпадает с SAN сертификата. Добавьте все используемые DNS-алиасы, а также IP, если клиенты подключаются по адресу.

Неполная цепочка CA. Если серверный сертификат подписан промежуточным CA, клиенты должны иметь полный путь доверия. Для MySQL указывайте файл ssl_ca на стороне сервера и соответствующий --ssl-ca на стороне клиента. В PostgreSQL используйте ssl_ca_file и клиентский sslrootcert. Убедитесь, что файл содержит правильный набор сертификатов в PEM-последовательности.

Старые протоколы/шифры. При жёстких настройках сервера клиенты со старыми библиотеками OpenSSL могут не установиться. Проверьте версии драйверов (Connector/J, libpq, mysqlclient) и минимальную версию TLS. Лучше обновить клиентов, чем ослаблять серверную политику.

Без TLS из-за режима по умолчанию. Для MySQL явно включайте --ssl-mode=VERIFY_IDENTITY. Для PostgreSQL используйте sslmode=verify-full. Режимы prefer или require без проверки имени не обеспечивают сопротивление MITM.

Форматы ключей и прав. Неверные права на ключи заставляют серверы отказываться от TLS. PostgreSQL придирчив: если ssl_key_file доступен шире, чем 600, TLS не стартует. Смотрите логи запуска.

Производительность и пулы соединений

Нагрузка от TLS в типичной БД-переписке невысока: основная цена — в рукопожатии. Помогают лимитированные пулы соединений и keepalive. В PostgreSQL часто применяют PgBouncer: он может принимать TLS от приложений и держать внутренние незашифрованные коннекты к Postgres или тоже TLS — как позволяет политика. В MySQL роль пула берут ProxySQL и аналогичные решения. Неплохо замерить p95/p99 задержек до и после включения TLS, чтобы корректно подобрать лимиты пула. Для смежных оптимизаций Postgres полезно перечитать заметку «Тюнинг autovacuum и индексов» — рекомендации по autovacuum и индексам.

Сегментация сети и firewall

Шифрование не заменяет сегментацию. Ограничьте доступ к 3306/TCP (MySQL) и 5432/TCP (PostgreSQL) только необходимыми подсетями и сервисами. Исключите публикацию портов БД в Интернет. Внутри кластера используйте списки контроля доступа и статические маршруты, чтобы исключить «случайные» хопы и NAT, которые усложняют отладку TLS. Если БД крутится на изолированном VDS, настраивайте хостовый firewall и security groups как первый рубеж обороны.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

CRL и отзыв сертификатов

Если вы используете внутренний CA, спланируйте процесс отзывов. PostgreSQL поддерживает ssl_crl_file, MySQL — ssl_crl и ssl_crlpath. Не все клиенты валидируют OCSP, поэтому практика коротких сроков жизни и автоматической ротации в сочетании с CRL остаётся рабочим компромиссом.

Контейнеры и секреты

В Kubernetes и аналогичных оркестраторах сертификаты и ключи храните как секреты и монтируйте в только-читаемые тома внутри контейнера. Следите, чтобы обновления секретов триггерили перезапуск/перезагрузку подов. Не включайте приватные ключи в образ: это усложняет ротацию и повышает риск утечки.

Чеклист внедрения

  • Выпустить внутренний CA и настроить безопасное хранение его ключей.
  • Сгенерировать для каждого узла БД сертификат с корректным SAN.
  • Включить TLS на сервере, ограничить протоколы до TLS 1.2+ и задать шифросьюты.
  • Принудить защищённый транспорт: require_secure_transport в MySQL, hostssl в PostgreSQL.
  • Настроить клиентов на строгую проверку: VERIFY_IDENTITY и sslmode=verify-full.
  • Проверить, что все приложения ходят по TLS; мониторить метрики TLS-сессий.
  • Автоматизировать ротацию сертификатов и CA, описать процедуру отзывов.
  • Ограничить доступ по портам БД на уровне сети и хостовых firewall.

Резюмируя: шифрование канала до БД — задача одного-двух спринтов и нескольких аккуратных правок конфигураций. На выходе вы убираете целый класс рисков, упрощаете аудит и закладываете фундамент под дальнейшие практики Zero Trust и сервис-сервис аутентификацию.

Поделиться статьей

Вам будет интересно

PostgreSQL HA на VDS с Patroni: кластер, DCS и безопасный failover OpenAI Статья написана AI Fastfox

PostgreSQL HA на VDS с Patroni: кластер, DCS и безопасный failover

Разбираем построение отказоустойчивого кластера PostgreSQL на VDS с Patroni: выбор и развёртывание DCS (etcd/Consul), сетевые прав ...
Безопасные миграции MySQL: pt‑online‑schema‑change и gh‑ost без простоя OpenAI Статья написана AI Fastfox

Безопасные миграции MySQL: pt‑online‑schema‑change и gh‑ost без простоя

Если таблицы уже на десятках гигабайт, обычный ALTER грозит блокировками и простоями. Разбираем онлайн‑миграции MySQL с pt‑online‑ ...
journald или rsyslog: настраиваем персистентность, rate‑limit и форвардинг OpenAI Статья написана AI Fastfox

journald или rsyslog: настраиваем персистентность, rate‑limit и форвардинг

Как выбрать между journald и rsyslog, включить хранение на диске, настроить rate‑limit и надёжный форвардинг на коллектор? В матер ...