Особенности использования брокера сообщений RabbitMQ

В качестве транспорта в платформе «Агредатор» может быть использовать брокер сообщений RabbitMQ. При эксплуатации данного ПО мы рекомендуем учесть некоторые особенности при его развёртывании и конфигурировании.

Используемые расширения

  • rabbitmq_auth_mechanism_ssl - использование механизма TLS при подключении к брокеру
  • rabbitmq_auth_backend_http - использование авторизационного сервиса auth, входящего в базовую поставку «Агредатора»
  • rabbitmq_auth_backend_cache - кеширование авторизационных данных для уменьшения нагрузки на auth сервис
  • rabbitmq_management - административная панель управления RabbitMQ
  • rabbitmq_peer_discovery_consul - интеграция с Consul для мониторинга состояния и объединения в кластер при необходимости
  • rabbitmq_prometheus - интеграция с Prometheus

Все расширения, используемые платформой, являются официальными и входят в базовую поставку RabbitMQ.

Базовая конфигурация

Для использования механизма TLS необходимо предоставить сертификаты и ключ. Мы рекомендуем следующее расположение ключей, одно оно может быть изменено согласно иным подходам/политикам, принятым в используемом Linux дистрибутиве.

etc
└── rabbitmq
    ├── ca
    │   └── cacert.pem     # Сертификат центра сертификации (CA)
    ├── server
    │   ├── cert.pem       # Сертификат, выданный брокеру
    │   └── key.pem        # Ключ выданный брокеру
    ├── definitions.json   # Предварительные объявления
    └── rabbitmq.conf      # Конфигурация
Ключ и сертификат

Ключ и необходимые сертификаты для использования TLS можно создать и скачать через административную панель платформы «Агредатор»

rabbitmq.conf

В данном файле настраиваются основные параметры брокера сообщений:

# Настройки логирования
log.console = true
log.console.level = info

log.connection.level = debug
log.queue.level = debug
log.channel.level = debug
log.default.level = debug

# Пользователь с правами администратора для авторизации без использвания внешних поставщиков (сервис auth)
loopback_users.1 = $MQ_USER

listeners.tcp.default = 5672
listeners.ssl.default = 5671

# Настройки сертификатов
ssl_options.cacertfile = /etc/rabbitmq/ca/cacert.pem
ssl_options.certfile = /etc/rabbitmq/server/cert.pem
ssl_options.keyfile = /etc/rabbitmq/server/key.pem
ssl_options.verify = verify_peer
ssl_options.depth = 2
ssl_options.fail_if_no_peer_cert = false
ssl_options.crl_check = best_effort
# Список отзывов - не используется
# ssl_options.crl_cache.ssl_crl_hash_dir.internal.dir = /etc/rabbitmq/crl

hipe_compile = false

# Механизмы авторизации 
auth_mechanisms.1 = EXTERNAL # внешний - сервис (auth)
auth_mechanisms.2 = PLAIN    # внутренний - пользователь в definitions.json

auth_backends.1 = rabbit_auth_backend_internal
#auth_backends.2 = rabbit_auth_backend_http

# Кеш запросов к сервису auth
auth_backends.2 = cache
auth_cache.cached_backend = http
auth_cache.cache_ttl = 120000


ssl_cert_login_from = common_name

# Настройки внешней авторизации - сервиса auth
auth_http.http_method = post
auth_http.user_path = http://${AUTH_HOST}:${AUTH_PORT}/auth/user
auth_http.vhost_path = http://${AUTH_HOST}:${AUTH_PORT}/auth/vhost
auth_http.resource_path = http://${AUTH_HOST}:${AUTH_PORT}/auth/resource
auth_http.topic_path = http://${AUTH_HOST}:${AUTH_PORT}/auth/topic

management.load_definitions = /etc/rabbitmq/definitions.json
management.disable_stats = false
management.enable_queue_totals = true
management_agent.disable_metrics_collector = false


# настройка Consul для регистрации сервиса, мониторинга (healthchecks) и объединения в кластер
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_consul
cluster_formation.consul.host = $CONSUL_HOST
cluster_formation.consul.port = $CONSUL_PORT
cluster_formation.consul.svc_addr_auto = true

