Clustering

Примечание

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

  • Если кластер потерян (кворум утрачен), единственным средством восстановления является заводская перезагрузка + восстановление. Обязательно часто делайте резервные копии. В будущих версиях будут доступны средства восстановления данных на диске.

  • Активная/пассивная настройка для поддержки двухузловых кластеров с использованием etcd Learner или Mirror пока недоступна.

  • Пока что системное время между узлами должно синхронизироваться вручную. В будущем выпуске будет предусмотрена автоматическая синхронизация часов.

NetHSM 4.0 и выше поддерживает кластеризацию для прямой синхронизации данных между несколькими NetHSM. Это позволяет поддерживать высокую частоту генерации ключей, реализовать высокую доступность и балансировку нагрузки. Кластер NetHSM основан на etcd, который использует алгоритм консенсуса Raft для обеспечения сильной согласованности. Это гарантирует, что данные (например, ключи) будут корректными во всех NetHSM в любое время.

Перед созданием кластера NetHSM ознакомьтесь с этой технологией и ее ограничениями, чтобы избежать аварийного отключения и потери данных. В дополнение к этому документу вы можете обратиться к документации etcd.

Operational Redundancy

Мы будем называть «узлом» NetHSM, который должен быть частью кластера. Кластер из узлов N будет работать до тех пор, пока хотя бы (N/2)+1 узлы здоровы и доступны. Это минимальное количество здоровых и доступных узлов называется кворумом **** .

Это предполагает следующие сценарии.

Один узел вышел из строя, но кворум все равно достигнут

В кластере из 3 узлов, если один узел выходит из строя (падает или становится недоступным из-за сетевых условий), два других узла продолжают работать и обслуживать запросы.

Если отказавший узел все еще здоров (например, возникли проблемы с сетью), он будет неработоспособен в изолированном состоянии (даже не доступен только для чтения).

Однако если узел восстановится, то он без проблем пересинхронизируется с остальными узлами кластера и снова станет работоспособным без потери данных.

Если он так и не восстановится, его придется удалить из кластера (см. следующий раздел), сбросить заводские настройки и пройти процесс присоединения заново.

Произошло разделение сети, но кворум все еще достигнут

Это просто обобщение предыдущего сценария. В кластере из 5 узлов, где, например, 3 узла находятся в одном физическом месте A, а 2 узла - в другом месте B, сетевая проблема, изолирующая A и B, будет означать следующее:

  • Три узла в расположении A удовлетворяют кворуму (3 в данном случае), поэтому они продолжают работать.

  • Два узла в локации B - не удовлетворяют кворуму (по-прежнему 3), поэтому они перестанут работать (даже в режиме чтения).

  • Если проблема с сетью решена, эти 2 узла без проблем присоединятся к 3 другим.

Кворум окончательно потерян

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

Это может произойти, например, при отказе одного узла в кластере из двух узлов (где кворум равен 2). В такой ситуации отказавший узел нельзя удалить из кластера, поскольку оставшийся здоровый узел уже неработоспособен, так как потерял кворум.

Поэтому рекомендуется всегда иметь нечетное количество узлов в кластере и часто выполнять резервное копирование.

To be clear, temporarily losing quorum (for example, if you are restarting all nodes of a cluster together, or a temporary network failure isolates nodes) is not a problem: once enough nodes are reconnected (without having to manually re-join) to reach quorum, the cluster will resume its normal operation. Only permanent failures such as network partitions, network misconfigurations, authentication issues or hardware failures, will require manual action.

Дополнительные сведения см. на сайте ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ.

2-узловой кластер

Двухузловой активный/пассивный кластер пока не поддерживается и будет добавлен в будущей версии. Мы рекомендуем ввести третий узел, либо третий NetHSM, либо «свидетель» etcd, который может работать на любом хосте. См. следующий раздел «Свидетель».

Свидетель

