Введение


Когда я устанавливаю Vault в Kubernetes, я держу в голове, что очень важно иметь возможность сделать автоматическое распечатывание(Auto-Unseal), чтобы кластер Vault был по настоящему высокодоступным.


В моей предыдущей статье "Highly available Vault cluster in Kubernetes" (ссылка), несмотря на то, что я изо всех сил пытался сделать кластер Vault максимально доступным, без автоматического распечатывания кластер Vault мог бы выдержать частичный отказ подов, но не пережил бы перезагрузку всего кластера.


В этой статье хорошо объяснено, почему это произошло. Для меня проблема заключается в том, что я не пользуюсь "службой AWS KMS", которую можно было бы использовать, или подобной службы безопасности от "облачного" провайдера, потому что я управляю Kubernetes на self-hosted "облаке" (в этой статье объясняется моя настройка).


В Vault версии 1.1 добавлена поддержка "Transit Auto Unseal", которая заключается в использовании второго Vault кластера B для автоматического распечатывания (Auto-Unseal) кластера А.


Итак, вот идея: развернуть 2 кластера Vault A и B и настроить их так, чтобы они делали автоматическое распечатывание друг для друга.


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


В этой статье я развернул два кластера Vault в одном Kubernetes, и назвал их "vault" и "vault-unlock", в двух неймспейсах. В реальной продакшн-среде я бы предложил более надежный способ их установки в двух кластерах Kubernetes.


Ниже приведена диаграмма.



Обновлено 1/9/2020


Vault использует "Consul Cluster" в качестве бэк-энд хранилища. В этой статье я поделился своим недавним опытом использования Consul в Kubernetes для боевой среды, чтобы сделать его безопасным/стабильным.

Исходники, использованные в этой статье


github link

Полезно ознакомиться перед началом


  • Высокодоступный кластер Kubernetes (пример)

Развёртывание двух Vault кластеров


Первый кластер называется "vault", в папке с исходным кодом "vault".
Этот кластер предназначен для внешнего обслуживания, поэтому у него есть правило Ingress.


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


Второй кластер называется "vault-unlock", в папке с исходным кодом "vault2".
Этот кластер предназначен для осуществления автоматического распечатывания(Auto-Unseal).


Для его развертывания надо сделать то же, что и для первого кластера, только в пространстве имён "vault-unlock", и без Ingress.


Проверьте файлы README.md в исходниках на наличие нижеприведенных команд.


# create namespace
$ kubectl apply -f vault2/vault_namespace.yml
# go to ca folder
$ cd ca
# create certs
$ cfssl gencert \
    -ca=ca.pem \
    -ca-key=ca-key.pem \
    -config=config/ca-config.json \
    -profile=default \
    config/vault-unlock-csr.json | cfssljson -bare vault-unlock
# it's important to use the same GOSSIP_ENCRYPTION_KEY as first cluster
$ kubectl -n vault-unlock create secret generic vault \
    --from-literal="gossip-encryption-key=${GOSSIP_ENCRYPTION_KEY}" \
    --from-file=ca.pem \
    --from-file=vault-unlock.pem \
    --from-file=vault-unlock-key.pem \
    --from-file=vault-client.pem \
    --from-file=vault-client-key.pem
# go to vault2 folder
$ cd vault2
$ kubectl -n vault-unlock create configmap vault --from-file=config/vault.json
# now deploy
$ kubectl apply -f .
# init and unseal
$ vault operator init
$ vault operator unseal
$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         1.1.3
Cluster Name    vault-cluster-98e11b27
Cluster ID      3804aaeb-8f62-ca79-4e34-f2cad7dfd062
HA Enabled      true
HA Cluster      https://10.0.210.129:8201
HA Mode         active

Когда всё развернуто, пользовательский интерфейс Consul будет выглядеть так.





Пользовательский интерфейс Vault доступен через публичный адрес.



Первая часть — Использовать кластер «vault” для автоматического распечатывания кластера „vault-unlock”


Я следую инструкциям из официального документа.


Исходное состояние


"vault” кластер полностью распечатан и работает


