メインコンテンツまでスキップ

タスク JWT

サーバーで JWT の発行が有効になっている場合、 テンプレートは生成する各タスクに対して、有効期間の短い署名付き token を発行できます。 この token は、実行中の playbook やスクリプトに SEMAPHORE_JWT 環境変数として公開され、OpenBao や HashiCorp Vault など、 JWT 認証をサポートする任意のシステムで 資格情報と交換できます。

キーストアに保存された長期的なシークレットと比べた利点は、 各タスクがその特定のタスク実行を識別する新しい token(プロジェクト、テンプレート、ユーザー ID)を受け取り、 タスク終了後まもなく期限切れになることです。

テンプレートで JWT を有効にする

テンプレートフォームで JWT セクションまでスクロールし(このセクションは管理者が JWT の発行を有効にした場合にのみ表示されます)、 JWT を有効にするにチェックを入れます。

テンプレートごとに次のオプションを設定できます。

フィールド説明
オーディエンスaud クレームに出力される 1 つ以上の文字列。下流のシステムが期待する識別子(例: OpenBao サーバーの URL)を設定します。最大 32 件まで指定できます。
TTLtoken の有効期間(30s10m1h などの期間)。空のままにすると、グローバルの jwt.default_ttl が使用されます。TTL はグローバルの jwt.max_ttl を超えてはいけません。

Token のクレーム

各 token には次のクレームが含まれており、下流のシステムでアクセスを許可する際に 利用できます。

クレーム備考
isshttps://semaphore.example.com管理者が設定します。
audhttps://bao.example.comテンプレートのオーディエンス一覧から取得されます。
subtask:1234タスク実行ごとに一意です。
iat / nbf / exp標準の時刻関連クレームです。
jti一意の token 識別子です。
project_id7テンプレートが属するプロジェクトです。
template_id42タスクを生成したテンプレートです。
user_id67タスクを起動したユーザーです(スケジュール実行やインテグレーション実行では省略されます)

これらのクレームを使って、利用側でアクセスの範囲を限定してください。たとえば、 project_id = 7 と特定の template_id を持つ token のみを受け入れる OpenBao のロールを作成します。

タスク内で 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

以下の手順では、Semaphore の JWT を信頼するように OpenBao を設定し、 JWT をデモ用パスワードと交換します。 semaphore.example.combao.example.com は、ご自身のホスト名に置き換えてください。

1. JWT 認証メソッドを設定する

JWT 認証メソッドを有効にし、Semaphore インスタンスの JWKS エンドポイントを 指定します。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 固有のクレーム(project_idtemplate_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

各ロールは、必ず少なくとも project_id または template_id クレームで 制限してください。バインディングがない場合、Semaphore インスタンスが発行したすべての JWT が そのロールを引き受けられてしまいます。

サポートされている設定パラメーターの完全な一覧はこちらを参照してください

4. テンプレートを設定する

デプロイ用 playbook を実行する Semaphore のテンプレートで、次の設定を行います。

  • JWT を有効にするにチェックを入れます。
  • オーディエンスhttps://bao.example.com を設定します。これは OpenBao ロールの bound_audiences と一致します。
  • 必要に応じて TTL15m に設定し、タスク終了後まもなく 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 に対して認証できるようになりました 🎉