# Резервирование места на диске для сброса памяти
# disk_free_limit.absolute = 10GB # 10GB - минимум - РЕКОМЕНДОВАНО ДЛЯ ПРОДА
# disk_free_limit.relative = 1.0  # 100% от памяти - РЕКОМЕНДОВАНО ДЛЯ ПРОДА
disk_free_limit.absolute = $DISK_FREE_ABS_LIMIT # 10GB - минимум
disk_free_limit.relative = $DISK_FREE_MEM_LIMIT # 100% от памяти

definitions.json

В предварительных объявлениях создаются сущности по-умолчанию: пользователь с правами администратора и vhost:

{
 "users": [
    {
      "name": "$MQ_USER",
      "password": "$MQ_PASS",
      "tags": "administrator"
    }
 ],
 "vhosts": [
  {
   "name": "\/"
  }
 ],
 "permissions": [
    {
      "user": "$MQ_USER",
      "vhost": "/",
      "configure": ".*",
      "write": ".*",
      "read": ".*"
    }
 ],
 "parameters": [],
 "policies": [],
 "queues": [],
 "exchanges": [],
 "bindings": []
}

Запуск с помощью Docker-образа

Наиболее простым способом запуска RabbitMQ является запуск с помощью Docker-контейнера, используя подготовленный заранее образ docker.rnds.pro/aggredator-mq:latest. Он собран на основе официального образа и в нём используется конфигурация, настроенная на работу с Consul и требуемая для запуска «Агредатора».

Оффициальный образ

Можно использовать официальный образ, однако в этом случае необходимо самим выполнить его настройку.

Параметры конфигурации для "docker.rnds.pro/aggredator-mq:latest"

При запуске из образа docker.rnds.pro/aggredator-mq:latest все параметры передаются через переменные окружения, которые в свою очередь читаются из Consul. Параметры, принимаемые из переменных окружения:

environment:
  - MQ_COOKIE    # Явное задание RABBITMQ_ERLANG_COOKIE для формирования кластера
  - CONSUL_HOST  # адрес Consul. Ex: consul
  - CONSUL_PORT  # порт Consul. Ex: 8500
  - CONSUL_HTTP_ADDR   # полный адрес Consul. Ex: http://consul:8500
  - CONSUL_CONFIG_PATH # путь в Consul K/V для поиска конфигурации. Ex: services/env/mq
  - DISK_FREE_ABS_LIMIT # абсолютный минимум места - 10GB РЕКОМЕНДОВАНО ДЛЯ ПРОДА
  - DISK_FREE_MEM_LIMIT # процент места от памяти - 1.0 (100%) РЕКОМЕНДОВАНО ДЛЯ ПРОДА
  - MQ_USER      # Пользователь с правами администрирования
  - MQ_PASS      # Пароль пользователя с правами администрирования
  - AUTH_HOST    # Адрес сервиса auth
  - AUTH_PORT    # Порт сервиса auth
  - CA_CERT      # Сертификат центра сертификации (CA). Попадет в файл /etc/rabbitmq/ca/cacert.pem
  - CLIENT_CERT  # Сертификат, выданный брокеру. Попадет в файл /etc/rabbitmq/server/cert.pem
  - CLIENT_KEY   # Сертификат, выданный брокеру. Попадет в файл /etc/rabbitmq/server/key.pem
TLS сертификаты

Платформа «Агредатора» содержит в себе собственный УЦ и базовые функции по управлению им. Управление всеми сертификатами выполняется из панели администрирования платформы - из сервиса admin.

TLS сертификаты

При встраивании платформы в существующую инфраструктуру существует несколько способов выстроить иерархию TLS сертификатов. В частности это касается конфигурации по использованию брокера сообщений RabbitMQ:

  • Типовой способ - каждый экземпляр использует собственный изолированный экземпляр RabbitMQ и собственный УЦ
  • Один на всех - все экземпляры используют единый экземпляр RabbitMQ, но с разными настройками vhost и общий УЦ
  • Существующий УЦ - в организации уже есть корневой сертификат и необходимо выстроить иерархию от него

Типовой способ

Типовой экземпляр платформы при старте инициализирует собственный корневой сертификат УЦ - Instance CA. Затем для каждого зарегистрированного сервиса выпускается собственный сертификат ServiceX и отдельный для сервиса RabbitMQ