Операции в кластере “vault”


# connect to "vault" cluster
$ kubectl -n vault port-forward svc/vault 8200 &
# below commands need root token
$ vault login
Token (will be hidden):
# enable audit, logs into container console 
$ vault audit enable file file_path=stdout
Success! Enabled the file audit device at: file/
# enable transit engine
$ vault secrets enable transit
# create key "autounseal"
$ vault write -f transit/keys/autounseal
Success! Data written to: transit/keys/autounseal
# create autounseal policy, content from official doc
$ vault policy write autounseal autounseal.hcl
Success! Uploaded policy: autounseal
# create a token with the policy, it's wrapped in wrapping_token
$ vault token create -policy="autounseal" -wrap-ttl=120
Key                              Value
---                              -----
wrapping_token:                  s.AO55UYmKpT4TmPVn2AZ0UkNT
wrapping_accessor:               7N3PtIwhuAtjJZ2GvA9RM0iV
wrapping_token_ttl:              2m
wrapping_token_creation_time:    2019-06-25 19:24:46.345501602 +0000 UTC
wrapping_token_creation_path:    auth/token/create
wrapped_accessor:                B8kWfoLfXYOAxFI2P2TIduaI
# get the token from wrapping_token
# as previous command shows, the wrapping_token is only valid for 120 seconds
$ VAULT_TOKEN="s.AO55UYmKpT4TmPVn2AZ0UkNT" vault unwrap
Key                  Value
---                  -----
token                s.LvLFn4InVdIorAFS5E9j6xd3
token_accessor       KST0fJN4xMd2Yaztrmya8SNx
token_duration       768h
token_renewable      true
token_policies       ["autounseal" "default"]
identity_policies    []
policies             ["autounseal" "default"]
# this is the token to be used in next step
token                s.LvLFn4InVdIorAFS5E9j6xd3

Операции в кластере „vault-unlock”


Скопируйте файл "vault2/config/vault.json” из исходников, назовите его "vault2/config/vault_autounseal.json”, и добавьте конфигурацию "seal".


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


"seal": {
    "transit": {
      "address": "https://vault.vault.svc.cluster.local:8200",
      "token": "this_is_token_to_access_vault",
      "disable_renewal":"false",
      "key_name": "autounseal",
      "mount_path": "transit/",
      "tls_skip_verify": "false",
      "tls_server_name": "vault",
      "tls_ca_file": "/etc/tls/ca.pem",
      "tls_client_cert": "/etc/tls/vault-unlock.pem",
      "tls_client_key": "/etc/tls/vault-unlock-key.pem"
    }
  },

Обновим конфигмап "vault" с содержимым из файла "vault_autounseal.json", но назовем его "vault.json”, чтобы под мог его использовать".


kubectl -n vault-unlock create configmap vault --from-file=vault.json=config/vault_autounseal.json -o yaml --dry-run | kubectl replace -f -

Пересоздаем деплоймент vault-unlock. Лог с параметрами для автоматического распечатывания выглядит следующим образом:


# Do below in source code vault2/
$ kubectl delete -f vault_deployment.yml
$ kubectl apply -f vault_deployment.yml
$ kubectl -n vault-unlock logs -f vault-544d44df85-6pmvf -c
 vault