Природа кластеризации с etcd делает ее тем надежнее, чем больше узлов в кластере. Как объясняется в разделе `»Оперативная избыточность», кластеры в идеале должны иметь не менее 3 узлов, чтобы иметь возможность отказа, поскольку кластер из 2 узлов полностью выйдет из строя, если откажет только один.

Однако конструкция этой функции такова, что для достижения стабильного количества узлов вам не нужно добавлять в кластер полноценное устройство NetHSM. Вместо этого вы можете самостоятельно развернуть и добавить узел-«свидетель». Такой узел - это просто экземпляр etcd, запущенный на выбранной вами машине (или в контейнере) и подключенный к кластеру. Он будет распознаваться как обычный узел реальными устройствами в кластере и получать все данные и обновления от устройств (но, конечно, вы не сможете выполнять с ним никаких операций HSM - он только хранит данные).

Security Considerations

Узел-свидетель (или любой, кто имеет к нему доступ) имеет прямой доступ к бэкенду хранилища всех узлов кластера (например, вы можете выгрузить все записи и соответствующие значения с помощью etcdctl get "/" "0").

Однако, за исключением версии конфигурации (/config/version, которая всегда должна быть «1»), строго все значения зашифрованы (либо ключом устройства для значений, специфичных для узла, либо ключами домена для остальных), что обеспечивает конфиденциальность важных данных.

Однако следует отметить, что вредоносный узел может:

  • записывать мусор в качестве значения для любой записи в хранилище, что приведет к отказу узлов расшифровывать его (что может привести к сбоям для некоторых системных записей).

  • список имен записей, таких как пользователи, пространства имен и ключи, которые вы можете считать конфиденциальными.

Что разделяется между узлами

Наличие кластера NetHSM означает, что большая часть данных используется совместно. Любое добавление, изменение или удаление ключей, пользователей или пространств имен на одном узле в конечном итоге отражается на всех остальных. В общем, любая операция, изменяющая состояние, изменяет состояние каждого узла. Сюда входит операция резервного копирования восстановления, которая работает как обычно.

В следующих разделах подробно описано, какие данные являются полностью локальными, какие хранятся в общем etcd хранилище, но остаются специфичными для узла, а какие полностью разделяются между узлами.

Не хранится в etcd

Ключ устройства каждого узла хранится только локально и никогда не передается между узлами.

Хранится в etcd, но зависит от узла

Следующие данные хранятся в etcd в разных диапазонах для каждого узла. Поэтому они доступны ** для каждого узла, но не единообразны для всех узлов (каждый узел может иметь разное значение для этих данных).

Configuration:

  • TLS certificates

  • clock configuration

  • network configuration

  • logging configuration

  • unattended boot configuration

  • соль для разблокировки (чтобы у каждого узла была своя парольная фраза для разблокировки)

  • ключ блокировки домена

Обратите внимание, что хотя каждый узел имеет свою версию заблокированного ключа домена (поскольку каждый узел блокирует его своим ключом устройства или парольной фразой для разблокировки), базовый ключ домена является общим для всех узлов (для доступа к их общим данным HSM, таким как ключи).

Хранится в etcd и находится в общем доступе

Все следующие данные хранятся в etcd в глобальной области видимости, поэтому они едины для всех узлов кластера:

Данные HSM:

  • keys

  • users

  • namespaces

Configuration:

  • config/domain store version

  • кластерный ЦС (используется для аутентификации узлов в кластере)

  • backup passphrase and backup salt

Обратите внимание, что пока версия хранилища конфигурации/доменов может быть только версии 1 (если ваша версия программного обеспечения поддерживает кластеризацию, то это то, что у вас есть). Обратитесь к разделу Обновление ПО в кластерах для получения более подробной информации о безопасности установки обновлений ПО в кластере.

Creating a Cluster

Любой кластер изначально состоит из одного узла. Новые узлы будут присоединяться к кластеру по очереди.

Preparing Nodes

Сетевой трафик между узлами шифруется и аутентифицируется с помощью их сертификата TLS.

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

В дальнейшем мы предполагаем, что все узлы только что созданы и работают.

Networking

Nodes must first be reconfigured with their expected final network configuration using the /config/network endpoint (refer to the API documentation).

Создание и установка ЦС

Пользователи должны создавать ЦС собственными средствами и в соответствии со своими операционными ограничениями, убедившись, что он позволяет использовать, по крайней мере, ключ keyCertSign.

Например, минимальный ЦС может быть создан с помощью openssl:

$ openssl genrsa -out CA.key 2048 # create a key
$ openssl req -x509 -new -nodes -key CA.key -sha256 -days 1825 -out CA.pem -addext keyUsage=critical,keyCertSign

Теперь этот ЦС должен быть установлен на каждом узле.

To do this, first generate a Certificate Signing Request (CSR) from the node with the /config/tls/csr.pem endpoint (refer to the API documentation).

Примечание

Для правильной аутентификации узлов бэкэнд кластеризации (etcd) ожидает, что у каждого узла есть сертификат с правильно заполненным полем Subject Alt Names (SAN). В частности, узлы, к которым предполагается обращаться только через их IP, должны иметь в сертификате соответствующий IP SAN. IP SAN можно запросить в CSR, добавив к именам префикс «IP:», как в openssl:

"subjectAltNames": [ "normalname.org", "IP:192.168.1.1" ]

Учитывая полученный CSR (назовем его nethsm.csr), мы можем сгенерировать для него сертификат, готовый к установке. Например, с openssl:

$ openssl x509 -req -days 1825 -in nethsm.csr -CA CA.pem -copy_extensions copy \
    -CAkey CA.key -out new_cert.pem -set_serial 01 -sha256

Then install the obtained new_cert.pem with the /config/tls/cert.pem endpoint (refer to the API documentation).

Наконец, CA (CA.pem) теперь может быть установлен с помощью конечной точки /config/tls/cluster-ca.pem (см. документацию API). Это возможно только после того, как установленный TLS-сертификат будет им подписан. В противном случае операция будет отклонена.

Примечание

Этот процесс необходимо повторить для каждого узла.

Синхронизация часов

Убедитесь, что на каждом узле установлено точное системное время. Если нет, настройте их часы с помощью конечной точки /config/time.

Adding a New Node

Добавление узла в кластер выполняется в два этапа:

  • зарегистрируйте добавление в кластере (через любого из его участников)

  • сообщите новому узлу, чтобы он присоединился

Configure a Backup Passphrase

Сначала убедитесь, что на узле, который будет использоваться для регистрации нового участника, настроена резервная парольная фраза (см. документацию по API конечной точки /config/backup-passphrase).

Регистрация нового узла

Предупреждение

Регистрация узла немедленно вводит новый узел в кластер, изменяя порог кворума, даже если узел еще не присоединился. Это может сделать существующие узлы неработоспособными до тех пор, пока новый узел не присоединится к ним. См. документацию по API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __ и раздел Operational Redundancy этого документа.

Имейте под рукой IP узла, который будет присоединяться. Полный URL (также называемый peer URL в терминологии etcd) этого узла будет https://<IP_of_node>:2380 (например, https://192.168.1.1:2380). Порт должен быть 2380, поэтому убедитесь, что любой брандмауэр между узлами разрешает TCP-трафик на этом порту.

Вы можете дважды убедиться в правильности URL, вызвав GET /cluster/members на узле, к которому предполагается присоединиться. В списке должен быть только один участник: он сам.

Затем зарегистрируйте ожидаемый URL на любом существующем узле кластера (если у вас еще нет кластера, сделайте это на NetHSM, который будет служить начальным узлом кластера). Это делается с помощью конечной точки POST /cluster/members (см. документацию по API ` <https://nethsmdemo.nitrokey.com/api_docs/index.html>` __), передавая ей тело JSON, содержащее URL.

