~/
~/

Содержание

Vault auto unseal (transit engine) Yandex Cloud

В этой статье мы настроим автоматический unseal “боевого” кластера с ипользованием промежуточного волта в реалиях Yandex Cloud

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

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

image

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

Important

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

Мы будем использовать transit engine, как это работает:

  • Будем использовать два кластера волта
  • Первый будет использоваться только для распечатывания второго (боевого), сам по себе он будет распечатываться с помощью Yandex KMS
  • Второй кластер боевой, который вы используете в проде (обновляя и конфигурируя его по своему усмотрению, без зависимости от Yandex Cloud)

image

Unwrap кластер ипользуется для распечатывания боевого кластера, а сам распечатывается средствами Яндекса

yc iam service-account create --name vault-unwrap-sa
yc iam key create \
   --service-account-name vault-unwrap-sa \
   --output key.json

yc kms symmetric-key create \
   --name vault-unwrap \
   --default-algorithm aes-256 \
   --deletion-protection \
   --description "Ключ для vault-unwrap разворачивающего основной vault в prod"

# Сохраните идентификатор ключа (id) — он понадобится при установке приложения.

yc kms symmetric-key add-access-binding \
   --name prod-vault-unwrap \
   --service-account-name prod-vault-unwrap-sa \
   --role kms.keys.encrypterDecrypter

Используем image от Yandex Cloud, что бы корректно работал KMS

  image:
    repository: "cr.yandex/yc/vault"
    tag: "1.11.5_yckms"
    pullPolicy: IfNotPresent

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

При выборе PostgreSQL в качестве бекенда, таблички не будут созданы автоматически, создать их можно в ручную

CREATE TABLE vault_kv_store (
  parent_path TEXT COLLATE "C" NOT NULL,
  path        TEXT COLLATE "C",
  key         TEXT COLLATE "C",
  value       BYTEA,
  CONSTRAINT pkey PRIMARY KEY (path, key)
);

CREATE INDEX parent_path_idx ON vault_kv_store (parent_path);

Табличка для HA мода

CREATE TABLE vault_ha_locks (
  ha_key                                      TEXT COLLATE "C" NOT NULL,
  ha_identity                                 TEXT COLLATE "C" NOT NULL,
  ha_value                                    TEXT COLLATE "C",
  valid_until                                 TIMESTAMP WITH TIME ZONE NOT NULL,
  CONSTRAINT ha_key PRIMARY KEY (ha_key)
); 

Если используется PostgreSQL до 9.5, создайте функцию

CREATE FUNCTION vault_kv_put(_parent_path TEXT, _path TEXT, _key TEXT, _value BYTEA) RETURNS VOID AS
$$
BEGIN
    LOOP
        -- first try to update the key
        UPDATE vault_kv_store
          SET (parent_path, path, key, value) = (_parent_path, _path, _key, _value)
          WHERE _path = path AND key = _key;
        IF found THEN
            RETURN;
        END IF;
        -- not there, so try to insert the key
        -- if someone else inserts the same key concurrently,
        -- we could get a unique-key failure
        BEGIN
            INSERT INTO vault_kv_store (parent_path, path, key, value)
              VALUES (_parent_path, _path, _key, _value);
            RETURN;
        EXCEPTION WHEN unique_violation THEN
            -- Do nothing, and loop to try the UPDATE again.
        END;
    END LOOP;
END;
$$
LANGUAGE plpgsql;
  extraconfig-from-values.hcl: |-
    disable_mlock = true
    ui = true

    listener "tcp" {
      tls_disable = 1
      address = "[::]:8200"
      cluster_address = "[::]:8201"
    }

    storage "postgresql" {
      connection_url = "postgres://<USER>:<PASSWORD>@<HOSTS>:6432/vault?sslmode=require"
      table = "vault_kv_store"
      ha_enabled = true
      ha_table = "vault_ha_locks"
      tls_ca_file = "/etc/ssl/certs/ca-yandex.pem"
    }

    seal "yandexcloudkms" {
      kms_key_id = ""
      service_account_key_file = "/vault/ssl/key.json"
    }
