wiki-js/DevOps/Hashicorp-Vault/Gitlab-with-vault.md

196 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: Vault через GitLab CI - Аутентификация и чтение секретов
description:
published: true
date: 2024-08-01T14:48:58.749Z
tags: vault, gitlab
editor: markdown
dateCreated: 2024-07-31T12:59:36.391Z
---
Источник: https://habr.com/ru/companies/nixys/articles/512754/
Этот туториал демонстрирует пример аутентификации, конфигурации и чтения секретов с HashiCorps Vault через GitLab CI/CD.
**Требования**
Туториал предполагает, что вы знакомы с GitLab CI/CD и Vault.
Чтобы ему последовать, вам понадобятся:
- Аккаунт в GItLab
- Запущенный Vault сервер и доступ для настройки аутентификации и создания ролей и политик.
Для каждой задачи (job) генерируется свой уникальный токен JSON Web Token (JWT), доступный только как значение переменной окружения CI_JOB_JWT конкретной задачи. Данный JWT может быть использован для аутентификации в Vault при помощи метода JWT Auth.
Пример того, как выглядит JWT в дешифрованном виде:
```json
{  
 "jti": "c82eeb0c-5c6f-4a33-abf5-4c474b92b558", # Уникальный идентификатор токена  
 "iss": "gitlab.example.com",                   # Issuer, т.е. домен вашего инстанса GitLab  
 "iat": 1585710286,                             # Время выдачи   
 "nbf": 1585798372,                             # Не валиден до  
 "exp": 1585713886,                             # Не велиден после  
 "sub": "22",                                   # Subject (project id)  
 "namespace_id": "1",  
 "namespace_path": "mygroup",  
 "project_id": "22",  
 "project_path": "mygroup/myproject",  
 "user_id": "42",  
 "user_login": "myuser",  
 "user_email": "myuser@example.com"  
 "pipeline_id": "1212",  
 "job_id": "1212",  
 "ref": "auto-deploy-2020-04-01",               # Название Git-refs для этой задачи  
 "ref_type": "branch",                          # Тип Git-refs, это либо(branch) либо тег(tag)  
 "ref_protected": "true"                        # true, если это ветка protected, иначе false  
}
```
Токен кодируется по стандарту RS256 и подписывается приватным ключом OpenID Connect вашего GitLab инстанса, причем этот ключ периодически изменяется без вашего ведома. И, если приватный ключ был изменен, при cледующем запуске задания новый JWT будет подписан с новым ключом. Срок валидности токена будет устанавливаться в соотвествии с таймаутом вашего задания, а если он не задан, то срок валидности будет 5 минут.
Вы можете использовать этот JWT-токен и URL (https://gitlab.example.com/-/jwks) как конечную точку JWKS для аутентификации на Vault сервере, если для него настроен соответствующий метод JWT-аутентификации.
При настройке ролей в Vault, вы можете задавать значения bound_claims для сопоставления их с полями из JWT и, таким образом, дополнительно ограничить то, к каким секретам какой процесс CI будет иметь доступ.
Для получения доступа к Vault можно использовать либо его CLI, либо выполнять запросы к API (через curl или другой клиент).
**Пример**
Предположим, у вас есть пароли для ваших баз данных, отличающиеся для production и staging окружений и они хранятся в Vault, который доступен по адресу http://vault.example.com:8200. Ваш пароль для stage это pa$$w0rd и real-pa$$w0rd для prod:
```
$ 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/
```
Создаем policy, которые дают доступ на чтение к нужным нам секретам:
```bash
$ vault policy write myproject-staging - <<EOF  
# Policy name: myproject-staging  
#  
# Read-only permission on 'secret/data/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  
#  
# Read-only permission on 'secret/data/myproject/production/*' path  
path "secret/data/myproject/production/*" {  
  capabilities = [ "read" ]  
}  
EOF  
Success! Uploaded policy: myproject-production
```
Теперь нам нужны роли, которые будут связывать созданные политики с JWT-токенами.
Для stage под названием myproject-staging:
```json
$ 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": {  
    "project_id": "22",  
    "ref": "master",  
    "ref_type": "branch"  
  }  
}  
EOF
````
И для production под названием myproject-production:
```json
$ 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": {  
    "project_id": "22",  
    "ref_protected": "true",  
    "ref_type": "branch",  
    "ref": "auto-deploy-*"  
  }  
}  
EOF
```
В этом примере использовались bound_claims указывающие, что только JWT-токены с соответствующими значениями смогут пройти аутентификацию.
В сочетании с GitLab protected branches, можно разграничивать тех, кто может проходить аутентификацию и читать секреты.
Token_explicit_max_ttl определяет, что выпущенный Vault токен, после аутентификации имеет время жизни 60 секунд.
User_claim определяет имя пользователя, которое будет использовать Vault при успешной авторизации. (Прим. переводчика — В нашем случае "user_claim" = "user_email", то есть имя пользователя будет иметь значение user_email из JWT-токена. То есть определяться как (известный GitLab) email пользователя, запустившего задание.)
Параметр bound_claims_type задает формат значений bound_claims. Если он установлен в “glob”, то значения будут интерпретироваться в формате glob и * будет означать любое количество символов. (Прим. переводчика — Также доступно значение “string”, в этом случае данные будут хранится в формате строк и * будет означать только *.)
Полный лист опций можно посмотреть в Vaults Create Role documentation.
Предупреждение: обязательно устанавливайте либо project_id либо namespace_id, иначе любой токен, сгенерированный этим инстансом GitLab, сможет использовать эту роль.
Теперь зададим метод аутентификации через JWT:
```
$ vault write auth/jwt/config \ 
   jwks_url="https://gitlab.example.com/-/jwks" \ 
   bound_issuer="gitlab.example.com"