В случае успеха возвращается JSON-тело формы:

{
  "members": [
    {
      "name": "",
      "urls": [
        "https://172.22.1.3:2380"
      ]
    },
    {
      "name": "9ZVNM2MNWP",
      "urls": [
        "https://172.22.1.2:2380"
      ]
    }
  ],
  "joinerKit": "eyJiYWNrdXBfc2FsdCI6IkVlUzNPOEhHSEc5NnlNRktrdG1NZmc9PSIsInVubG9ja19zYWx0IjoiU3phMkEvYW13NlhxVWsrdHZMMmFubm5SZFlWd2ZQUjdpZ3IxK1RSdTdVaU14dmh3d0x2NWIvYVNkY2c9IiwibG9ja2VkX2RvbWFpbl9rZXkiOiIyMnNGVlkyelhQUVZ6S1pQenI3MmkwTk1WM3lmQ2k5dGwzeDhUbGtuOXM0WjFOd3JoZkRQTFZIVHp1WVl0YkQxaVZCMlovV3JHUHJlMXlwN0t4U0w4WkxjY2ZUTmUzcFg0WXE4YXNlY0wwREhXNGlIaXlPMlZnPT0ifQ=="
}

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

Сохраните этот ответ для следующего шага.

Фактическое присоединение к кластеру

Возьмите ответ с последнего шага и добавьте к нему поле backupPassphrase, содержащее резервную парольную фразу узла, на котором был зарегистрирован новый участник, и передайте эти данные в вызов POST /cluster/join (см. документацию API) на узле, к которому ожидается присоединение.

Предполагая, что кластер и узел могут связаться друг с другом, это приведет к фактическому присоединению, стирая данные нового участника, чтобы синхронизировать его состояние с состоянием кластера.

