Vault поддерживает множество серверных хранилищ для хранения зашифрованных данных (например, Consul, MySQL, DynamoDB и т. д.). Мы рассмотрим несколько вариантов

VAULT - часть 2: Кластер Vault High Availability Integrated Storage (RAFT)

Подготовка сертификатов TLS

Добавление сертификатов в доверенные

Подготовка кластера

Восстановление кворума

VAULT - часть 2: Кластер High Availability (Consul)

Настройка кластера

Развертывание кластера Vault HA Integrated Storage (RAFT)

Интегрированное хранилище имеет следующие преимущества:

 Использование интегрированного хранилища Vault требует настройки серверной части хранилища Raft. Одноранговые узлы Raft могут быть инициализированы вручную с жестко заданными значениями конфигурации

     Прежде чем мы рассмотрим установку кластера, рассмотрим, как узлы Vault общаются друг с другом. 
     Vault предоставляет два TCP-порта: порт API и порт кластера. 
     Через порт API клиенты отправляют свои HTTP-запросы Vault. 
  Для кластера Vault с одним узлом вам не нужно беспокоиться о порте кластера, так как он не будет использоваться. Если у вас несколько узлов, вам нужен порт кластера. Он используется узлами Vault для выдачи RPC друг другу, например, для пересылки запросов от резервного узла к активному узлу или, когда используется Raft, для обработки выбора лидера и репликации сохраненных данных. 
 Порт кластера защищен с помощью сертификата TLS, который генерируется активным узлом хранилища. Понятно, как это может работать, если не используется интегрированное хранилище: каждый узел имеет как минимум доступ для чтения к хранилищу, поэтому, как только активный узел сохранил сертификат, резервные узлы могут его получить, и все согласны с тем, как следует шифровать трафик кластера. 
   Узлы не имеют общего представления о хранилище, пока не будет сформирован кластер, но мы пытаемся сформировать кластер! Чтобы решить эту проблему, узел Vault должен взаимодействовать с другим узлом Vault, используя порт API вместо порта кластера. В настоящее время это единственная ситуация, в которой OSS Vault делает это.

node2 хочет присоединиться к кластеру, поэтому отправляет вызов API-запрос  существующему участнику
node1 отвечает на запрос запроса с (1) зашифрованным случайным UUID и (2) конфигурацией seal
node2 необходимо расшифровать UUID с помощью seal; если с помощью автоматического unseal (распечатывания) можно сделать это напрямую, если с помощью Шамира нужно дождаться, пока пользователь предоставит достаточно ключей для unseal выполнения расшифровки 
node2 отправляет расшифрованный UUID обратно в node1 API ответ 

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

Подготовка сертификатов TLS

ПРИМЕЧАНИЕ. ​Пакет установки создает самозаверяющий сертификат TLS для использования службой Vault для защиты связи внутри кластера. Хотя эти сертификаты можно использовать для экспериментов с запуском и запуском Vault, HashiCorp настоятельно рекомендует заменить их сертификатами, сгенерированными и подписанными соответствующим ЦС.

       У вас должно быть три файла для настройки TLS для Vault. 
/opt/vault/tls/vault-cert.pem - cертификат Vault TLS, представляющий собой общее имя (CN) или альтернативное имя субъекта (SAN), которое соответствует значению, заданному leader_tls_servername в конфигурации Raft. Если этот файл был подписан промежуточным ЦС, добавьте сертификат этого ЦС (и любых других связанных ЦС) в конец этого файла.
/opt/vault/tls/vault-key.pem - Закрытый ключ сертификата Vault TLS.
/opt/vault/tls/vault-ca.pem - Сертификат корневого ЦС, подписавшего сертификат Vault TLS.    

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

   Создание и проверка пары корневых ключей CA​ с парольной фразой

$  openssl genrsa -aes256 -out /opt/vault/tls/vault-ca-key.pem 4096
openssl req -new -x509 -nodes -days 3650 -key ​/opt/vault/tls/vault-ca-key.pem -out /opt/vault/tls/vault-ca-cert.pem 
$  openssl x509 -noout -text -in ./vault-ca-cert.pem

             Подготовка конфигурационных файлов с необходимыми параметрами Vault TLS

