EncryptionMessagePlugin#
С версии SMB 3.0.0 режим шифрования full становится depricated, останется только режим шифрования disk_only.
Плагин работает только для персистентного режима кластера (параметр persistence-enabled должен иметь значение true).
Плагин предназначен для шифрования тела сообщения при его поступлении на брокер и дешифрования при его вычитке клиентом.
Шифрование и дешифрование происходит только для durable-сообщений, передаваемых по протоколам CORE и AMQP. Тестирование на других протоколах не проводилось.
При использовании плагина шифрования в кластере, состоящем из нескольких брокеров, плагин шифрования должен быть обязательно инициализирован на каждом брокере кластера.
Важно: При необходимости выключения плагина шифрования на одном из брокеров кластера производится выключение плагина (параметр mode в конфигурационном файле encryption_msg_plugin.conf устанавливается в значение Off) без перезапуска брокера. В таком случае уже зашифрованные сообщения, хранящиеся на брокере, будут расшифровываться, а вновь поступающие сообщения не будут шифроваться.
При необходимости перезапуска брокера, следует включить плагин заново, произвести рестарт, а затем выключить плагин выше описанным способом.
Ручное подключение и пример настройки плагина в конфигурационном файле broker.xml#
В classpath Artemis (например, broker_instance_dir/lib) положить encryption-message-plugin-*.jar-файл.
В конфигурации
broker.xmlв части настройки плагинов необходимо добавить следующие настройки:
<broker-plugins>
...
<broker-plugin class-name="ru.sbt.ss.artemis.encryption.message.plugin.EncryptionMessagePlugin">
<property key="CONFIG_PATH" value="path_to_config_file" /> <!-- <ОБЯЗАТЕЛЬНЫЙ ПАРАМЕТР: путь до конфигурационного файла -->
<property key="RELOAD_CHECK_PERIOD_MS" value="period_in_ms" /> <!-- НЕОБЯЗАТЕЛЬНЫЙ ПАРАМЕТР: периодичность проверки планировщиком обнаружения изменений в файле конфигурации в миллисекундах-->
</broker-plugin>
...
</broker-plugins>
<!-- ОБЯЗАТЕЛЬНАЯ НАСТРОЙКА: определяет выходной интерцептор, фильтрующий исходящие сообщения на консьюмер по признаку наличия error или encrypt хэдеров -->
<remoting-outgoing-interceptors>
<class-name>ru.sbt.ss.artemis.encryption.message.interceptor.NonDecryptMessageFilterOutgoingInterceptor</class-name>
</remoting-outgoing-interceptors>
Настройка |
Пример значения |
Значение по умолчанию |
Обязательность |
Комментарии |
|---|---|---|---|---|
CONFIG_PATH |
|
- |
Да |
путь до конфигурационного файла |
RELOAD_CHECK_PERIOD_MS |
1000 |
5000 |
Нет |
периодичность проверки планировщиком обнаружения изменений в файле конфигурации в миллисекундах |
Сформировать конфигурационный файл
encryption_msg_plugin.conf, в котором должны быть указаны необходимые настройки.
Пример конфигурационного файла:
encryptionMessagePlugin: {
mode: on
addresses: ["#", "#::#"]
excludedAddresses: ["DLQ", "DLQ::DLQ", "ExpiryQueue", "ExpiryQueue::ExpiryQueue"]
msgIdHeaderNames: ["RqUid"]
encryptionMode: disk_only
providerClassName: providerClassNameValue
vaultConfigurationPath: "etc/vault.properties"
encodingClassName: "ru.sbt.ss.password.AesGcmBaseEncryptor"
secrets: [
{
secret: "vault:kv1/certstore:key"
alias: secret_1
},
{
secret: "etc/encrypt.pass"
alias: secret_2
},
{
secret: "etc/encrypt2.pass"
alias: secret_3
}
]
activeSecret: secret_1
}
Настройка |
Пример значения |
Значение по умолчанию |
Обязательность |
Комментарии |
|---|---|---|---|---|
mode |
|
OFF |
Да |
включение/отключение плагина шифрования |
addresses |
|
|
Да |
наименования адресов, адресов::очередей, для которых будет проводится шифрование сообщений* |
excludedAddresses |
|
[] |
Нет |
наименования адресов, адресов::очередей, которые нужно исключить из результирующего перечня адресов, для которых будет проводиться шифрование** |
msgIdHeadersName |
|
[] |
Нет |
наименования заголовков сообщений, в которых может находиться id сообщения |
vaultConfigurationPath |
|
— |
Нет |
путь до конфигурационного файла, где находятся настройки для подключения к |
encodingClassName |
|
ru.sbt.ss.password.AesGcmBaseEncryptor |
Нет |
Ссылка на класс, используемый для шифрования/дешифрования сообщения, например |
encodingClassParameters |
|
|
Нет |
Перечень параметров для класса шифрования в формате key -> value****** |
hashAlgorithm |
|
SHA-256 |
Нет |
Алгоритм вычисления hash-суммы секрета |
secrets |
|
— |
Да |
Перечень секретов, которые могут быть использованы для шифрования сообщения **** |
activeSecret |
|
— |
Да |
Активный секрет, который используется при шифровании сообщения***** |
encryptionMode |
|
full |
Нет |
Режим шифрования сообщений ******* |
providerClassName |
|
- |
Нет |
Класс подключаемого криптопровайдера |
*- поддерживается wildcard-синтаксис на уровнеадресиадрес::очередь. Примеры значений:#— все адреса,#::#- все возможные комбинации адрес::очередь;**- не поддерживается wildcard-синтаксис, необходимо явно прописывать наименования адрес или адрес::очередь***- настройка необходима, если предполагается забирать секреты изHashiCorp Vault. Перечень настроек, которые могут находиться вvault.propertiesпредставлены здесь
Важно: для корректной работы плагина шифрования в блоке addresses необходимо указывать не только очереди в формате <имя адреса>::<имя очереди>, но дополнительно указывать <имя адреса>.
Например:
...
encryptionMessagePlugin: {
mode: on
addresses: ["address1", "address1::queue1"]
...
}
Минимальный набор параметров для подключения к HashiCorp Vault по APPROLE и получения секрета из хранилища
Параметр |
Комментарии |
|---|---|
ssl.vault.address |
Адрес подключения к HashiCorp Vault |
ssl.vault.auth.role.id |
Идентификатор роли приложения при ssl.vault.auth.type=approle |
ssl.vault.auth.secret.id |
Секрет роли приложения при ssl.vault.auth.type=approle |
ssl.vault.auth.type |
Тип алгоритма аутентификации в HashiCorp Vault (APPROLE) |
ssl.vault.engine.version |
Версия Key-Value хранилища секретов |
ssl.vault.tls.enable |
Включение протокола TLS при подключении к HashiCorp Vault |
ssl.vault.tls.truststore.location |
Расположение хранилища доверенных сертификатов |
ssl.vault.tls.truststore.password |
Пароль от хранилища доверенных сертификатов |
****- настройка представляет собой перечень секретов, которые могут быть использованы для шифрования/дешифрования сообщения.
Пример использования настройки можно посмотреть выше, в примере конфигурационного файла;
secret- в зависимости от того, где предполагается забирать секрет (с сервера или изHashiCorp Vault) используется различная нотация поляsecret:Секрет находится на сервере - необходимо указать путь до нахождения файла с секретом. Файл с секретом должен обязательно иметь расширение
.pass, например -secret: "etc/encrypt.pass"Секрет находится в
HashiCorp Vault— необходимо указать путь до нахождения секрета вHashiCorp Vaultв следующей нотации —secret: "vault:storePath:keyPassword", гдеvault:— обязательный префикс,storePath— путь до секрета вHashiCorp Vault,keyPassword- имя поля с паролем,
alias- псевдоним секрета, который будет использоваться вactiveSecret
***** — указывается псевдоним секрета, который будет использоваться для шифрования;
****** — перечень дополнительных параметров, которые могут быть использованы для переопределения настроек класса шифрования ru.sbt.ss.password.AesGcmBaseEncryptor.
Параметр |
Пример значения |
Значение по умолчанию |
Комментарии |
|---|---|---|---|
salt |
file:pathToFile or string_value |
Генерируемое значение |
Соль для шифрования. Может быть передана в виде ссылки на |
algorithm |
AES/GCM/NoPadding |
AES/GCM/NoPadding |
Алгоритм шифрования |
key.algorithm |
PBKDF2WithHmacSHA256 |
PBKDF2WithHmacSHA256 |
Алгоритм для генерации ключа шифрования |
key.iterations |
500 |
1000 |
Количество итераций хэширования при генерации ключа |
key.size.bytes |
512 |
256 |
Длина генерируемого ключа |
iv.size.bytes |
8 |
12 |
Длина генерируемого IV (Initialization Vector), который используется при шифровании |
gcm.auth.tag.length |
64 |
128 |
Длина Authentication Tag, который добавляется в зашифрованное сообщение, по умолчанию 128 |
*******-full- шифрование сообщения происходит при поступлении сообщения на брокер, а дешифрование происходит при вычитке сообщения или пересылке сообщения с одного брокера на другой через bridge/scaleDown.disk_only- шифрование сообщения происходит только при записи в файлы журнала, в очереди сообщения находятся в незашифрованном виде.
Подключение plugin через Jenkins Job artemis_custom#
Для подключения plugin с помощью Jenkins, необходимо в файле inventories/<новая директория>/group_vars/all/vars.yml внести настройки (пример приведен ниже), далее запустить Jenkins Job artemis_custom с параметрами:
inventory— выбрать инвентори, для которого запускается plugin;playbook— artemis.yml;tags— encryption_plugin.
Если в процессе установки кластера plugin не был включен, и затем его включили с помощью Jenkins, то необходимо перезапустить брокер, чтобы применились изменения, внесенные в broker.xml, и EncryptionMessagePlugin заработал.
Пример настройки plugin в vars.yml#
encryption_plugin:
enable: false # активация плагина шифрования сообщений на брокере
reloadCheckPeriodMs: 5000 # период (в ms) проверки изменения конфигурационного файла
addresses: [] # наименование адресов или адрес:очередь, для которых будет проводиться шифрование сообщений (поддерживаются wildCard-шаблоны Artemis)
# - "queues.test_1.Q1"
# - "#::#"
excludedAddresses: [] # наименование адресов или адрес:очередь, для которых НЕ будет проводиться шифрование сообщений (поддерживаются wildCard-шаблоны Artemis)
# - "DLQ"
# - "DLQ::DLQ"
# - "ExpiryQueue"
# - "ExpiryQueue::ExpiryQueue"
msgIdHeaderNames: [] # наименования заголовков сообщений, в которых может находиться id сообщения
# - "RqUid"
# - "messageId"
encodingClassName: ru.sbt.ss.password.AesGcmBaseEncryptor # Класс для шифрования/дешифрования сообщения
encodingClassParameters: {} # Перечень параметров для класса шифрования в формате key: value
# key1: value1
# key2: value2
hashAlgorithm: SHA-256 # Алгоритм вычисления хэш-суммы секрета
secrets: # ключи для шифрования/дешифрования сообщения
- secret: ./etc/encrypt.pass # путь до ключа для шифрования/дешифрования сообщения
alias: file_secret # алиас ключа для указания в activeSecret
# - secret: "vault:/my/store/path:secret_key" # путь до ключа в Vault для шифрования/дешифрования сообщения
# alias: vault_secret # алиас ключа для указания в activeSecret
activeSecret: file_secret # Активный секрет - секрет, с помощью которого проводится шифрование сообщений на брокере
#encryptionMode: full # full или disk_only, выбор режима шифрования. По умолчанию - full
#providerClassName: # имя класса криптопровайдера
Описание работы плагина#
Шифрование сообщений#
Для шифрования поступающего на брокер сообщения, необходимо выполнения следующих условий:
брокер находится в персистентном режиме работы;
настройка
modeнаходится в значенииon;сообщение поступает в адрес, который указан в настройках
addressesи не исключен в настройкеexcludedAddresses;признак
durableу сообщения находится в значенииtrue.
В случае, если эти условия выполнены, то происходит шифрование тела сообщения с помощью секрета, указанного в настройке activeSecret.
После шифрования, сообщение поступает в журнал на брокере и перенаправляется в очередь.
Признаком того, что тело сообщения зашифровано, является наличие заголовка HDR_ENCRYPT_MSG при нахождении сообщения на брокере.
Значением этого заголовка является hash-сумма секрета, с помощью которого было зашифровано сообщение.
По умолчанию, для расчета hash-суммы используется алгоритм SHA-256.
Дешифрование сообщений#
Перед тем как сообщение будет отправлено с брокера в сторону клиента, будет проведена проверка на наличие заголовка HDR_ENCRYPT_MSG.
Наличие такого заголовка однозначно указывает на то, что тело сообщения зашифровано.
Исходя из значения заголовка HDR_ENCRYPT_MSG (hash-сумма секрета) определяется секрет для расшифровки сообщения.
После чего сообщение будет расшифровано и заголовок HDR_ENCRYPT_MSG будет удален из сообщения.
Особенности работы плагина#
Не допускается в конфигурационном файле плагина в поле
secretsиспользовать не уникальные пары значенийsecret, alias. Каждая пара должна быть уникальной.Также и при дополнении поля
secretsновым блоком (перед обновлением конфигурации без перезапуска брокера) уникальность должна быть соблюдена.В случае, если на этапе обработки конфигурационного файла плагина происходит ошибка, то будет выброшено исключение, прерывающее инициализацию брокера. Если в
broker.xmlдобавлено использование плагина шифрования, и при этом конфигурационный файл не содержит никаких параметров, то необходимо отключить использование этого плагина, так как в противном случае инициализация брокера будет прервана и брокер не будет стартовать.Плагин поддерживает перезагрузку конфигурации без необходимости перезапуска брокера. Для того чтобы новая конфигурация была применена, необходимо обязательно провести сохранение конфигурационного файла. Например, необходимо произвести замену активного секрета на новый. Для этого в поле
activeSecretнеобходимо указать новое значение alias, после чего провести сохранение конфигурационного файла.Плагин поддерживает работу с двумя типами сообщений — текстовыми и байтовыми.
При формировании сообщения необходимо, чтобы тип сообщения был указан. В случае некорректного типа клиент-producer получит в ответ на отправленное сообщение исключение типа EncryptMessageException с указанием, что данный тип сообщения не поддерживается плагином шифрования.
После выключения плагина и перезапуска брокера сообщения перестают дешифровываться. Перед выключением плагина необходимо удостовериться в отсутствии зашифрованных сообщений на брокере необходимо запустить Jenkins job artemis_custom с playbook reencrypt_messages и tag check_only (сценарий администрирования Поиск, перешифрация и удаление устаревших ключей шифрования). В случае отсутствия на брокере зашифрованных сообщений можно выключать плагин шифрования и перезапускать брокер.
Если необходимо отказаться от шифрования вновь поступающих сообщений, тогда необходимо перевести плагин в состояние off (запустить Jenkins job artemis_custom с playbook artemis.yml, tag encryption_plugin без tag restart) и не перезапускать брокер. После этого плагин перестанет шифровать поступающие сообщения, но будет отслеживать вычитываемые сообщения на наличие заголовка HDR_encrypt_msg и расшифровывать зашифрованные сообщения.
Формирование error-header и поведение плагина при ошибках шифрования/дешифрования сообщения#
Поведение плагина при ошибке шифрования сообщения#
Если на этапе шифрования сообщения возникла ошибка, то плагин отбрасывает исключение типа EncryptMessageException в сторону клиента.
На брокере формируется лог с ошибкой и формируется аудит-событие о случившейся ошибке при шифровании. При этом такое сообщение в очередь не поступает.
Поведение плагина при ошибке дешифрации сообщения#
на этапе пересылки сообщения с одного брокера на другой (работа в режиме кластера)
Сообщение обогащается error-header
HDR_ERROR_DECRYPT_BEFORE_DELIVER_CORE_BRIDGEс указанием ошибки и параметров брокера, на котором это произошло.
Пример заголовка -
"HDR_ERROR_DECRYPT_BEFORE_DELIVER_CORE_BRIDGE": "ex=java.lang.IllegalArgumentException: EXCEPTION_DECRYPT_MESSAGE_CORE_BRIDGE, broker=Broker[host={ IP_ADDRESS }, id=26530d13-2257-11ee-90df-0050560a71e6, clusterConnectionName=my-cluster]"В брокере формируется лог с ошибкой и формируется аудит-событие о случившейся ошибке при дешифрации.
на этапе scale_down с одного брокера на другой (работа в режиме кластера)
Сообщение обогащается error-header
HDR_ERROR_DECRYPT_BEFORE_DELIVER_SCALE_DOWNс указанием ошибки и параметров брокера, на котором это произошло.
Пример заголовка -
"HDR_ERROR_DECRYPT_BEFORE_DELIVER_SCALE_DOWN": "ex=java.lang.IllegalArgumentException: EXCEPTION_DECRYPT_MESSAGE_SCALE_DOWN, broker=Broker[host={ IP_ADDRESS }, id=26530d13-2257-11ee-90df-0050560a71e6, clusterConnectionName=my-cluster]""На брокере формируется лог с ошибкой и формируется аудит-событие о случившейся ошибке при дешифрации.
на этапе вычитки сообщения consumer
Сообщение обогащается error-header
HDR_ERROR_DECRYPT_BEFORE_DELIVERс указанием ошибки и параметров брокера, на котором это произошло.Сообщение отправляется в
DeadLetterAddress, при этом consumer не получает никакого сообщения.На брокере формируется лог о случившейся ошибке и формируется аудит-событие о случившейся ошибке при дешифрации.
на этапе пересылки большого сообщения через bridge/scaleDown или вычитки консьюмером
Сообщение обогащается error-хэдером
HDR_ERROR_DECRYPT_BEFORE_DELIVER_LARGE_MESSAGEс указанием ошибки и параметров брокера на котором это произошло Пример хэдера -"HDR_ERROR_DECRYPT_BEFORE_DELIVER_LARGE_MESSAGE": "ex=java.lang.IllegalArgumentException: EXCEPTION_DECRYPT_MESSAGE_CORE_BRIDGE, broker=Broker[host={ IP_ADDRESS }, id=26530d13-2257-11ee-90df-0050560a71e6, clusterConnectionName=my-cluster]"В брокере формируется лог с ошибкой и формируется аудит-событие о случившейся ошибке при дешифрации
на этапе загрузки сообщения из файла (только при работе в режиме
disk_only)Сообщение обогащается error-хэдером
HDR_ERROR_DECRYPT_BEFORE_LOAD_FROM_STORAGEс указанием ошибки и параметров брокера на котором это произошло Пример хэдера -"HDR_ERROR_DECRYPT_BEFORE_LOAD_FROM_STORAGE": "ex=java.lang.IllegalArgumentException: EXCEPTION_DECRYPT_MESSAGE_CORE_BRIDGE, broker=Broker[host={ IP_ADDRESS }, id=26530d13-2257-11ee-90df-0050560a71e6, clusterConnectionName=my-cluster]"В брокере формируется лог с ошибкой и формируется аудит-событие о случившейся ошибке при дешифрации.
Особенности поведение плагина при ошибке дешифрации сообщения для AMQP протокола#
на этапе вычитки сообщения amqp-standard-сообщения обогащение error-хэдером не происходит
Сообщение отправляется в
DeadLetterAddress, при этом consumer не получает никакого сообщения.На брокере формируется лог о случившейся ошибке и формируется аудит-событие о случившейся ошибке при дешифрации.
Если на этапе редистрибуции сообщения с одного брокера на другой (работа в режиме кластера) или scale_down произошла ошибка дешифрации, то такое сообщение обогащается error-header и переходит на другой брокер в нерасшифрованном виде. При этом у сообщения сохраняется header HDR_ENCRYPT_MSG.
При попытке вычитки такого сообщения, происходит отправка сообщения в DeadLetterAddress, при этом consumer не получает никакого сообщения.
Также на брокере формируется лог с указанием причины возникшей ошибки, хранящейся в error-header.
Особенности работы плагина при добавлении новых очередей#
При добавлении нового адреса-очереди, происходит автоматическое обновление списка адресов-очередей, для которых будет проводиться шифрование сообщений. На этом этапе происходит их проверка на соответствие шаблонам имен адресов-очередей (wildcards), указанных в настройке плагина addresses и их отсутствие в списке имен, указанных в настройке excludedAddresses.
При перезапуске брокера и начальной инициализации плагина, в список адресов, предназначенных для шифрования сообщений, попадают только те адреса-очереди, которые указаны в конфигурации брокера в файле addresses.xml.
Для шифрования сообщений настоятельно рекомендуется явно указывать адреса-очереди в конфигурационном файле брокера addresses.xml. Иначе при рестарте брокера сообщения в таких очередях не будут шифроваться.
Особенности работы плагина при различных режимах шифрования - full/disk_only для regular-сообщений#
Режим шифрования disk_only:
шифрование сообщения происходит только при записи на диск;
дешифрование сообщения происходит при загрузке сообщения из файла в очередь брокера.
Режим шифрования full:
шифрование сообщения происходит при поступлении сообщения на брокер и в зашифрованном виде записывается на диск и поступает в очередь;
дешифрование сообщений происходит при уходе сообщения с брокера - при вычитке консьюмером, при пересылке сообщения через bridge/scaleDown.
Особенности работы плагина при поступлении на брокер large-сообщений#
Вне зависимости от установленного режима шифрования - full/disk_only - шифрование большого сообщения будет происходить при его поступлении на брокер, а дешифрование - при его вычитке или пересылке на другой брокер через bridge/scaleDown.
Обработка ошибок загрузки/перезагрузки конфигурации плагина#
Механизм перезагрузки конфигурации реализует следующее поведение в случае возникновения ошибок при чтении или обработке конфигурации методом configProcessor:
если ошибка происходит при начальной инициализации плагина, то выбрасывается исключение
ActiveMQException, которое приводит к остановке брокера;если ошибка происходит при перезагрузке плагина из-за обновления конфигурации, то плагин получает последнюю успешно загруженную конфигурацию через callback-метод
onProcessConfig;если ошибки при обработке отсутствуют, то плагин получает новую загруженную из файла конфигурацию через callback-метод
onProcessConfig.
При возникновении ошибок формируется лог о случившейся ошибке.
Перечень аудит-событий, формируемых плагином#
Сущность |
Операция |
Идентификатор лога |
|---|---|---|
Сообщение |
ошибка на этапе шифрования (неудачное) |
Audit_0011 |
ошибка на этапе дешифрации (неудачное) |
Audit_0012 |
|
Ключ_шифрования |
добавление ключа шифрования в конфигурации плагина (удачное) |
Audit_0013 |
удаление ключа шифрования из конфигурации плагина (удачное) |
Audit_0014 |
|
Активный_ключ |
обновление активного ключа в конфигурации плагина (удачное) |
Audit_0015 |
Для отправки аудит-событий в Platform V Audit необходимо дополнительно настроить logback.xml, добавив дополнительный logger, appender:
<logger name="ru.sbt.ss.artemis.encryption.message.plugin.audit.event.EncryptionAuditLog" level="INFO" additivity="false">
<appender-ref ref="audit"/>
</logger>
Метрики плагина#
secretHash— метрика, строковым значением которой является списокalias -> hash-суммадля указанных секретов в конфигурации плагина в полеsecrets.
MBean name для метрики
org.apache.activemq.artemis:broker="brokerName",component=encryption_plugin_metric,name=secretHash"
Пример значения метрики:
[
{
"alias": "secret1",
"hash": "<hash>"
},
{
"alias": "secret2",
"hash": "<hash>"
}
]