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

Использование секретов Vault в CI/CD

В AppSec.Code можно использовать секреты Vault в конвейерах CI/CD. Для аутентификации в Vault применяются ID-токены.

Прежде чем использовать секреты Vault в задании CI/CD, необходимо настроить сервер Vault. Подробнее о настройке Vault и аутентификации с помощью ID-токенов см. в документации Vault.

Примечание

В приведённых ниже примерах замените vault.example.com на URL вашего сервера Vault, а appseccode.example.com — на URL вашего экземпляра AppSec.Code.

Настройка сервера Vault

Чтобы настроить сервер Vault, выполните следующие действия:

  1. Включите метод аутентификации, выполнив приведённые ниже команды. Они передают серверу Vault OIDC Discovery URL вашего экземпляра AppSec.Code, благодаря чему Vault может получить публичный ключ подписи и проверить JSON Web Token (JWT) при аутентификации:

    $ vault auth enable jwt
    
    $ vault write auth/jwt/config \
      oidc_discovery_url="https://appseccode.example.com" \
      bound_issuer="appseccode.example.com"
    
  2. Настройте политики на сервере Vault, чтобы разрешить или запретить доступ к определённым путям и операциям. В этом примере предоставляется доступ на чтение к набору секретов, необходимых для рабочего окружения:

    vault policy write myproject-production - <<EOF
    # Read-only permission on 'ops/data/production/*' path
    
    path "ops/data/production/*" {
      capabilities = [ "read" ]
    }
    EOF
    
  3. Настройте роли на сервере Vault, ограничив их областью проекта или пространства имён.

  4. Создайте следующие переменные CI/CD, описывающие параметры сервера Vault (см. раздел «Переменные CI/CD»):

    • VAULT_SERVER_URL — URL сервера Vault, например, https://vault.example.com:8200.
    • VAULT_AUTH_ROLE — необязательная переменная для указания роли аутентификации. Если роль не указана, Vault использует роль по умолчанию, указанную при настройке метода аутентификации.
    • VAULT_AUTH_PATH — необязательная переменная; путь, по которому подключён метод аутентификации. По умолчанию jwt.
    • VAULT_NAMESPACE — необязательная переменная; пространство имён Vault Enterprise, используемое для чтения секретов и аутентификации:
      • Для Vault, пространство имен root/») используется, если пространство имен не указано.
      • Для Vault Open source, параметр игнорируется.
      • Для облачной платформы HCP Vault, требуется указать пространство имен. HCP Vault по умолчанию использует пространство имен администратора в качестве корневого пространства имен, например, VAULT_NAMESPACE=admin.

Настройка ролей сервера

При попытке аутентификации задание CI/CD указывает роль. Роли позволяют группировать различные политики. При успешной аутентификации эти политики привязываются к выданному токену Vault.

Привязанные утверждения (bound claims) — это предопределённые значения, которые сопоставляются с утверждениями JWT. С их помощью можно ограничить доступ конкретными пользователями, конкретными проектами или даже заданиями, выполняемыми для определённых Git-ссылок. Привязанных утверждений может быть сколько угодно, но для успешной аутентификации должны совпасть все.

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

$ vault write auth/jwt/role/myproject-production - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-production"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_audiences": "https://vault.example.com",
  "bound_claims_type": "glob",
  "bound_claims": {
    "project_id": "42",
    "ref_protected": "true",
    "ref_type": "tag",
    "ref": "auto-deploy-*"
  }
}
EOF

Внимание

Всегда ограничивайте роли областью проекта или пространства имён, используя одно из доступных утверждений, например project_id или namespace_id. Без таких ограничений любой JWT, выпущенный этим экземпляром AppSec.Code, сможет пройти аутентификацию с использованием этой роли.

Для выдаваемых токенов Vault можно также задать ряд атрибутов: время жизни (time-to-live), диапазон IP-адресов и число использований. Полный список параметров приведён в документации Vault по созданию ролей для метода аутентификации JSON Web Token.

Использование секретов Vault в задании CI/CD

Если в задании определён хотя бы один ID-токен, ключевое слово secrets автоматически использует этот токен для аутентификации в Vault.

После настройки сервера Vault используйте ключевое слово secrets:vault для доступа к секретам, хранящимся в Vault (см. раздел «secrets:vault»):

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops
      token: $VAULT_ID_TOKEN

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

  • production/db — путь к секрету.
  • password — поле.
  • ops — путь монтирования движка секретов.
  • production/db/password@ops преобразуется в путь ops/data/production/db.
  • Аутентификация выполняется с использованием $VAULT_ID_TOKEN.