cat <<EOF > /opt/vault/tls/cert-vault1.cfg 
[v3_ca] 
subjectAltName = @alt_names 
[alt_names] 
DNS.1 = vault.example.org
DNS.2 = vault1.example.org 
IP.1 = 10.0.0.1 
IP.2 = 127.0.0.1 
EOF
cat <<EOF > /opt/vault/tls/cert-vault2.cfg 
[v3_ca] 
subjectAltName = @alt_names 
[alt_names]
DNS.1 = vault.example.org 
DNS.2 = vault2.example.org 
IP.1 = 10.0.0.2 
IP.2 = 127.0.0.1 
EOF
$ ​cat <<EOF > /opt/vault/tls/cert-vault3.cfg 
[v3_ca] 
subjectAltName = @alt_names 
[alt_names]
DNS.1 = vault.example.org
DNS.2 = vault3.example.org 
IP.1 = 10.0.0.3 
IP.2 = 127.0.0.1 
EOF  

             Подготовка CSR запроса:

openssl req -newkey rsa:4096 -nodes -keyout vault1-key.pem -out vault1-csr.pem -subj "/CN=vault.example.org" 
openssl req -newkey rsa:4096 -nodes -keyout vault2-key.pem -out vault2-csr.pem -subj "/CN=vault.example.org" 
openssl req -newkey rsa:4096 -nodes -keyout vault3-key.pem -out vault3-csr.pem -subj "/CN=vault.example.org" 

             Выпуск сертификатов:

openssl x509 -req -set_serial 01 -days 3650 -in vault1-csr.pem -out vault1-cert.pem -CA vault-ca-cert.pem -CAkey vault-ca-key.pem -extensions v3_ca -extfile cert-vault1.cfg 
$  openssl x509 -req -set_serial 01 -days 3650 -in vault2-csr.pem -out vault2-cert.pem -CA vault-ca-cert.pem -CAkey vault-ca-key.pem -extensions v3_ca -extfile cert-vault2.cfg 
$  openssl x509 -req -set_serial 01 -days 3650 -in vault3-csr.pem -out vault3-cert.pem -CA vault-ca-cert.pem -CAkey vault-ca-key.pem -extensions v3_ca -extfile cert-vault3.cfg 

              Проверка Subject Alternative Name:

openssl x509 -noout -text -in ./vault1-cert.pem
  ...
        X509v3 extensions:
                   X509v3 Subject Alternative Name:
                              DNS:vault1.example.org, IP Address:10.0.0.1, IP Address:127.0.0.1

  ...

Добавление сертификатов в доверенные

В дистрибутивах Linux на базе RPM (CentOS, Oracle, RHEL, Rocky Linux, Fedora) для добавления сертификата в доверенные:

$ ​​​​ ​ yum install ca-certificates
$   cp mycert.pem /etc/pki/ca-trust/source/anchors/
$   update-ca-trust force-enable
$   update-ca-trust extract

Подготовка кластера

  Скопируйте сертификаты для каждой из нод vault и установите права собственности на файлы ЦС и сертификатов, чтобы они принадлежали пользователю root.

sudo chown root:root /opt/vault/tls/vault1-cert.pem /opt/vault/tls/vault-ca-cert.pem    

  Установите права доступа к файлам ЦС и сертификатов, чтобы они были доступны для чтения всем пользователям

$  sudo chmod 0644 /opt/vault/tls/vault1-cert.pem /opt/vault/tls/vault-ca-cert.pem         

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

$  sudo chown root:vault /opt/vault/tls/ vault1-key.pem      

   Установите права доступа к файлу закрытого ключа так, чтобы он был доступен для чтения только службе Vault.

sudo chmod 0640 /opt/vault/tls/ vault1-key.pem            

  Конфигурация Vault - раздел listener можно указать несколько раз, чтобы Vault прослушивал несколько интерфейсов. Если вы настраиваете несколько прослушивателей, вам также необходимо указать, api_addr чтобы cluster_addr Vault сообщал правильный адрес другим узлам.
     Основные обязательные значения конфигурации для Vault

api_addr – ​Указывает адрес (полный URL-адрес) для объявления другим серверам Vault в кластере для перенаправления клиентов. Это значение также используется для бэкендов плагинов . Это также может быть предоставлено через переменную окружения VAULT_API_ADDR. Как правило, это должен быть полный URL-адрес, указывающий на значение адреса listener.             
cluster_addr – ​Указывает адрес для объявления другим серверам Vault в кластере для переадресации запросов. Это также может быть предоставлено через переменную окружения VAULT_CLUSTER_ADDR.             
listener - Настраивает, как Vault прослушивает запросы API.

