Розглянемо процес налаштування інтеграції з HashiCorpVAULT. Для інтеграції типу “app to app” рекомендується використовувати метод аутентифікації AppRole.
Рекомендується ознайомитись з кращими практиками approle-best-practices та впроваджувати їх.
Що таке AppRole?
Це один з методів аутентифікації, який дозволяє додаткам, хостам аутентифікуватися за допомогою визначених ролей в VAULT. В нашому випадку за допомогою встановленого та налаштованого плагіну HashicorpVault, Jenkins зможе отримувати VAULT_TOKEN з відповідними політиками, які надають доступ до вказаних шляхів.
Як працює AppRole?
Кожна створена approle має унікальний ідентифікатор role_id який захищений за допомогою secret_id (можемо вважати це логіном та паролем). Коли отримали обидва ці значення, можемо запросити в Vault токен, який буде використаний для доступу до сховища, вказаних шляхів які ми описуємо в політиках VAULT.
Для чого це потрібно?
В першу чергу для безпеки, щоб не зберігати критичні дані в “Jenkins Credentials Storage” та не вказувати в “job parameters”, а отримувати їх з централізованого сховища.
Як будемо реалізовувати?
Сам процес розділимо на декілька етапів:
- роботи з VAULT (налаштування, створення політики, ролі)
- роботи з Jenkins (встановлення/налаштування плагіну, тестування)
Підготовка VAULT
Дані маніпуляції можна проводити на сервері VAULT або з локальної машини (наш варіант), для цього потрібно щоб у вас був встановлений пакет vault або виконувати запити за допомогою curl(варіант з curl описаний в документації).
Налаштовуємо доступ, експортуємо дані:
export VAULT_ADDR=https://vault.example.com
export VAULT_TOKEN=s.3**23*********fs42
Вмикаємо метод авторизації approle:
vault auth enable approle
Success! Enabled approle auth method at: approle/
Створюємо політику доступу з назвою “jenkins”, в якій вказуємо шлях до якого потрібен доступ:
vault policy write jenkins -<<EOF path "service/data/jenkins/credentials" { capabilities = [ "read" ] }EOF
де:
- path “service/data/jenkins/credentials” – шлях з якого ми хочемо зчитувати ключ-значення;
- capabilities = [ “read” ] – вказуємо що дозволено виконувати, а що ні, в такому випадку дозволено тільки читати записи;
Переходимо до створення ролі, назвемо її “jenkins-role”:
vault write auth/approle/role/jenkins \
secret_id_bound_cidrs="*43.*.*.*/32","**9.*.*.*/32","*1.*.*.*/32","127.0.0.1/32" \
secret_id_num_uses=0 \
enable_local_secret_ids=false \
token_bound_cidrs="*43.*.*.*/32","**9.*.*.*/32","*1.*.*.*/32","127.0.0.1/32" \
token_num_uses=0 \
token_ttl=1h \
token_max_ttl=3h \
token_type=default \
period="" \
policies="default","jenkins"
де:
- secret_id_bound_cidrs – дозволені ip-адреси які можуть виконувати логін;
- secret_id_num_uses – кількість разів коли певний SecretID може отримати токен з AppRole, після чого дія SecretID закінчується. Якщо потрібно необмежене використання встановлюємо 0. За бажанням цей параметр можна змінити полем «num_uses» при генерації SecretID;
- enable_local_secret_ids – не створювати local_secret_ids;
- token_num_uses – максимальна кількість разів, коли згенерований токен може бути використаний (протягом встановленого терміну служби). 0 – означає необмежений.
- token_ttl – час життя токена після якого він буде поновлюватись;
- token_max_ttl – максимальний термін служби згенерованих токенів;
- token_type – тип токена який буде генеруватися;
- token_bound_cidrs – список ір-адрес яким дозволено аутентифікуватися за допомогою токена;
- policies=”jenkins” – додаємо створено політику “jenkins” до ролі;
Отримуємо role_id:
vault read auth/approle/role/jenkins-role/role-id
Key Value
--- -----
role_id 8f******-****-d236-****-7*******67
де:
- role_id – ідентифікатор (унікальними UUID) який призначається для approle (можна вважати це логіном).
Генеруємо secret_id:
vault write -f auth/approle/role/jenkins-role/secret-id
Key Value
--- -----
secret_id b*******-5**c-*c**-8***-**********50
де:
- secret_id – якщо коротко, це облікові дані які використовуються для будь-якого входу (можна вважати це паролем).
Перед використанням в Jenkins перевіримо доступ за допомогою ролі з локальної робочої станції (вашого ПК). Виконаємо логін за допомогою approle:
vault write auth/approle/login role_id="******7-cf**-****-***f-**ec*****ea" secret_id="ed******-****f-****-***f-********5f29" Key Value --- ----- token s.ncE******************5h token_accessor gIQF*******************nQu token_duration 1h token_renewable true token_policies ["default" "jenkins"] identity_policies [] policies ["default" "jenkins"] token_meta_role_name jenkins
У виводі отримали певну інформацію, з якої беремо токен та експортуємо його:
export APP_TOKEN="s.ncE******************5h" export VAULT_TOKEN=$APP_TOKEN
перевіряємо доступ за шляхом service/jenkins/credentials:
vault kv get service/jenkins/credentials ========= Secret Path ========= service/data/jenkins/credentials ====== Metadata ====== Key Value --- ----- created_time ************* deletion_time n/a destroyed false version 1 =========== Data =========== Key Value --- ----- jenkins_pass ************************* jenkins_token ******************** jenkins_user ********************
тепер спробуємо вказати інший шлях, приклад service/gitlab:
vault kv get service/gitlab/
Error making API request.
URL: GET https://vault.example.com/v1/sys/internal/ui/mounts/service/gitlab
Code: 403. Errors:
* preflight capability check returned 403, please ensure client's policies grant access to path "service/gitlab/"
отримали 403, оскільки в політиці доступу даний шлях не вказаний. Таким чином ми перевірили доступ за допомогою approle, переконалися що з політика налаштована вірно, переходимо до встановлення та налаштування плагіну з боку Jenkins.
Встановлення
Логінимось в Jenkins, переходимо в Manage Jenkins > Manage Plugins > Avealible Plugins, обираємо HashiCorp Vault та встановлюємо:
Створимо запис для доступу в Vault, переходимо Manage Jenkins > Credentiasl > System > Global credentials > Add credentials, назвемо його vault-role-jenkins:
де:
- Kind “VAULT App role Credentials” – тип запису для AppRole;
- Role ID – унікальний ідентифікатор ролі;
- Secret ID – таємний ключ для ролі;
- ID – назва запису;
Налаштування Плагіну
Переходимо в Manage Jenkins > Configure System знаходимо розділ Vault Plugin:
де:
- Vautl URL – посилання на Ваш сервер;
- Vault Credential – створений запис для доступу;
Заповнюємо та зберігаємо зміни, перевіряємо роботу плагіну.
Використання
Створимо тестове завдання, в якому будемо витягувати записи з VAULT. Приклад пайплайну взято з офіційної сторінки плагіну, використовуємо groovy:
node {
def configuration = [vaultUrl: 'https://vault.example.com', vaultCredentialId: 'vault-role-jenkins', engineVersion: 2]
def secrets = [
[path: 'service/jenkins/credentials', engineVersion: 2, secretValues: [
[vaultKey: 'jenkins_user']]]
]
withVault([configuration: configuration, vaultSecrets: secrets]) {
sh 'echo $jenkins_user >> test.txt'
}
}
де:
- def configuration – функція в якій описуємо конфігурацію для доступу до VAULT;
- def secrets – вказуємо шлях до ключів та значень і ключ, значення якого хочемо отримати;
Запустимо завдання, переглянемо вивід:
Started by user geek
[Pipeline] Start of Pipeline
[Pipeline] node
Running on runner in /opt/jenkins/workspace/TEST/VAULT_TEST
[Pipeline] {
[Pipeline] withVault
Retrieving secret: service/jenkins/credentials
[Pipeline] {
[Pipeline] sh
+ echo ****
[Pipeline] // withVault
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Оскільки плагін за замовчуванням маскує вивід критичних даних в output переглянути вміст не вийде. Щоб переконатися що отримане значення вірне, можемо вивід ключа перенаправити в файл, потім прочитати значення з файлу (безпосередньо на сервері або агенті jenkins). Інтеграцію налаштовано.
Корисні посилання
- https://developer.hashicorp.com/vault/docs/auth/approle
- https://developer.hashicorp.com/vault/tutorials/auth-methods/approle
- https://developer.hashicorp.com/vault/api-docs/auth/approle
- https://plugins.jenkins.io/hashicorp-vault-plugin