После того как AppSec.Code получает секрет из Vault, его значение сохраняется во временный файл. Путь к этому файлу записывается в переменную CI/CD с именем DATABASE_PASSWORD — аналогично переменным типа file.

Чтобы переопределить поведение по умолчанию, явно задайте параметр file (см. раздел «secrets:file»):

secrets:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  DATABASE_PASSWORD:
    vault: production/db/password@ops
    file: false
    token: $VAULT_ID_TOKEN

В этом примере значение секрета помещается непосредственно в переменную DATABASE_PASSWORD, а не указывает на файл с этим значением.

Движки секретов

Раннер поддерживает различные движки секретов через ключевое слово secrets:engine:name:

Движок секретов Значение secrets:engine:name Описание
KV secrets engine — version 2 kv-v2 Движок, используемый раннером по умолчанию при отсутствии явного указания типа движка.
KV secrets engine — version 1 kv-v1 или generic
AWS secrets engine generic
Vault Artifactory Secrets Plugin generic Взаимодействует с сервером JFrog Artifactory версии 5.0.0 и выше, динамически выдаёт токены доступа с заданными правами.

Использование другого движка секретов

По умолчанию используется kv-v2. Чтобы применить другой движок, добавьте секцию engine под vault в конфигурацию.

Пример настройки движка секретов и пути для Artifactory:

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.com
  secrets:
    JFROG_TOKEN:
      vault:
        engine:
          name: generic
          path: artifactory
        path: production/jfrog
        field: access_token
      file: false

В этом примере значение секрета получается из artifactory/production/jfrog с полем access_token.

Устранение неполадок

Ошибка самоподписанного сертификата: certificate signed by unknown authority

Если сервер Vault использует самоподписанный сертификат, в логах задания появляется следующая ошибка:

ERROR: Job failed (system failure): resolving secrets: initializing Vault service: preparing authenticated client: checking Vault server health: Get https://vault.example.com:8000/v1/sys/health?drsecondarycode=299&performancestandbycode=299&sealedcode=299&standbycode=299&uninitcode=299: x509: certificate signed by unknown authority

Устранить эту ошибку можно одним из двух способов:

  • Добавьте самоподписанный сертификат в хранилище CA на сервере раннера. Если раннер развёрнут с помощью Helm chart, потребуется создать собственный образ раннера (см. раздел «Запуск средства выполнения (раннера)»).
  • Используйте переменную окружения VAULT_CACERT, чтобы настроить раннер на доверие сертификату:
    • При управлении раннером через systemd добавьте пользовательскую переменную окружения для раннера.
    • Если раннер развёрнут с помощью Helm chart:

      1. Предоставьте пользовательский сертификат для доступа к серверу Vault и убедитесь, что добавлен именно сертификат сервера Vault, а не сертификат AppSec.Code. Если экземпляр AppSec.Code также использует самоподписанный сертификат, оба сертификата можно добавить в один и тот же Secret.
      2. Добавьте следующие строки в файл values.yaml:
      ## Replace both the <SECRET_NAME> and the <VAULT_CERTIFICATE>
      ## with the actual values you used to create the secret
      
      certsSecretName: <SECRET_NAME>
      
      envVars:
        - name: VAULT_CACERT
          value: "/home/gitlab-runner/.gitlab-runner/certs/<VAULT_CERTIFICATE>"
      

Если сервер Vault запущен локально в режиме разработки, эта ошибка также может возникать. В этом случае можно вручную добавить самоподписанный сертификат сервера Vault в доверенные. Например, для macOS процесс описан в этом руководстве.

Ошибка resolving secrets: secret not found: MY_SECRET

Если AppSec.Code не может найти секрет в Vault, может возникнуть следующая ошибка:

ERROR: Job failed (system failure): resolving secrets: secret not found: MY_SECRET

Убедитесь, что значение vault корректно настроено в задании CI/CD (см. раздел «Использование секретов Vault в задании CI/CD»).

Для проверки доступности секрета и определения синтаксиса значения vault в конфигурации CI/CD можно использовать команду kv в Vault CLI. Например, чтобы получить секрет:

$ vault kv get -field=password -namespace=admin -mount=ops "production/db"
this-is-a-password