НЕОБЯЗАТЕЛЬНЫЕ ЗНАЧЕНИЯ КОНФИГУРАЦИИ

tls_client_ca_file - Файл центра сертификации в кодировке PEM, используемый для проверки подлинности клиента.
tls_require_and_verify_client_cert - Включает аутентификацию клиента для этого слушателя; слушателю потребуется представленный сертификат клиента, который успешно проверяется системными центрами сертификации.
tls_disable_client_certs - Отключает аутентификацию клиента для этого прослушивателя. Поведение по умолчанию (если это значение равно false) заключается в том, что Vault запрашивает клиентские сертификаты, когда они доступны.

Предупреждение. Поля tls_disable_client_certs и tls_require_and_verify_client_cert в разделе прослушивателя конфигурации сервера Vault являются взаимоисключающими полями. Убедитесь, что они оба не установлены в true. Проверка клиента TLS остается необязательной с настройками по умолчанию и не применяется принудительно.

   Если вы решили использовать параметр конфигурации tls_require_and_verify_client_cert -  необходимо добавить  переменные окружения

$  export VAULT_CACERT=/opt/vault/tls/vault-ca-cert.pem 
$  export VAULT_CLIENT_CERT=/opt/vault/tls/vault1-cert.pem
$  
export VAULT_CLIENT_KEY=/opt/vault/tls/vault1-key.pem

cmd   setx VAULT_ADDR "https://vault.example.org:8200"
cmd  setx VAULT_CACERT "%USERPROFILE%\VAULT\ca-vault.crt"

cmd   setx VAULT_CLIENT_CERT "%USERPROFILE%\VAULT\vault1.crt"
cmd  setx VAULT_CLIENT_KEY "%USERPROFILE%\VAULT\vault.key"

            Пример конфигурации для узла 1:

$  ​ vi /etc/vault.d/vault.hcl    
cluster_addr  = "https://vault1.example.org:8201" 
api_addr      = "https://vault.example.org:8200"
disable_mlock = true
ui = true
listener "tcp" {   
   address            = "0.0.0.0:8200"   
   tls_client_ca_file   = "/opt/vault/tls/vault-ca-cert.pem"
   tls_require_and_verify_client_cert = true   
   tls_cert_file      = "/opt/vault/tls/vault1-cert.pem"   
   tls_key_file       = "/opt/vault/tls/vault1-key.pem"
}
storage "raft" {   
   path    = "/opt/vault/data"   
   node_id = "vault1.example.org"
   retry_join {     
     leader_tls_servername   = "vault1.example.org"     
     leader_api_addr         = "https://vault1.example.org:8200"     
     leader_ca_cert_file     = "/opt/vault/tls/vault-ca-cert.pem"     
     leader_client_cert_file = "/opt/vault/tls/vault1-cert.pem"     
     leader_client_key_file  = "/opt/vault/tls/vault1-key.pem"   
   }   
   retry_join {
     leader_tls_servername   = "vault2.example.org"
     leader_api_addr         = "https://vault2.example.org:8200"
     leader_ca_cert_file     = "/opt/vault/tls/vault-ca-cert.pem"
     leader_client_cert_file = "/opt/vault/tls/vault1-cert.pem"
     leader_client_key_file  = "/opt/vault/tls/vault1-key.pem"
   }   
retry_join {
     leader_tls_servername   = "vault3.example.org"
     leader_api_addr         = "https://vault3.example.org:8200"
     leader_ca_cert_file     = "/opt/vault/tls/vault-ca-cert.pem"
     leader_client_cert_file = "/opt/vault/tls/vault1-cert.pem"
     leader_client_key_file  = "/opt/vault/tls/vault1-key.pem"
   }
}        

          Запускаем службу.

systemctl start vault           

          Проверяем статус:

vault status
Key                           Value
---                           -----
Seal Type               shamir
Initialized             false
Sealed                     true
...
Storage Type       raft
HA Enabled          true

      

           Теперь необходимо инициализировать и распечатать сервер.
           Описание процесса инициализации и "распечатывания" описано в первой части

Инициализация Vault

           Проверяем статус после инициализации и "распечатывания":

vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
...
Storage Type raft
...
HA Enabled true
HA Cluster https://10.0.0.1:8201
HA Mode active

...

        Проводим аналогичные действия для всех нод (без инициализации)

ПРИМЕЧАНИЕ. ​​При запуске в режиме HA инициализация происходит один раз на кластер

        Авторизируемся с помощью ​Initial Root Token

vault login           

        Проверяем статус хранилища

vault operator raft list-peers     
Node                                 Address          State     Voter
----                                 -------         -----   -----
vault1.example.org    10.0.0.1:8201 ​leader       true
vault2.example.org   10.0.0.2:8201 follower  true
vault3.example.org   10.0.0.3:8201 ​follower  true     

     Добавляем Round Robin DNS - vault.example.org c IP адресами нод в DNS сервер или hosts клиентам которые используют Vault.
Кластер Vault (RAFT) готов к использованию

     Удаление однорангового узла является необходимым шагом, когда вы больше не хотите, чтобы узел был в кластере. Это может произойти, если узел заменяется новым, имя хоста постоянно меняется и к нему больше нельзя получить доступ, вы пытаетесь уменьшить размер кластера или по многим другим причинам. Удаление однорангового узла гарантирует сохранение желаемого размера кластера и сохранение кворума.Чтобы удалить узел, вы можете ввести remove-peerкоманду и указать идентификатор узла, который вы хотите удалить:

vault operator raft remove-peer vault3.example.org          

Восстановление кворума

         Данный вариант развертывания имеет свои недостатки, а именно соблюдения кворума в кластере
         Благодаря интегрированному хранилищу Vault обслуживание кворума Raft является важным фактором при настройке и эксплуатации среды Vault. Кворум в кластере Raft теряется безвозвратно, когда нет возможности восстановить достаточное количество узлов для достижения консенсуса и избрания лидера. Без кворума операции чтения и записи не могут выполняться внутри кластера.
  Кворум кластера динамически обновляется, когда к кластеру присоединяются дополнительные серверы. Кворум рассчитывается по формуле (n+1)/2, где n количество серверов в кластере. Например, для кластера с 3 серверами вам потребуется как минимум 2 рабочих сервера, чтобы кластер функционировал должным образом (3+1)/2 = 2. В частности, вам потребуются 2 постоянно активных сервера, чтобы иметь возможность выполнять операции чтения и записи.
         Когда два из трех серверов выходят из строя, кластер теряет кворум и становится неработоспособным.

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

vault operator raft list-peers 
No raft cluster configuration found 
$ vault kv get kv/apikey 
nil response from pre-flight request

       В случае безвозвратной потери двух их трех узлов, есть возможность преобазовать кластер с одним узлом. Для этого необходимо подготовить файл конфигурации.
          Создайте файл peer.json внутри каталога хранилища ./vault/data/raft 
     Чтобы позволить единственному оставшемуся серверу Vault достичь кворума и выбрать себя в качестве лидера, создайте файл raft/peers.json, содержащий информацию о сервере. Файл должен быть отформатирован как массив JSON, содержащий идентификатор узла, адрес: порт и информацию об избирательном праве работоспособного сервера Vault

cat > ./vault/data/raft/peers.json << EOF
[
  {
  "id": "vault1",
  "address": "10.0.0.1:8201",
  "non_voter": false
  } 
]
EOF

id - Указывает идентификатор узла сервера.
address - Указывает хост и порт сервера. Порт — это порт кластера сервера.
non_voter - Это определяет, является ли сервер не голосующим.

         ​Перезапустите процесс Vault, чтобы Vault мог загрузить новый peers.json файл
         После рестарта службы, файла peers.json не будет т.к. он будет загружен в базу RAFT

systemctl restart vault

     ​Процедура восстановления завершается успешно, когда Vault запускается и отображает эти сообщения в системных журналах.

... 
[INFO] core.cluster-listener: serving cluster requests: cluster_listen_address=[::]:8201 
[INFO] storage.raft: raft recovery initiated: recovery_file=peers.json 
[INFO] storage.raft: raft recovery found new config: config="{[{Voter vault1 https://10.0.0.1:8201}]}" 
[INFO] storage.raft: raft recovery deleted peers.json 
...

            Распечатайте хранилище и проверьте список пиров

