Перейти к содержанию

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

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


Введение

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

Предусловия

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

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

Работа с Vault

Аутентификация через JWT

Для интеграции с Vault необходима аутентификация с использованием JWT-токенов. Другие методы аутентификации не поддерживаются.

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, а GitFlic расположен по адресу http://localhost:8080. Ваш промежуточный пароль — password, а рабочий пароль — real-password.

$ vault kv put secret/myproject/staging/db password=password
========== Secret Path ==========
secret/data/myproject/staging/db

======= Metadata =======
Key                Value
---                -----
created_time       2024-11-28T12:45:47.797958266Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

$ vault kv put secret/myproject/production/db password=real-password
========== Secret Path ==========
secret/data/myproject/production/db

======= Metadata =======
Key                Value
---                -----
created_time       2024-11-28T12:46:14.579238266Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1
$ vault kv get -field=password secret/myproject/staging/db
password

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

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

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

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

$ vault policy write myproject-staging - <<EOF
# Policy name: myproject-staging
# При указании пути для политики ориентируйтесь на ответ от Vault после создания секрета (========== Secret Path ==========)
# Read-only permission on 'secret/myproject/staging/*' path
path "secret/data/myproject/staging/*" {
  capabilities = [ "read" ]
}
EOF
Success! Uploaded policy: myproject-staging

$ vault policy write myproject-production - <<EOF
# Policy name: myproject-production
# При указании пути для политики ориентируйтесь на ответ от Vault после создания секрета (========== Secret Path ==========)
# Read-only permission on 'secret/myproject/production/*' path
path "secret/data/myproject/production/*" {
  capabilities = [ "read" ]
}
EOF
Success! Uploaded policy:s 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_login",
  "bound_audiences": [ # обязательное поле для Vault > 1.16 
    "http://vault.example.com:8200" 
  ],
  "bound_claims": {
    "user_login": "adminuser"
  }
}
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_login",
  "bound_audiences": [ # обязательное поле для Vault версии > 1.16
    "http://vault.example.com:8200"
  ],
  "bound_claims_type": "glob",
  "bound_claims": {
    "user_login": "adminuser"
  }
}
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:8080/vault" \
    bound_issuer="http://localhost:8080"

Ознакомиться с полным списком настроек можно в документации для 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: http://vault.example.com:8200
  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 и функции защиты веток для ограничить круга лиц, которые могут аутентифицироваться или читать секреты.