Перейти к основному содержимому

JWT для задач

Когда выпуск JWT включён на сервере, шаблон может выпускать короткоживущий подписанный token для каждой создаваемой им задачи. Token передаётся выполняемому playbook или скрипту через переменную окружения SEMAPHORE_JWT, и его можно обменять на учётные данные в любой системе, поддерживающей аутентификацию по JWT, — например, OpenBao или HashiCorp Vault.

Преимущество по сравнению с долгоживущим секретом, хранящимся в хранилище ключей, в том, что каждая задача получает новый token, идентифицирующий конкретный запуск задачи (проект, шаблон, идентификатор пользователя), который истекает вскоре после завершения задачи.

Включение JWT в шаблоне

В форме шаблона прокрутите до раздела JWT (он отображается только если администратор включил выпуск JWT) и отметьте JWT enabled.

Для каждого шаблона можно настроить следующие параметры:

ПолеОписание
AudienceОдна или несколько строк, помещаемых в claim aud. Укажите здесь идентификатор(ы), которые ожидает ваша целевая система (например, URL сервера OpenBao). Поддерживается до 32 записей.
TTLВремя жизни token'а в виде длительности (30s, 10m, 1h, ...). Если оставить пустым, используется глобальное значение jwt.default_ttl. TTL не должен превышать глобальное значение jwt.max_ttl.

Claims token'а

Каждый token содержит следующие claims, на которые можно полагаться при предоставлении доступа в целевой системе:

ClaimПримерПримечания
isshttps://semaphore.example.comНастраивается администратором.
audhttps://bao.example.comИз списка audience шаблона.
subtask:1234Уникален для каждого запуска задачи.
iat / nbf / expСтандартные временные claims.
jtiУникальный идентификатор token'а.
project_id7Проект, к которому относится шаблон.
template_id42Шаблон, создавший задачу.
user_id67Пользователь, запустивший задачу (отсутствует для запусков по расписанию / из интеграций)

Используйте эти claims, чтобы ограничить доступ на принимающей стороне. Например, роль OpenBao, принимающая только token'ы с project_id = 7 и определённым template_id.

Использование token'а внутри задачи

Semaphore экспортирует token как SEMAPHORE_JWT в окружении процесса задачи.

#!/usr/bin/env bash

# Bash example
echo "Look at my fancy token: $SEMAPHORE_JWT"
# Ansible example
- name: Read secret from OpenBao KVv2 via JWT auth
ansible.builtin.set_fact:
openbao_secret_value: >-
{{ lookup(
'community.hashi_vault.hashi_vault',
secret='kv/data/semaphore/demo:value',
auth_method='jwt',
url='https://bao.example.com',
role_id=bao_role,
jwt=lookup('ansible.builtin.env', 'SEMAPHORE_JWT')
) }}

Пример: OpenBao

Следующее пошаговое руководство настраивает OpenBao на доверие к JWT от Semaphore и обменивает их на демонстрационный пароль. Замените semaphore.example.com и bao.example.com на ваши собственные имена хостов.

1. Настройте метод аутентификации JWT

Включите метод аутентификации JWT и укажите ему конечную точку JWKS вашего экземпляра Semaphore. OpenBao использует полученный оттуда открытый ключ для проверки каждого token'а.

bao auth enable jwt

bao write auth/jwt/config \
jwks_url="https://semaphore.example.com/.well-known/jwks.json" \
bound_issuer="https://semaphore.example.com"

2. Определите политику

Предоставьте разрешения, необходимые задаче. Пример ниже разрешает чтение демонстрационных учётных данных, расположенных по пути kv/data/semaphore/demo:

bao policy write semaphore-demo-policy - <<EOF
path "kv/data/semaphore/demo" {
capabilities = ["read"]
}
EOF

3. Определите роль OpenBao, привязанную к шаблону

Роль OpenBao определяет, каким задачам Semaphore разрешено использовать какую политику. Используйте специфичные для Semaphore claims (project_id, template_id, ...) в качестве bound_claims, чтобы роль мог использовать только нужный шаблон:

bao write auth/jwt/role/semaphore-demo-role - <<EOF
{
"role_type": "jwt",
"user_claim": "sub",
"bound_audiences": "https://bao.example.com",
"bound_claims": {
"project_id": "7",
"template_id": "42"
},
"policies": ["semaphore-demo-policy"],
}
EOF

Всегда ограничивайте каждую роль как минимум claim'ом project_id или template_id. Без такой привязки любой JWT, выпущенный вашим экземпляром Semaphore, сможет использовать эту роль.

Полный список поддерживаемых параметров конфигурации можно найти здесь

4. Настройте шаблон

В шаблоне Semaphore, который запускает playbook развёртывания:

  • Отметьте JWT enabled.
  • Укажите в Audience значение https://bao.example.com — оно соответствует bound_audiences в роли OpenBao.
  • При желании задайте TTL равным 15m, чтобы token истекал вскоре после завершения задачи.

5. Используйте token в задаче

- hosts: localhost
gather_facts: false
tasks:
- name: Read secret from OpenBao KVv2 via JWT auth
ansible.builtin.set_fact:
openbao_secret_value: >-
{{ lookup(
'community.hashi_vault.hashi_vault',
secret='kv/data/semaphore/demo:value',
auth_method='jwt',
url='https://bao.example.com',
role_id='semaphore-demo-role',
jwt=lookup('ansible.builtin.env', 'SEMAPHORE_JWT')
) }}

Теперь задача аутентифицируется в OpenBao без какого-либо заранее разделяемого секрета 🎉