vault operator raft list-peers 
Node  Address                            State    Voter 
----  -------                          ----- ----- 
vault1 https://10.0.0.1:8201 leader  true

    Потеря кворума восстановлена, преобразовав кластер с 3 серверами в кластер с одним сервером с помощью peers.json. Этот peers.json файл позволял вручную перезаписать список одноранговых узлов Raft на один оставшийся сервер, что позволило этому серверу достичь кворума и завершить выборы лидера. Если отказавшие серверы можно восстановить, лучший вариант — вернуть их в оперативный режим и повторно подключить к кластеру, используя те же адреса хостов. Это вернет кластер в полностью работоспособное состояние. В таком случае raft/peers.json должен содержать идентификатор узла, адрес: порт и информацию об избирательном праве каждого сервера Vault, который вы хотите включить в кластер.

$ cat > /opt/vault/data/raft/peers.json << EOF
[
  {
    "id": "vault1.example.org",
    "address": "10.0.0.1:8201",
    "non_voter": false
  },
  {
    "id": "vault2.example.org",
    "address": "10.0.0.2:8201",
    "non_voter": false
  },
  {
    "id": "vault3.example.org",
    "address": "10.0.0.3:8201",
    "non_voter": false
  }
]
EOF 

            В этом разделе мы настроили кластер из трех узлов и восстановли работоспособность кластера при потере кворума, в следующем разделе мы настроим кластер c хранилищем consul в котором отсутствует необходимость соблюдения кворума.

Развертывание кластера Vault HA with Consul

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

Задержка и пропускная способность сети

     Чтобы члены кластера оставались правильно синхронизированными, задержка сети между зонами доступности должна составлять менее восьми миллисекунд (8 мс). 

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

     Поскольку Vault использует только один активный узел, кластеру Vault состоящего из трех узлов кластера, может выдержать потерю двух узлов или всей зоны доступности

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

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

ПРИМЕЧАНИЕ. ​​​Порты для Consul RPC и трафика сплетен отличаются от портов по умолчанию в этой архитектуре.

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

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

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

     При развертывании элементов кластера Vault и Consul в рекомендуемой архитектуре в трех зонах доступности общая архитектура может выдержать потерю любой отдельной зоны доступности

             В случаях, когда развертывание в трех зонах невозможно, сбой зоны доступности может привести к тому, что кластер Vault станет недоступным или кластер Consul не сможет выбрать лидера. Например, при развертывании с двумя зонами доступности сбой одной зоны доступности может привести к тому, что кластер Consul потеряет свой кворум Raft и не сможет обслуживать запросы с вероятностью 50%. В архитектуре с двумя зонами доступности, можно воспользоваться сторонними сервисами, например Pacemaker + Corosync для обеспечения работы узла кластера в двух зонах доступности одновременно.

Мы произведем настройку Vault HA, состоящую из:
           2 сервера Vault: 1 активный и 1 резервный
           Кластер из 3 серверов Consul

       Подразумевается, что первоначальная установка Consul и Vault уже произведена, если нет воспользуйтесь ссылками ниже:

CONSUL - часть 1 (Установка, базовая настройка)

VAULT - часть 1 (Установка, базовая настройка)

        Для координации высокой доступности и записи в хранилище Consul службе Vault требуется токен Consul ACL

           Создайте политику ACL на кластере Consul:

$   consul acl policy create -name vault-service -rules 'service "vault" { policy = "write" } key_prefix "vault/" {policy = "write"} agent_prefix "" { policy = "read" } session_prefix "" {policy = "write"}'  

           Создайте токен ACL, используя эту политику:

$   consul acl token create -description "Vault Service Token" -policy-name vault-service

     Скопируйте SecretID результат,  полученный на предыдущем шаге, и используйте его в конфигурации хранилища Consul для Vault, описанной ниже

        Чтобы настроить хранилище Consul, используйте следующий раздел конфигурации Vault, используя токен ACL службы Vault, созданный на предыдущем шаге.

vi  /etc/vault.d/vault.hcl
...
storage "consul" {
  address = "http://localhost:8500"
  path = "vault/"
  token = "<VAULT_SERVICE_TOKEN>" 
}

...

          Запускаем службу Vault, и проверяем статус:

$   vault status
Key                      Value
---                      -----
...

Storage Type   consul
...

Кластер Vault HA with Consul готов к использованию