Аутентификация и чтение секретов в Vault через Gitflic CI

Функционал доступен в Enterprise версии


Введение

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

Предусловия

Для работы с Vault необходимо иметь

  • аккаунт на GitFlic
  • доступ к работающему серверу Vault (версии 1.2.0 и выше) для настройки аутентификации, а также для создания ролей и политик

Работа с Vault

JSON Web Tokens (JWTs) используется для OIDC аутентификации со сторонними службами. Если для задачи определен хотя бы один JWTs, то секрет автоматически использует этот токен для аутентификации в Vault.

В JWTs включены следующие параметры:

Параметр Наличие Описание
iss Обязательно Домен сервиса gitflic
project_visibility Обязательно Приватность проекта
ref_name Обязательно Имя ветки
commit_sha Обязательно Хеш коммита
project_path Обязательно Путь проекта
project_name Обязательно Псевдоним проекта
project_title Обязательно Название проекта
pipeline_source Обязательно Источник конвейера
pipeline_id Обязательно ID конвейера
sub Обязательно ID задачи
user_login Обязательно Имя пользователя, запускающего задачу
default_branch Обязательно Стандартная ветка проекта
iat Обязательно Дата создания
exp Обязательно Дата окончания действия
aud Не обязательно Адрес Vault

Пример JWTs:

{
  "iss": "gitflic.ru/vault",
  "project_visibility": "private"
  "ref_name": "master",
  "commit_sha": "812194e1724d03aaaaaaaaaaaa9adec3ec71f7c2",
  "project_path": "mygroup/myproject",
  "project_name": "myproject",
  "project_title": "myproject",
  "pipeline_source": "web",
  "pipeline_id": "1212",
  "sub": "1546"
  "user_login": "myuser",
  "default_branch": "master"
  "iat": 1585710286,
  "exp": 1585713886,
  "aud": "https://gitflic.ru/vault"
}

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

Этот JWT можно использовать для аутентификации на сервере Vault, который настроен на использование метода аутентификации JWT. Для этого необходимо указать базовый URL-адрес GitFlic (например, https://gitflic.ru/vault) на сервере Vault в качестве oidc_discovery_url. Затем сервер сможет получить ключи для проверки вашего токена.

При настройке ролей в Vault, вы можете использовать JWT для ограничения доступа к секретам для каждой задачи CI/CD.

Для взаимодействия с Vault вы можете использовать его клиент CLI, либо выполнять API запросы (с помощью Curl или другого клиента).

Пример работы

Допустим, у вас есть пароли для промежуточной и рабочей баз данных, хранящиеся на сервере Vault, работающем по адресу http://vault.example.com:8200. Ваш промежуточный пароль — pa$$w0rd, а рабочий пароль — real-pa$$w0rd.

$ vault kv get -field=password secret/myproject/staging/db
pa$$w0rd

$ vault kv get -field=password secret/myproject/production/db
real-pa$$w0rd

Чтобы настроить сервер Vault, начните с включения метода аутентификации JWT:

$ vault auth enable jwt
Success! Enabled jwt auth method at: jwt/

Затем создайте политики, которые позволят вам читать эти секреты (по одному для каждого секрета):

$ vault policy write myproject-staging - <<EOF
# Policy name: myproject-staging
#
# Read-only permission on 'secret/myproject/staging/*' path
path "secret/myproject/staging/*" {
  capabilities = [ "read" ]
}
EOF
Success! Uploaded policy: myproject-staging

$ vault policy write myproject-production - <<EOF
# Policy name: myproject-production
#
# Read-only permission on 'secret/myproject/production/*' path
path "secret/myproject/production/*" {
  capabilities = [ "read" ]
}
EOF
Success! Uploaded policy: myproject-production

Вам также нужны роли, которые связывают JWT с этими политиками.

Одна для промежуточной базы данных с именем myproject-staging:

$ vault write auth/jwt/role/myproject-staging - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-staging"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_claims": {
    "user_login": "myuser"
  }
}
EOF

Вторая для рабочей базы данных с именем myproject-production:

$ vault write auth/jwt/role/myproject-production - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-production"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_claims_type": "glob",
  "bound_claims": {
    "user_login": "myuser"
  }
}
EOF

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

В сочетании с защищенными ветвями вы можете ограничить круг лиц, которые могут аутентифицироваться или читать секреты.

Любое из требований, включенное в JWT, может быть сопоставлено со списком значений в связанных требованиях. Например:

"bound_claims": {
  "user_login": ["alice", "bob", "mallory"]
}

"bound_claims": {
  "ref_name": ["main", "develop", "test"]
}
  • token_explicit_max_ttl указывает, что токен, выдаваемый Vault после успешной аутентификации, имеет срок действия в 60 секунд.

  • user_claim указывает псевдоним, созданного Vault при успешном входе в систему.

Ознакомиться с полным списком настроек можно здесь.

Настройка метода аутентификации JWT:

vault write auth/jwt/config \
    oidc_discovery_url="http://localhost:8044/vault" \
    bound_issuer="http://localhost:8044""

Ознакомиться с полным списком настроек можно в документации для API Vault’a.

В GitFlic создайте следующие переменные CI/CD, чтобы предоставить подробную информацию о вашем сервере Vault:

  • VAULT_SERVER_URL — URL-адрес вашего сервера Vault, например https://vault.example.com:8200.
  • VAULT_AUTH_ROLE — Роль, используемая при попытке аутентификации. Необязательная переменная. Если роль не указана, Vault использует роль по умолчанию, указанную при настройке метода аутентификации.
  • VAULT_AUTH_PATH — Путь, по которому смонтирован метод аутентификации. Необязательная переменная. По умолчанию — jwt
  • VAULT_NAMESPACE – Пространство имен Vault Enterprise, которое будет использоваться для чтения секретов и аутентификации. Необязательная переменная. Если пространство имен не указано, Vault использует корневое пространство имен (/). Этот параметр игнорируется Vault Open Source.

Задача, приведенная ниже, запущенная для ветки по умолчанию, может читать секреты в secret/myproject/staging/, но не секреты в secret/myproject/production/:

job_with_secrets:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://example.vault.com
  secrets:
    STAGING_DB_PASSWORD:
      vault: secret/myproject/staging/db/password@secrets # авторизация с помощью $VAULT_ID_TOKEN
  script:
    - access-staging-db.sh --token $STAGING_DB_PASSWORD

В этом примере:

  • @secrets — имя хранилища, в котором включены механизмы защиты.
  • secret/myproject/staging/db — путь к секрету в Vault.
  • password - поле, которое необходимо получить из указанного секрета.

Ограничения токенов доступа к секретам в Vault

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

  • Использование Vault bound claims для определенных групп с помощью group_claim.
  • Жесткое кодирования для Vault bound claims, на основе user_login и user_email конкретных пользователей.
  • Установка ограничения времени Vault для TTL токена, с помощью token_explicit_max_ttl.
  • Комбинация JWT и функции защиты веток для ограничить круга лиц, которые могут аутентифицироваться или читать секреты.