Коротко. Брокер на время перехода слушает 5672 и 5671. Клиенты переводятся по одному, откат это прежний порт. Кто ещё без TLS, показывает rabbitmqctl list_connections ... ssl. Обычный порт закрывается, когда список пуст сутки. После продления сертификата сбрасывается кэш, у RX корень должен быть доверен внутри контейнеров.

Сервисы Directum RX обмениваются сообщениями через RabbitMQ: асинхронные обработчики, фоновые процессы, индексация. По умолчанию это обычный AMQP на порту 5672 без шифрования, и в нём ходят учётные данные брокера и содержимое сообщений. Когда служба ИБ просит закрыть этот трафик, первое желание включить TLS и перезапустить всё разом. Переход можно сделать по частям, без простоя для пользователей и с понятной точкой отката.

Симптом

После неудачного перевода на TLS обычно видно одно из следующего:

  • В журналах RX RabbitMQ is not available. Possible problems: TLS configuration (check useTls setting). Incorrect port.
  • Брокер после перезапуска не слушает 5671, в его журнале ошибка чтения файла ключа.
  • RX подключился, а другой клиент брокера (сервис интеллектуальной обработки, мониторинг, скрипт выгрузки) перестал, потому что о нём забыли.
  • После продления сертификата брокер продолжает отдавать старый.

Почему так

RabbitMQ может слушать обычный порт и порт с TLS одновременно. Это и позволяет переходить по частям: включить TLS-порт, перевести клиентов по одному, убедиться, что на обычном порту никого не осталось, и только после этого его закрыть. Если сделать наоборот и сначала закрыть 5672, все клиенты, которые не успели перейти, теряют брокер одновременно, и фоновая работа RX встаёт.

У каждого клиента три настройки должны совпасть с брокером: порт (5671 для TLS), признак TLS и имя хоста, которое есть в сертификате брокера. Кроме того, клиент должен доверять удостоверяющему центру, который выпустил сертификат. Сервисы RX работают в контейнерах, хранилище сертификатов хоста им не видно, и корень добавляется внутрь контейнера.

Подготовка

Сертификат брокера

  • В поле SAN имена, по которым к брокеру подключаются клиенты. Для кластера это имя каждого узла и общее имя, если подключение идёт через балансировщик.
  • Файл сертификата содержит сертификат и промежуточные по порядку, файл ключа читается пользователем, от которого работает RabbitMQ.
  • Проверить пару до выкладки:
openssl x509 -in server.crt -noout -subject -ext subjectAltName -enddate
openssl x509 -in server.crt -noout -pubkey | sha256sum
openssl pkey -in server.key -pubout | sha256sum      # суммы должны совпасть
grep -c 'BEGIN CERTIFICATE' server.crt; grep -c 'END CERTIFICATE' server.crt

Кто вообще подключается к брокеру

До начала работ нужен полный список клиентов. Брокер его знает:

rabbitmqctl list_connections user peer_host ssl | sort | uniq -c

В выводе видно учётку, адрес и признак TLS. Если по адресу непонятно, что это за клиент, добавьте колонку client_properties: в ней название и версия клиентской библиотеки. Каждого клиента из списка нужно будет перевести, иначе он сломается при закрытии 5672.

Переход

1. Включить TLS-порт рядом с обычным

# rabbitmq.conf
listeners.tcp.default = 5672
listeners.ssl.default = 5671

ssl_options.cacertfile = /etc/rabbitmq/tls/ca.crt
ssl_options.certfile   = /etc/rabbitmq/tls/server.crt
ssl_options.keyfile    = /etc/rabbitmq/tls/server.key
ssl_options.verify     = verify_none
ssl_options.fail_if_no_peer_cert = false
ssl_options.versions.1 = tlsv1.3
ssl_options.versions.2 = tlsv1.2

verify_none здесь означает, что брокер не требует сертификата от клиента. Клиенты подключаются по логину и паролю, а шифрование и проверка сертификата брокера на стороне клиента работают как обычно.

Новые слушатели появляются после перезапуска узла. В кластере узлы перезапускаются по одному, с проверкой, что предыдущий вернулся в кластер и очереди синхронизированы. Клиенты RX при перезапуске узла переподключаются сами.

Проверка:

rabbitmq-diagnostics listeners                     # должны быть и 5672, и 5671
openssl s_client -connect rabbit01.example.local:5671 -servername rabbit01.example.local </dev/null | head -20

2. Перевести клиентов по одному

Для RX это включение признака TLS и порт 5671 в настройках подключения к брокеру, плюс доверенный корень внутри контейнеров сервисов. После перезапуска сервисов в списке соединений у них должно появиться ssl = true:

rabbitmqctl list_connections user peer_host ssl ssl_protocol

Так же переводятся остальные клиенты. Если что-то пошло не так, откат это вернуть клиенту прежний порт: 5672 всё ещё работает.

3. Закрыть обычный порт

Когда в списке соединений не осталось ни одного с ssl = false (и он остаётся пустым хотя бы сутки, чтобы попались ночные задания и редкие выгрузки), обычный слушатель отключается:

listeners.tcp = none

И снова перезапуск узлов по одному.

Что ещё в брокере ходит без TLS

  • Веб-интерфейс управления на 15672. Переводится отдельными настройками management.ssl.* на 15671.
  • Метрики для Prometheus на 15692. Это HTTP, содержимое не секретное, но доступ к порту стоит ограничить.
  • Обмен между узлами кластера. TLS для него настраивается отдельно и сложнее. Обычно узлы кластера стоят в одном закрытом сегменте, и межузловой трафик закрывают сетью, а не TLS. Если требования ИБ иначе, на это нужна отдельная репетиция.

Продление сертификата

RabbitMQ кэширует прочитанные сертификаты. Если просто заменить файлы, новые соединения ещё какое-то время получают старый сертификат. Кэш сбрасывается на каждом узле без перезапуска:

rabbitmqctl eval 'ssl:clear_pem_cache().'

После этого проверка через openssl s_client должна показывать новый срок действия. Срок сертификата брокера стоит держать под наблюдением вместе с остальными сертификатами контура.

Типовые ошибки

Где и что Причина
RX: check useTls setting. Incorrect port признак TLS и порт не совпадают с брокером, или брокер недоступен. Разбор в справочнике
RX: RemoteCertificateNameMismatch имени, по которому подключается RX, нет в SAN сертификата брокера
RX: UntrustedRoot или PartialChain корень не доверен в контейнере или брокер не отдаёт промежуточный сертификат. Разбор в справочнике
Брокер: CLIENT ALERT: Fatal - Certificate Unknown клиент не принял сертификат брокера; искать на стороне клиента
Брокер: ошибка рукопожатия от клиента на 5671 без TLS клиент подключается к TLS-порту обычным AMQP
Брокер не слушает 5671 после перезапуска не читается ключ или сертификат: права, путь, формат; причина в журнале узла при старте
Брокер: ACCESS_REFUSED TLS ни при чём, неверный логин или пароль. Разбор в справочнике

Чего не делать

  • Не закрывать 5672 одновременно с включением 5671. Все, кто не успел перейти, потеряют брокер разом.
  • Не закрывать 5672, пока в списке соединений есть клиенты без TLS. Смотрите список не один раз, а в течение суток.
  • Не отключать проверку сертификата брокера на клиентах, чтобы «заработало». Шифрование без проверки не защищает от подмены брокера.
  • Не перезапускать все узлы кластера одновременно.
  • Не забывать сбросить кэш сертификатов после продления.