Important

tls_ca_file - публичный сертификат для подлючения к managed сервисам с SSL
kms_key_id - id ключа который мы получили в первом шаге
service_account_key_file - получаем при создании аккаунта в первом шаге

Для инициализации достаточно запустить vault operator init в любом поде, если все настроенно верно, вывод будет следующий

Recovery Key 1: iz1XWxe4CM+wrOGqRCx8ex8kB2XvGJEdfjhXFC+MA6Rc
Recovery Key 2: rKZETr6IAy686IxfO3ZBKXPDAOkkwkpSepIME+bjeUT7
Recovery Key 3: 4XA/KJqFOm+jzbBkKQuRVePEYPrQe3H3TmFVmdlUjRFv
Recovery Key 4: lfnaYoZufP0uhooO3mHDAKGNZB5HLP9HYYb+LAfKkUmd
Recovery Key 5: L169hHj3DMpphGsOnS8TEz3Febvdx3vsG3Xr8kGWdUtW

Initial Root Token: s.AWnDagUkKNNbvkENiL72wysn

Success! Vault is initialized

Recovery key initialized with 5 key shares and a key threshold of 3. Please
securely distribute the key shares printed above.

Для автоматического распечатывания, первый раз кластер нужно распечатать вручную vault operator unseal <key> Вводим 3 ключа, кластер будет распечатан Теперь при падении подов кластер будет распечатываться автоматически

Note

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

  • Включаем transit
vault secrets enable transit
  • Создаем ключ шифрования
vault write -f transit/keys/autounseal
  • Создаем полиси
vault policy write autounseal -<<EOF
path "transit/encrypt/autounseal" {
   capabilities = [ "update" ]
}

path "transit/decrypt/autounseal" {
   capabilities = [ "update" ]
}
EOF

Если все сделанно правильно вывод должен быть следующим

Success! Uploaded policy: autounseal
  • Создаем orphan periodic токен с политикой autounseal и TTL 120 сек, использовать его мы будем когда будет готов боевой прод волт, поэтому создать его можно и позже

#Логинимся 
$ vault login
#Генерим токен в соответствии с политикой
$ vault token create -policy="autounseal" -wrap-ttl=120 -orphan -period=30m

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

#Получаем токен для распечатывания
$ VAULT_TOKEN="s.AO55UYmKpT4TmPVn2AZ0UkNT" vault unwrap

Key                  Value
---                  -----
token                s.LvLFn4InVdIorAFS5E9j6xd3
......

Все точно так же как для unwrap кластера, только в другой неймспейс

Все точно так же как для unwrap кластера

Здесь все тоже без изменений, так же как для unwrap

seal "transit" {
  address = "http://vault.vault-unwrap-system:8200"
  token = "s.LvLFn4InVdIorAFS5E9j6xd3"
  disable_renewal = "false"
  key_name = "autounseal"
  mount_path = "transit/"
  tls_skip_verify = "true"
  }

Если все сделано правильно волт перейдет в режим миграции ( это видно в логах )

core: entering seal migration mode; Vault will not automatically unseal even if using an autoseal: from_barrier_type=shamir to_barrier_type=transit

Распечатываем волт в режиме миграции ( достаточно проделать это с одним подом )

vault operator unseal -migrate <key>

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

Note

Таким образом unwrap vault распечатывается с помощью Яндекс kms, а боевой с помощью vault unwrap
Проверяем - убиваем под в промежуточном и основном вольте и проверяем что они автоматически распечатались.

Если по какой-то причине боевой волт не может достучаться до unwrap волта в течении 30 минут, токен не будет обновлен и волт упадет с ошибкой

  | Error making API request.
  |
  | URL: PUT http://vault.vault-unwrap-system:8200/v1/auth/token/renew-self
  | Code: 403. Errors:
  |
  | * permission denied

Время в 30 минут устанавливается здесь:

vault token create -policy="autounseal" -wrap-ttl=120 -orphan -period=30m

В таком случае необходимо обновить токен в unwrap волте и подложить его в конфигмап боевого волта, либо увеличить -period до удобного вам значения.