В зависимости от состояния сети и кластера эта операция может занять несколько десятков секунд. Если операция не удалась сразу (например, кластер не был доступен или аутентификация не прошла), состояние узла не будет стерто, и присоединение будет отменено. Однако как только первое присоединение будет успешным, эта операция станет окончательной и может быть отменена только сбросом на заводские настройки.

Если присоединение прошло успешно, узел окажется в состоянии Locked и должен быть разблокирован с помощью парольной фразы разблокировки узла, который использовался для регистрации. После этого парольная фраза разблокировки может быть изменена (парольные фразы разблокировки остаются специфичными для узла и не передаются между узлами).

Примечание

Даже после успешного присоединения, если база данных кластера велика или кластер занят, новому присоединившемуся узлу может потребоваться некоторое время для полной синхронизации своего состояния. В течение этого времени все узлы (включая, в частности, новый присоединившийся) могут быть менее отзывчивыми или не реагировать на запросы. В частности, новый присоединяемый узел может сначала выдавать ошибки при попытке его разблокировать. В этом случае дайте ему немного времени и попробуйте снова.

Adding a Witness Node

Prepare a Witness

Вам понадобится среда с доступной версией etcd v3.6, с адресом IPv4 (по крайней мере), до которого могут добраться другие участники вашего кластера. TCP-трафик на порт 2380 и с него должен быть разрешен.

Создайте пустой каталог, в котором etcd будет хранить свои данные, и запишите путь к нему (мы будем использовать /var/etcd/data). Убедитесь, что пользователь, который будет запускать процесс, имеет право на чтение и запись в каталог.

Перенесите на машину сертификат ЦС, который используется для аутентификации узлов в кластере. Вы должны были создать его в разделе Создание и установка CA. Мы будем хранить его в /var/etcd/CA.pem.

Затем вам нужно будет создать сертификат для свидетеля и подписать его в центре сертификации, чтобы он мог общаться со своими коллегами. Это можно сделать, например, с помощью openssl:

# Create a key
$ openssl genrsa -out witness.key 2048
# Create a CSR with a SAN that corresponds to the witness's IP or hostname
$ openssl req -new -sha256 -key own.key -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=witness" \
    -addext "subjectAltName=IP:172.22.1.3" --out witness.csr
# Sign it
$ openssl x509 -req -days 1825 -in witness.csr -CA CA.pem -copy_extensions copy \
    -CAkey CA.key -out witness.pem -set_serial 01 -sha256

Сохраните получившиеся witness.key и witness.pem в /var/etcd.

Register Witness to Cluster