```
bound_issuer определяет, что только токены, выпущенные от имени домена gitlab.example.com (iss claim) могут использовать этот метод аутентификации, и в качестве точки валидации токена JWKS должна использоваться страница https://gitlab.example.com/-/jwks .
Полный список доступных опций можно посмотреть в Vaults API documentation.
Теперь создадим джобу для master-ветки, у которой будут права на чтение secret/myproject/staging/, но при этом не будет прав на чтение secret/myproject/production/:
```yaml
read_secrets:  
 script:  
   # Проверяем имя ref джобы  
    - echo $CI_COMMIT_REF_NAME  
   # и является ли она protected  
    - echo $CI_COMMIT_REF_PROTECTED  
   # Адрес Vault может быть передан через переменную в CI  
    - export VAULT_ADDR=http://vault.example.com:8200  
   # Проходим аутентификацию и получаем токен. Время истечения жизни токена и другие    
   # его параметры можно задать при конфигурации   
   # JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1  
    - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-staging jwt=$CI_JOB_JWT)"  
   # Теперь используем VAULT_TOKEN для чтения секретов и сохранения их в перемнных окружения  
    - export PASSWORD="$(vault kv get -field=password secret/myproject/staging/db)"  
   # Используем секрет  
    - echo $PASSWORD  
   # Здесь получить секрет не получится, потому что роль myproject-staging не может   
   # читать секреты из secret/myproject/production/*  
    - export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
```
![vault-gitlab.png](/DevOps/img/vault-gitlab.png)
Следующее задание сможет пройти аутентификацию через роль myproject-production и прочитать секрет в /secret/myproject/production/:
```yaml
read_secrets:  
 script:  
   # Проверяем имя ref джобы  
    - echo $CI_COMMIT_REF_NAME  
   # и является ли она protected  
    - echo $CI_COMMIT_REF_PROTECTED  
   # Адрес Vault может быть передан через переменную в CI  
    - export VAULT_ADDR=http://vault.example.com:8200  
   # Проходим аутентификацию и получаем токен. Время истечения жизни токена и другие    
   # его параметры можно задать при конфигурации   
   # JWT Auth - https://www.vaultproject.io/api/auth/jwt#parameters-1  
    - export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"  
   # Теперь используем VAULT_TOKEN для чтения секретов и сохранения их в перемнных окружения  
    - export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"  
   # Используем секрет  
    - echo $PASSWORD
```
![vault-gitlab2.png](/DevOps/img/vault-gitlab2.png)
На этом все, надеюсь данный туториал окажется вам полезен!