graph TD; classDef clientClass fill:#d0ffb0,stroke-width:1px; classDef aggClass fill:#ffe8be,stroke-width:1px; classDef rootClass fill:#ffdddd,stroke-width:1px; classDef prjClass fill:#ffffff,stroke-width:1px,stroke-dasharray: 5 5; classDef subClass fill:#fffff2,stroke-width:1px,stroke-dasharray: 5 5; InstanceCA(Instance CA)-->RabbitMQ(RabbitMQ Server):::clientClass; InstanceCA(Instance CA)-->Service1(Service 1); InstanceCA(Instance CA)-->ServiceN(Service N); subgraph srv [Сервисы]; Service1:::clientClass; ServiceN:::clientClass; end; subgraph instance [Агредатор]; srv; end class srv subClass; class instance subClass;

Один на всех

В целях экономии ресурсов существует возможность использовать один брокер RabbitMQ для множества независимых экземпляров платформы «Агредатор». В этом случае для обеспечения корректности проверки цепочки TLS сертификатов все экземпляры платформы должны использовать общий корневой сертификат - AggredatorCA. В этом случае RabbitMQ, также являясь потомком AggredatorCA, сможет валидировать подключаемых клиентов, а клиенты - RabbitMQ. AggredatorCA выпускается вручную и отдаётся в пользование каждому экземпляру платформы вместе с закрытым ключом.

graph TD; classDef clientClass fill:#d0ffb0,stroke-width:1px; classDef aggClass fill:#ffe8be,stroke-width:1px; classDef rootClass fill:#ffdddd,stroke-width:1px; classDef prjClass fill:#ffffff,stroke-width:1px,stroke-dasharray: 5 5; classDef subClass fill:#fffff2,stroke-width:1px,stroke-dasharray: 5 5; AggredatorCA(Aggredator CA):::aggClass-->Instance1CA(Instance 1 CA); AggredatorCA(Aggredator CA):::aggClass-->InstanceNCA(Instance N CA); AggredatorCA-->RabbitMQ(RabbitMQ Server):::clientClass; subgraph instanceN [Агредатор N]; InstanceNCA-->ServiceN_1(Service 1); InstanceNCA-->ServiceN_N(Service N); subgraph srvN [Сервисы]; ServiceN_1:::clientClass; ServiceN_N:::clientClass; end end; subgraph instance1 [Агредатор 1]; Instance1CA-->Service1_1(Service 1); Instance1CA-->Service1_N(Service N); subgraph srv1 [Сервисы]; Service1_1:::clientClass; Service1_N:::clientClass; end end; subgraph project[ ]; AggredatorCA; RabbitMQ; instance1; instanceN; end class project prjClass; class instance1 subClass; class instanceN subClass; class srv1 subClass; class srvN subClass;

Существующий УЦ

В условиях когда требуется породить всю иерархия сертификатов от корневого (например сертификата организации) возможно использование данной схемы. В данном как и в конфигурации "Один на всех" AggredatorCA выпускается вручную и отдаётся в пользование каждому экземпляру платформы вместе с закрытым ключом. Однако в этом случае он выпускается от имени существующего RootCA.

graph TD; classDef clientClass fill:#d0ffb0,stroke-width:1px; classDef aggClass fill:#ffe8be,stroke-width:1px; classDef rootClass fill:#ffdddd,stroke-width:1px; classDef prjClass fill:#ffffff,stroke-width:1px,stroke-dasharray: 5 5; classDef subClass fill:#fffff2,stroke-width:1px,stroke-dasharray: 5 5; RootCA(Root CA):::rootClass-->AggredatorCA; AggredatorCA(Aggredator CA):::aggClass-->Instance1CA(Instance 1 CA); AggredatorCA(Aggredator CA):::aggClass-->InstanceNCA(Instance N CA); AggredatorCA-->RabbitMQ(RabbitMQ Server):::clientClass; subgraph instanceN [Агредатор N]; InstanceNCA-->ServiceN_1(Service 1); InstanceNCA-->ServiceN_N(Service N); subgraph srvN [Сервисы]; ServiceN_1:::clientClass; ServiceN_N:::clientClass; end end; subgraph instance1 [Агредатор 1]; Instance1CA-->Service1_1(Service 1); Instance1CA-->Service1_N(Service N); subgraph srv1 [Сервисы]; Service1_1:::clientClass; Service1_N:::clientClass; end end; subgraph project[ ]; AggredatorCA; RabbitMQ; instance1; instanceN; end class project prjClass; class instance1 subClass; class instanceN subClass; class srv1 subClass; class srvN subClass;