Следуйте обычным инструкциям из раздела `»Регистрация нового узла», чтобы сообщить существующему кластеру о добавлении нового участника с указанным URL.

Запишите ответ от кластера: он должен содержать список участников кластера и набор для присоединения (эта часть вам не понадобится).

Configure etcd

В отличие от NetHSM, которые автоматически выбирают имя узла для себя (используя идентификатор устройства), вы должны выбрать имя для каждого добавляемого свидетеля, убедившись, что имена уникальны. В следующих примерах мы будем использовать «witness1».

Вместе с ответом NetHSM о регистрации свидетеля подготовьте переменные формы:

export ETCD_NAME="witness1"
export ETCD_DATA_DIR="/var/etcd/data"
export ETCD_INITIAL_CLUSTER="peer1=url1,peer1=url2,peer2=url1,peer2=url2,..."
export ETCD_INITIAL_ADVERTISE_PEER_URLS="my_url1,my_url2,..."

Если предположить, что ответ NetHSM хранится в файле response.json, то эти две последние переменные можно сгенерировать автоматически с помощью следующих выражений jq:

export ETCD_INITIAL_CLUSTER=$(jq --raw-output '[.members[] | ["\(if .name == "" then "witness1" else .name end)=\(.urls[])"]] | flatten | join(",")' < response.json)
export ETCD_INITIAL_ADVERTISE_PEER_URLS=$(jq --raw-output '.members[] | select(.name=="") | .urls | join(",")' < response.json)

Например, в примере ответа, приведенном в разделе Регистрация нового узла, вы получите:

ETCD_NAME="witness1"
ETCD_DATA_DIR="/var/etcd/data"
ETCD_INITIAL_CLUSTER="witness1=https://172.22.1.3:2380,9ZVNM2MNWP=https://172.22.1.2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://172.22.1.3:2380"

Наконец, создайте файл etcd.conf.yml, используя файл-шаблон, представленный в docs/etcd_witness.conf.template:

$ envsubst < NETHSM_ROOT/docs/etcd_witness.conf.template > /var/etcd/witness.conf.yml
$ cat witness.conf.yml

В результате вы получите файл с формой:

name: witness1
data-dir: /var/etcd/data
log-level: warn
log-format: console

listen-peer-urls: https://0.0.0.0:2380
listen-client-urls: http://localhost:2379

initial-advertise-peer-urls: https://172.22.1.3:2380
advertise-client-urls: http://localhost:2379
initial-cluster: witness1=https://172.22.1.3:2380,9ZVNM2MNWP=https://172.22.1.2:2380
initial-cluster-state: 'existing'

peer-transport-security:
  cert-file: witness.pem
  key-file: witness.key
  client-cert-auth: true
  trusted-ca-file: CA.pem
  skip-client-san-verification: true

Start etcd

Запустите etcd предпочтительным для вас способом (вручную, systemd сервис, контейнер и т.д.), указав ему на файл конфигурации, созданный в предыдущем шаге:

$ cd /var/etcd
$ etcd --config-file witness.conf.yml

Вы должны увидеть, как он запускается, присоединяется к кластеру и подхватывает данные. Через некоторое время вы сможете проверить его работоспособность с помощью клиента etcdctl:

etcdctl get /config/version

Этот ключ должен существовать и содержать «1».

Убедитесь, что этот процесс продолжается, поскольку теперь он является полноценным членом вашего кластера. Если вам нужно вывести его из эксплуатации, сначала правильно удалите его из кластера (см. специальный раздел). Если его достижимый IP изменился, обновите его URL из кластера.

Operating a Cluster

Резервное копирование и восстановление

Операция резервного копирования работает так же, как и без кластера, и может быть запрошена с любого узла кластера. Резервная копия данных будет создана для всего кластера, включая поля, специфичные для узла (хотя они будут проигнорированы, если не восстанавливать резервную копию на нераспределенном узле).

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

При восстановлении резервной копии на неразрешенном узле будут восстановлены специфические для узла поля (например, конфигурация сети, сертификаты и т. д.) узла, на котором была создана резервная копия.

Восстановление большой резервной копии может на некоторое время перегрузить кластер, пока узел, применяющий восстановление, будет передавать изменения остальным.

Эта операция совместима с резервными копиями, созданными на предыдущих версиях NetHSM.

Примечание

Восстановление на узле A резервной копии, сделанной на другом узле Z с другим ключом домена, корректно перезапишет ключ домена A, как и раньше. Однако если A находился в кластере с узлом B, B станет неработоспособным, поскольку ключ домена Z не будет восстановлен на B.

Другими словами, выполняйте восстановление только в кластере с резервными копиями, созданными в том же кластере (хотя с тех пор узлы могли быть удалены или добавлены). Если вы хотите восстановить чужую резервную копию на узле, сначала безопасно удалите его из кластера, затем выполните заводской сброс и восстановите резервную копию.

Чистое удаление узла

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

Сначала нужно узнать ID узла, который вы хотите удалить, перечислив все узлы через GET /cluster/members и отыскав нужный.

Затем его можно удалить, вызвав команду DELETE /cluster/members/<id>. Если рассматриваемый узел все еще был здоров, это изолирует его от остального кластера и сделает неработоспособным.

Software Updates in Clusters

Будущие обновления будут помечены как «кластерно-безопасные» (это должно быть большинство) или «кластерно-небезопасные».

Кластерно-безопасные обновления можно применять к узлам, входящим в кластер, не удаляя их из кластера. Однако, как и при любых других операциях, вы должны убедиться, что это делается на одном узле за раз и в таком кластере, где удаление узла не приведет к снижению кворума (например, если обновление не удастся).

Небезопасные для кластера обновления должны применяться на изолированных узлах. Вам следует разобрать кластер (удаляя узлы по одному), сбросить все узлы, кроме одного, применить обновление к каждому узлу, а затем заставить все сброшенные узлы присоединиться к оставшемуся узлу.

Перед такими операциями обязательно создайте резервную копию.

Изменение конфигурации существующего кластера

Changing the Cluster CA

Существующий кластер (с двумя или более узлами) не может изменить свой кластерный ЦС во время работы. Если вам нужно изменить этот сертификат: выберите узел, удалите все остальные узлы, обновите ЦС, а затем попросите остальных участников снова присоединиться.

Changing the Network Configuration of Nodes

Изменение сетевой конфигурации узла (например, изменение его IP) автоматически сообщит об этом другим узлам. Однако следует убедиться, что такие обновления выполняются только на одном узле за раз и в таком кластере, где потеря этого узла не приведет к потере кворума.