Hashicorp Vault

OIDC аутентификация

В качестве OIDC провайдера можно использовать Keycloak. Там создаем Realm роли и назначаем из пользователю. Также необходимо сделать так, чтобы назначенные роли попали в id_token, который выдается со стороны Keycloak после аутентификации (информация есть здесь https://stackoverflow.com/questions/68741412/grafana-generic-oauth-role-assignment).

Создаем oidc метод доступа (обязательно указываем роль по умолчанию)

# to do

Создаем роль для oidc

vault write auth/oidc/role/default -<<EOF
{
  "allowed_redirect_uris": ["https://vault.example.com/ui/vault/auth/oidc/oidc/callback"],
  "user_claim":"email",
  "groups_claim":"roles",
  "bound_audiences": "vault",
  "oidc_scopes": "openid roles",
  "ttl": "8h"
}
EOF

Команда выше подразумевает, что id_token из Keycloak содержит поле roles с массивом Realm ролей.

Уже можно пробовать зайти через OIDC и получить доступ в объеме default политики.

Допустим уже существует политика admin, которая предоставляет административный доступ к Vault. Чтобы к ней привязаться ролью vault-admin из Keycloak нам потребуется создать т.н. identity/group и identity/group-alias.

Кроме того, нам потребуется получить т.н. mount_accessor для oidc

vault auth list -detailed

Path      Plugin    Accessor
-------     ------       --------
oidc/     oidc        auth_oidc_123    <------------ mount_accessor
...

Создаем identity/group (идентификатор группы пригодится в следующей команде)

vault write identity/group \
    name="vault-admin-group" \
    type="external" \
    policies="admin"

Key     Value
---     -----
id      123123
name    vault-admin-group

Создаем identity/group-alias

vault write identity/group-alias \
    name="vault-admin" \
    mount_accessor="auth_oidc_123" \
    canonical_id="123123"

Здесь значения для mount_accessor и cacnonical_id определяются в командах выше.

В данной конфигурации, пользователю с Realm ролью vault-admin будет назначена политика admin в Vault.

Для добавления новых ролей необходимо выполнить:

  • на стороне Keycloak создаем роль и назначаем ее пользователю
  • на стороне Vault создаем политику для этой роли, а также соответствующие identity/group и identity/group-alias

AppRole

Для интеграции сервисов и инструментов (напр. Ansible) с Vault можно использовать метод доступа AppRole. Суть сводится к созданию политики, роли и секрета на стороне Vault, а на сторону сервиса передается идентификаторы роли и секрета.

Шаг 1 - создаем политику, напр. ansible-policy

path "kv/*" {
  capabilities = ["read"]
}

Шаг 2 - активируем метод доступа и создаем роль (нам потребуется ид-р роли)

vault auth enable approle
vault write auth/approle/role/ansible token_policies="ansible-policy"
vault read auth/approle/role/ansible/role-id
# Key        Value
# ---        -----
# role_id    39aef9d2-...

Шаг 3 - создаем секрет

vault write -f auth/approle/role/ansible/secret-id
# Key                   Value
# ---                   -----
# secret_id             469f6928-...

Шаг 4 - авторизуемся на клиенте с использованием role_id и secret_id

# --- получаем токен
vault write auth/approle/login \
    role_id="39aef9d2-..." \
    secret_id="469f6928-..."
# Key                     Value
# ---                     -----
# token                   hvs.CAESIO...

Используем токен для работы

JWT и Gitlab CI

Секреты можно забирать из Vault при выполнении линии сборки Gitlab CI через механизм JWT. Пример конфигурации:

Активируем метод доступа

vault auth enable jwt

Конфигурация метода доступа

vault write auth/jwt/config -<<EOF
{
  "jwks_url": "https://gitlab.example.com/oauth/discovery/keys",
  "bound_issuer": "https://gitlab.example.com"
}
EOF

Создаем роль для метода доступа

vault write auth/jwt/role/ci-backend - <<EOF
{
  "role_type": "jwt",
  "policies": ["some-policy"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_audiences": ["https://vault.example.com"],
  "bound_claims": {
    "project_path": "project/path"
  }
}
EOF

Конфигурация джобы в .gitlab-ci.yml

test_vault:
  stage: test
  image:
    name: hashicorp/vault:1.19
  id_tokens:
    JWT:
      aud: https://vault.example.com
  script:
    - export VAULT_ADDR=https://vault.example.com
    - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=ci-backend jwt=$JWT)"
    - export MY_SECRET="$(vault kv get -field=my_secret kv/test/app)"
    - echo $MY_SECRET