Аутентификация и чтение секретов в 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 и функции защиты веток для ограничить круга лиц, которые могут аутентифицироваться или читать секреты.