==> Vault server configuration:
Seal Type: transit
         Transit Address: https://vault.vault.svc.cluster.local:8200
        Transit Key Name: autounseal
      Transit Mount Path: transit/
             Api Address: https://vault.vault-unlock.svc.cluster.local:8200
                     Cgo: disabled
         Cluster Address: https://10.0.181.115:8201
              Listener 1: tcp (addr: "[::]:8200", cluster address: "[::]:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "enabled")
               Log Level: info
                   Mlock: supported: true, enabled: true
                 Storage: consul (HA available)
                 Version: Vault v1.1.3
             Version Sha: 9bc820f700f83a7c4bcab54c5323735a581b34eb
2019-06-25T19:51:54.065Z [WARN]  core: entering seal migration mode; Vault will not automatically unseal even if using an autoseal: from_barrier_type=shamir to_barrier_type=transit
==> Vault server started! Log data will stream in below:

Теперь кластер "vault-unlock” находится в режиме "seal migration mode”.


Делаем миграцию запечатывания (Seal)


# connect to "vault-unlock" cluster
$ kubectl -n vault-unlock port-forward vault-544d44df85-6pmvf 8200 &
# below means seal migration in progress
$ vault status
Key                           Value
---                           -----
Recovery Seal Type            shamir
Initialized                   true
Sealed                        true
Total Recovery Shares         5
Threshold                     3
Unseal Progress               0/3
Unseal Nonce                  n/a
Seal Migration in Progress    true
Version                       1.1.3
HA Enabled                    true
# do seal migration
$ vault operator unseal -migrate
Unseal Key (will be hidden):
# Repeat until unsealed
$ vault status
Key                      Value
---                      -----
Recovery Seal Type       shamir
Initialized              true
Sealed                   false
Total Recovery Shares    5
Threshold                3
Version                  1.1.3
Cluster Name             vault-cluster-c6f60ee0
Cluster ID               a152257b-813d-9eb3-57ea-f7d0683f0b1c
HA Enabled               true
HA Cluster               https://10.0.181.115:8201
HA Mode                  active

Миграцию запечатывания необходимо сделать только в одном поде "vault-unlock” кластера.


Теперь перезапускаем "vault-unlock” кластер ещё раз. Все поды кластера "vault-unlock” станут автоматически распечатанными. Лог будет выглядеть вот так:


# Do below in source code vault2/
$ kubectl delete -f vault_deployment.yml
$ kubectl apply -f vault_deployment.yml
$ kubectl -n vault-unlock logs -f vault-544d44df85-7877s -c
 vault
==> Vault server configuration:
Seal Type: transit
         Transit Address: https://vault.vault.svc.cluster.local:8200
        Transit Key Name: autounseal
      Transit Mount Path: transit/
             Api Address: https://vault.vault-unlock.svc.cluster.local:8200
                     Cgo: disabled
         Cluster Address: https://10.0.181.70:8201
              Listener 1: tcp (addr: "[::]:8200", cluster address: "[::]:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "enabled")
               Log Level: info
                   Mlock: supported: true, enabled: true
                 Storage: consul (HA available)
                 Version: Vault v1.1.3
             Version Sha: 9bc820f700f83a7c4bcab54c5323735a581b34eb
==> Vault server started! Log data will stream in below:
2019-06-25T20:01:28.680Z [INFO]  core: stored unseal keys supported, attempting fetch
2019-06-25T20:01:28.702Z [INFO]  core: vault is unsealed
2019-06-25T20:01:28.702Z [INFO]  core.cluster-listener: starting listener: listener_address=[::]:8201
2019-06-25T20:01:28.702Z [INFO]  core.cluster-listener: serving cluster requests: cluster_listen_address=[::]:8201
2019-06-25T20:01:28.703Z [INFO]  core: entering standby mode
2019-06-25T20:01:28.706Z [INFO]  core: unsealed with stored keys: stored_keys_used=1
2019-06-25T20:01:28.736Z [INFO]  core: acquired lock, enabling active operation
2019-06-25T20:01:28.781Z [INFO]  core: post-unseal setup starting
2019-06-25T20:01:28.784Z [INFO]  core: loaded wrapping token key
2019-06-25T20:01:28.784Z [INFO]  core: successfully setup plugin catalog: plugin-directory=
2019-06-25T20:01:28.788Z [INFO]  core: successfully mounted backend: type=system path=sys/
2019-06-25T20:01:28.788Z [INFO]  core: successfully mounted backend: type=identity path=identity/
2019-06-25T20:01:28.789Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
2019-06-25T20:01:28.811Z [INFO]  core: successfully enabled credential backend: type=token path=token/
2019-06-25T20:01:28.811Z [INFO]  core: restoring leases
2019-06-25T20:01:28.811Z [INFO]  rollback: starting rollback manager
2019-06-25T20:01:28.813Z [INFO]  expiration: lease restore complete
2019-06-25T20:01:28.816Z [INFO]  identity: entities restored
2019-06-25T20:01:28.821Z [INFO]  identity: groups restored
2019-06-25T20:01:28.822Z [INFO]  core: post-unseal setup complete

Итак, у кластера "vault-unlock” появилась возможность автоматического распечатывания.


Вторая часть — Использование кластера “vault-unlock” для автоматического распечатывания кластера „vault”


В основном, это то же самое, что и в первой части.


Просто держите в уме, с каким кластером работаете в данный момент… Особенно на этапе "пересоздания" деплоймента, убедитесь, что папка с исходниками верна.


Я бы посоветовал создавать резервные копии кластера "Consul" по ходу выполнения шагов. Согласно доке.


Готово?


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


Устраняем проблемы:


  • ошибка при попытке сделать "seal migration”

$ vault operator unseal -migrate
Unseal Key (will be hidden):
Error unsealing: Error making API request.
URL: PUT https://127.0.0.1:8200/v1/sys/unseal
Code: 400. Errors:
* 'migrate' parameter set true in JSON body when not in seal migration mode

Это происходит из-за того, что Configmap vault всё ещё содержит конфиг из файла "config/vault.json”. Обновите его содержимым файла "config/vault_autounseal.json”.


  • Ошибка включения транзитного seal "client tls verify”

# vault container could not start
$ kubectl -n vault-unlock get pod
NAME                     READY   STATUS    RESTARTS   AGE
vault-6d5fff8bd8-6d5dr   1/2     Error     1          12s
vault-6d5fff8bd8-cmfjt   1/2     Error     1          12s
vault-6d5fff8bd8-kzn9l   1/2     Running   1          12s
$ kubectl -n vault-unlock logs -f vault-6d5fff8bd8-6d5dr -c vaul
t
Error parsing Seal configuration: Put https://vault.vault.svc.cluster.local:8200/v1/transit/encrypt/autounseal: x509: certificate signed by unknown authority

Эта проблема долгое время доставляла мне неприятности… даже после того, как я поверил, что правильно настроил все параметры для конфигурации "seal".


Легко заставить всё работать, установив "tls_skip_verify" как "true", и в данном случае это может быть нормально, так как здесь оба кластера Vault находятся внутри одного и того же кластера Kubernetes.


Однако, в случае двух кластеров Vault в двух разных кластерах Kubernetes, проверка TLS должна быть выполнена.


     "tls_skip_verify": "false",
      "tls_server_name": "vault",
      "tls_ca_file": "/etc/tls/ca.pem",
      "tls_client_cert": "/etc/tls/vault-unlock.pem",
      "tls_client_key": "/etc/tls/vault-unlock-key.pem"

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

        env:
          - name: VAULT_CACERT
            value: "/etc/tls/ca.pem"

Тест для самоуспокоения


Итак, 2 кластера Vault теперь делают автоматическое распечатывание друг за другом. Цель — получить высокодоступный Vault в качестве сервиса.


С точки зрения пользователя, я настраиваю тест, чтобы проверять состояние Vault каждую секунду с помощью statping, как показано ниже. Он проверяет состояние Vault из Интернета на контроллере Ingress от Kubernetes, а затем на кластере Vault.


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



  • Плавающее обновление деплоймента

Как описано в этой статье, выпуск vault’a объединяет "RollingUpdate”, "livenessProbe”, "readinessProbe”, "lifecycle-preStop”, и "PodDisruptionBudget”. Во время обновления происходит подтверждение, что только один из трех подов был завершен и вновь созданный под должен получить состояние распечатанного для следующего обновления.


Во всех обновленях в деплойменте vault’a, которые я проводил за время написания этой статьи, не было обнаружено ни одной ошибки.


  • Прямая перезагрузка хоста

Во время написания этой статьи, мой облачный провайдер временно отключил одну хост-машину на обслуживание. Для двух серверов, на одном из которых был haproxy, а на другом — мастер-нода с Ingress Controller’ом, падение заняло 20 минут. В этом случае statping зафиксировал 4 ошибки.


  • Полная перезагрузка кластера Kubernetes

Чтобы протестировать сценарий перезапуска обслуживания, я использую метод, описанный в этой статье. Я последовательно перезагружаю все ноды кластера Kubernetes, например:


192.168.3.122 haproxy1.example.com haproxy1
192.168.2.17 haproxy2.example.com haproxy2
192.168.4.114 master1.example.com master1
192.168.5.58 master2.example.com master2
192.168.1.203 master3.example.com master3
192.168.3.72 worker1.example.com worker1
192.168.5.67 worker2.example.com worker2
192.168.7.180 worker3.example.com worker3

Для каждой ноды сначала удалим поды, затем перезагружаем, дожидаемся, пока все вернется на место, и, наконец, "развяжем” ноду.


В этом тесте statping зафиксировал около 50 ошибок, по 2-6 за один цикл перезагрузки. У меня ушло очень много времени для поиска решения. Я пытался использовать методы из этой статьи, но данный способ не помог. Обсуждение по ссылке объясняет, почему Vault не создан для нулевого простоя. Когда активная Vault-нода падает, проходит некоторое время, прежде чем резервная перенимает контроль на себя.


Поэтому в исходном коде я сделал лучшее, что мог: 6 секунд задержки для vault контейнера, и 6 секунд задержки, а затем вызов "consul leave” для consul-vault-agent. Дайте мне знать, если здесь есть возможность внести улучшения.


# container vault
        lifecycle:
          preStop:
            exec:
              command: [
                "sh", "-c",
                # Introduce a delay to the shutdown sequence to wait for the
                # pod eviction event to propagate.
                "sleep 6",
              ]
...
# container consul-vault-agent
        lifecycle:
          preStop:
            exec:
              command: [
                "sh", "-c",
                # shutdown vault first, then shutdown consul agent
                "sleep 6 && consul leave"
              ]

Обновлено 1/31/2020

Хочется заметить, что доступность Vault’a значительно улучшается после подключения высокодоступного Consul Cluster. Подробнее читайте в этой статье.

В последние два раза, когда я перезагружал кластер (подробнее тут: "полную перезагрузку кластера”) statping обнаружил 0 и 1 ошибок, соответственно.

Наихудший случай – Dead lock


Что случится, если оба Vault кластера умрут в одно и то же время?
Я сталкивался с таким случаем лишь однажды, когда я случайно уничтожил деплоймент Consul. Несмотря на то, что я смог вернуть Consul обратно без потери данных, оба Vault кластера были недоступны для распечатывания.




Обновление: я нашел еще один случай, который также наверняка отключит Vault кластер. Так как Vault зависит от Consul, как от хранилища бэкенда, если Consul кластер упадет, например, если он попадет в такое состояние, что не будет существовать ведущего, Vault кластер перейдет в состояние "Все Запечатано”.


Поэтому важно убедиться, что Consul кластер будет высокодоступным. Я обновил consul_statefulset.yml, чтобы добавить livenessProbe. Когда Consul кластер нуждается в плавающем обновлении, я вижу, что у Consul и Vault кластеров все в порядке.


Кроме того, если произойдет одновременная перезагрузка серверов с worker-нодами, Vault кластер попадет в состояние dead lock’a. Поэтому такой ситуации стоит избегать.




К сожалению, я не смог найти способ для восстановления, когда оба кластера остаются навсегда в состоянии Sealed… Хочу надеяться, что в этом случае Vault может быть распечатанным со всеми ключами восстановления, но не уверен, что это возможно(соответствующий пост по ссылке).


$ kubectl get pod --all-namespaces -l app=vault
NAMESPACE      NAME                            READY   STATUS    RESTARTS   AGE
vault-unlock   vault-unlock-5fc9c7cdd7-22cl4   1/2     Running   10         5h6m
vault-unlock   vault-unlock-5fc9c7cdd7-pclv8   1/2     Running   11         38h
vault-unlock   vault-unlock-5fc9c7cdd7-v6pvx   1/2     Running   11         38h
vault          vault-5fc9c7cdd7-62qb6          1/2     Running   11         38h
vault          vault-5fc9c7cdd7-gnfdj          1/2     Running   10         5h6m
vault          vault-5fc9c7cdd7-nb8n7          1/2     Running   11         38h

Так что в этот раз у меня не было другого выбора, кроме как пересобрать оба Vault кластера.


Решение для восстановления из dead lock’a



Как восстановиться из dead lock’a, который, вроде бы, происходит редко, но, тем не менее, возможен в теории? Да и происходит он обычно из-за человеческой оплошности.


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


Моя идея заключается, как показывает диаграмма, в том, чтобы создать кластер Vault с "Ручным распечатыванием” во втором кластере Kubernetes. Этот кластер "Vault” содержит то самое, что и кластер "Vault-Unlock”, но в то же время он находится в режиме "Ручного распечатывания”.


Высокоуровневые шаги:


Главный кластер Kubernetes


  1. Инициализировать кластер "Consul”;
  2. Инициализировать” кластер "Vault;
  3. Инициализировать кластер "Vault-Unlock”;
  4. Переключить кластер "Vault” в режим автоматического распечатывания при помощи кластера "Vault-Unlock”.

Вспомогательный кластер Kubernetes


  1. Создать кластер "Consul-back”;
  2. Создать снапшот главного кластера "Consul” и восстановить "Consul-back”. Сохранить только "Vault-Unlock” K/V директорию;
  3. Создать кластер "Vault-Unlock”, как и содержимое в "Vault-Unlock” в главном кластере, оно должно быть распечатанным с те ми же самыми ключами распечатывания;
  4. Держать "Vault-Unlock” во вспомогательном Kubernetes в режиме "Ручного Распечатывания”, таким образом, он может быть распечатан вручную, и он содержит бэкап транзитного ключа для распечатывания "Vault” в главном кластере.


Главный кластер Kubernetes


  1. Переключить "Vault-Unlock” в режим "Автоматического распечатывания” при помощи кластера "Vault”.

В случае dead lock’a


  1. Убедиться, что кластер "Vault-Unlock” во вспомогательном кластере Kubernetes доступен и находится в распечатанном состоянии;
  2. Удалить деплоймент "Vault” из главного кластера Kubernetes, переключиться на "Экстренное распечатывание” при помощи "Vault-Unlock” во вспомогательном Kubernetes кластере;

kubectl -n vault create configmap vault --from-file=vault.json=config/vault_emergency.json -o yaml --dry-run | kubectl replace -f -

  1. После того, как кластер "Vault” перейдет в состояние распечатанного, пересоздайте кластер "Vault-Unlock” в главном Kubernetes;
  2. Переключите кластер "Vault” для использования "Vault-Unlock” в главном Kubernetes как "Автоматическое Распечатывание”.

kubectl -n vault create configmap vault --from-file=vault.json=config/vault_autounseal.json -o yaml --dry-run | kubectl replace -f -

Todo: разобраться, как настроить TLS коммуникацию между главным "Vault” кластером Kubernetes и вспомогательным "Vault-Unlock” кластером. На текущий момент TLS верификация пропущена.


Обновлено: Оказывается, настроить TLS верификацию очень легко. Так как Kubernetes helper предоставляет Vault сервис через Trafik Ingress по https://vault.backup.example.com, он использует сертификат Let’s Encrypt.


Просто закомментируйте две строчки из vault_deployment.yml в "Vault” кластере:


          #- name: VAULT_CACERT
          #  value: "/etc/tls/ca.pem"

Логи:


$ kubectl -n vault logs -f vault-6df998bb7c-5q7g8 -c vault
==> Vault server configuration:
Seal Type: transit
         Transit Address: https://vault.backup.example.com
        Transit Key Name: autounseal
      Transit Mount Path: transit/
             Api Address: https://vault.vault.svc.cluster.local:8200
                     Cgo: disabled
         Cluster Address: https://10.0.181.79:8201
              Listener 1: tcp (addr: "[::]:8200", cluster address: "[::]:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "enabled")
               Log Level: INFO
                   Mlock: supported: true, enabled: true
                 Storage: consul (HA available)
                 Version: Vault v1.1.3
             Version Sha: 9bc820f700f83a7c4bcab54c5323735a581b34eb
==> Vault server started! Log data will stream in below:
2019-07-03T04:38:10.435Z [INFO]  core: stored unseal keys supported, attempting fetch
2019-07-03T04:38:10.466Z [INFO]  core: vault is unsealed
2019-07-03T04:38:10.466Z [INFO]  core.cluster-listener: starting listener: listener_address=[::]:8201
2019-07-03T04:38:10.466Z [INFO]  core.cluster-listener: serving cluster requests: cluster_listen_address=[::]:8201
2019-07-03T04:38:10.466Z [INFO]  core: entering standby mode
2019-07-03T04:38:10.469Z [INFO]  core: unsealed with stored keys: stored_keys_used=1

Обновление токена Автоматического Распечатывания


Спустя месяц, я обнаружил, что автоматическое распечатывание не работает. Я получил "403 permission denied”, когда пытался совершить распечатывание между Vault’ами.


Это произошло из-за того, что мы рассчитывали на токен с политикой "Автоматического Распечатывания”, чтобы выполнить работу. Помните, в шагах выше:


# create a token with the policy, it's wrapped in wrapping_token
$ vault token create -policy="autounseal" -wrap-ttl=120
Key                              Value
---                              -----
wrapping_token:                  s.AO55UYmKpT4TmPVn2AZ0UkNT
wrapping_accessor:               7N3PtIwhuAtjJZ2GvA9RM0iV
wrapping_token_ttl:              2m
wrapping_token_creation_time:    2019-06-25 19:24:46.345501602 +0000 UTC
wrapping_token_creation_path:    auth/token/create
wrapped_accessor:                B8kWfoLfXYOAxFI2P2TIduaI
# get the token from wrapping_token
# as previous command shows, the wrapping_token is only valid for 120 seconds
$ VAULT_TOKEN="s.AO55UYmKpT4TmPVn2AZ0UkNT" vault unwrap
Key                  Value
---                  -----
token                s.LvLFn4InVdIorAFS5E9j6xd3
token_accessor       KST0fJN4xMd2Yaztrmya8SNx
token_duration       768h
token_renewable      true
token_policies       ["autounseal" "default"]
identity_policies    []
policies             ["autounseal" "default"]
# this is the token to be used in next step
token                s.LvLFn4InVdIorAFS5E9j6xd3

Токен для выполнения автоматического распечатывания истечет после 768 часов, что приблизительно равно 32 дням. Так как мы используем токен в конфигмапе (vault_autounseal.json), становится невозможным удаленно подключиться после истечения срока токена.


В "vault_autounseal.json” даже если "disable_renewal” определен как "false”, токен все равно истекает. В моем понимании "renew” не происходит, если токен не был использован в течении всех 32-х дней, например, если за все время автоматическое распечатывание так и не произошло.


"seal": {
    "transit": {
      "address": "https://vault.vault-unlock.svc.cluster.local:8200",
      "token": "this_is_token_to_access_vault-unlock",
      "disable_renewal":"false",

Чтобы решить эту проблему, должно быть несколько действий:


  • Увеличить TTL
  • Периодически обновлять
  • Периодически перегенерировать токен и обновлять конфигмап

Подводя итог


В этой статье я описал мою попытку создания высокодоступного Vault сервиса. Чтобы достичь цели, я установил 2 кластера Vault для взаимного автоматического распечатывания. Один из них обеспечивал Vault сервис для пользователей, а другой был скрыт и выполнял "Unlock” работу. Чтобы избежать Dead Lock’а, который мог произойти в экстренных ситуациях, третий Vault кластер был в роли бэкапа для "Unlock” Vault’a.


Все исходники доступны в github.


Ссылки:


Auto-unseal using Transit Secrets Engine
transit Seal configurations
vault Server configurations
tcp Listener configurations

Комментарии (1)


  1. arren
    20.09.2021 07:31
    +4

    Статья устарела, особенно в части про Consul в качестве хранилища.

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