infisical-sync-skill について
Infisical とシークレットを同期するエージェント向けのリファレンススキルです。API 操作に加え、認証、セキュリティ確認、同期状態の追跡、ローカルの暗号化 vault 操作を扱います。
主な機能
- 01Universal Auth による認証手順
- 02シークレットの一覧・作成・更新・削除
- 03同期状態とハッシュの追跡
- 04暗号化 vault 操作のリファレンス
- 05セキュリティ確認とトラブルシューティング
活用シーン
- 01Infisical のシークレットをローカル vault に同期
- 02プロジェクトや環境ごとのシークレット管理
- 03認証・権限・接続エラーの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rightnow-ai/ openfang --skill infisical-sync-skillインストール後、Claude Code で/infisical-sync-skillを入力して読み込まれたか確認します。
同梱ファイルHAND.toml
詳細
Infisical 同期に関する専門知識
1. Infisical API リファレンス
ベース URL
すべてのリクエストの送信先は $INFISICAL_URL です。これはセルフホストインスタンスのベース URL です。例:https://infisical.example.com。
認証 — Universal Auth
Infisical は、エージェント間通信に Universal Auth を使用するマシン ID を使用します。
エンドポイント:POST /api/v1/auth/universal-auth/login
リクエスト:
{
"clientId": "<INFISICAL_CLIENT_ID>",
"clientSecret": "<INFISICAL_CLIENT_SECRET>"
}
レスポンス(成功時):
{
"accessToken": "eyJ...",
"expiresIn": 7200,
"accessTokenMaxTTL": 43200,
"tokenType": "Bearer"
}
curl の例:
RESPONSE=$(curl -s -X POST "$INFISICAL_URL/api/v1/auth/universal-auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"$INFISICAL_CLIENT_ID\",\"clientSecret\":\"$INFISICAL_CLIENT_SECRET\"}")
ACCESS_TOKEN=$(echo "$RESPONSE" | python3 -c "import sys,json; print(json.load(sys.stdin)['accessToken'])")
トークンの有効期間は expiresIn 秒です(通常は 7200 秒=2 時間)。有効期限が切れたら再認証してください。
シークレットの一覧表示
エンドポイント:GET /api/v4/secrets
クエリパラメーター:
| パラメーター | 必須 | 説明 |
|---|---|---|
projectId | はい | Infisical プロジェクト ID |
environment | はい | 環境スラッグ(例:prod、staging、dev) |
secretPath | いいえ | パスのプレフィックス。デフォルトは / |
includeImports | いいえ | インポートされたシークレットを含めるかどうか。デフォルトは false |
recursive | いいえ | サブパス内のシークレットを含めるかどうか。デフォルトは false |
curl の例:
curl -s -X GET \
"$INFISICAL_URL/api/v4/secrets?projectId=$PROJECT_ID&environment=$ENVIRONMENT&secretPath=/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
レスポンスの形式:
{
"secrets": [
{
"id": "uuid",
"version": 1,
"secretKey": "DATABASE_URL",
"secretValue": "postgres://...",
"secretComment": "",
"environment": "prod",
"workspace": "uuid"
}
],
"imports": []
}
次のように解析します:
echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for s in data.get('secrets', []):
print(s['secretKey'])
"
シークレットの作成または更新
API に単一の upsert エンドポイントはありません。POST は作成のみを行い(シークレットがすでに存在する場合は 409 を返します)、PATCH は更新のみを行います(シークレットが存在しない場合は 404 を返します)。作成してから更新するパターンを使用してください。
ステップ 1 — 作成を試みる(POST)
エンドポイント:POST /api/v4/secrets/{secretName}
リクエストボディ:
{
"projectId": "<PROJECT_ID>",
"environment": "<ENV>",
"secretValue": "<VALUE>",
"secretPath": "/"
}
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" \
-X POST "$INFISICAL_URL/api/v4/secrets/$SECRET_NAME" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"projectId\":\"$PROJECT_ID\",\"environment\":\"$ENVIRONMENT\",\"secretValue\":\"$SECRET_VALUE\",\"secretPath\":\"/\"}")
成功すると 201 を返します。
ステップ 2 — 409 の場合は PATCH で更新する
エンドポイント:PATCH /api/v4/secrets/{secretName}
if [ "$HTTP_STATUS" = "409" ]; then
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" \
-X PATCH "$INFISICAL_URL/api/v4/secrets/$SECRET_NAME" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"projectId\":\"$PROJECT_ID\",\"environment\":\"$ENVIRONMENT\",\"secretValue\":\"$SECRET_VALUE\",\"secretPath\":\"/\"}")
fi
成功すると 200 を返します。それ以外のステータスコードはエラーです。
重要:シークレット名に特殊文字が含まれている場合は、URL エンコードしてください。
シークレットの削除
エンドポイント:DELETE /api/v4/secrets/{secretName}
クエリパラメーター:projectId、environment、secretPath(デフォルトは /)
curl の例:
curl -s -X DELETE \
"$INFISICAL_URL/api/v4/secrets/$SECRET_NAME?projectId=$PROJECT_ID&environment=$ENVIRONMENT&secretPath=/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
アクセス可能なプロジェクト(ワークスペース)の一覧表示
エンドポイント:GET /api/v1/workspace
curl -s -X GET "$INFISICAL_URL/api/v1/workspace" \
-H "Authorization: Bearer $ACCESS_TOKEN"
レスポンス:{ "workspaces": [{ "id": "uuid", "name": "...", "environments": [...] }] }
2. HTTP エラーコード
| コード | 意味 | 対応 |
|---|---|---|
| 200/201 | 成功 | 続行する |
| 400 | 不正なリクエスト | レスポンスボディをログに記録します。JSON の形式が不正、またはフィールドが不足している可能性があります |
| 401 | 認証されていない | 再認証します。トークンの有効期限が切れている可能性があります |
| 403 | 禁止 | マシン ID に権限がありません。Infisical のアクセス制御を確認してください |
| 404 | 見つからない | シークレットまたはプロジェクトが存在しません |
| 429 | レート制限 | 60 秒待ってから 1 回再試行します |
| 500/503 | サーバーエラー | ログに記録し、30 秒後に 1 回再試行します。それでも失敗する場合は通知してください |
レスポンスボディを信頼する前に、必ず HTTP ステータスを確認してください:
HTTP_STATUS=$(curl -s -o /tmp/infisical_response.json -w "%{http_code}" ...)
if [ "$HTTP_STATUS" != "200" ] && [ "$HTTP_STATUS" != "201" ]; then
# handle error
fi
RESPONSE=$(cat /tmp/infisical_response.json)
3. 同期状態ファイルの形式
infisical_sync_state.json に保存します:
{
"last_sync": "2025-01-15T10:30:00Z",
"project_ids": ["uuid1", "uuid2"],
"environment": "prod",
"secrets": {
"DATABASE_URL": {
"hash": "sha256_of_key_plus_value",
"version": 3,
"last_synced": "2025-01-15T10:30:00Z"
}
},
"error_count": 0,
"push_count": 12,
"pull_count": 47
}
ハッシュの計算(値を保存せずに変更を検出するため):
echo -n "DATABASE_URL:postgres://..." | sha256sum | awk '{print $1}'
または Python を使用します:
import hashlib
h = hashlib.sha256(f"{key}:{value}".encode()).hexdigest()
4. Vault 操作リファレンス
ローカル Vault は、暗号化されたキーと値のストレージを提供します。Infisical から同期されたすべてのシークレットはここに保存します。
| 操作 | 説明 |
|---|---|
vault_set key=K value=V | シークレット K を書き込む、または上書きする |
vault_get key=K | シークレット K を読み取る |
vault_list | すべてのキーを一覧表示する(値は返されません) |
vault_delete key=K | シークレット K を削除する |
一括同期のパターン:
// Pull from Infisical → vault
for each (key, value) in infisical_secrets:
vault_set key=<key> value=<value>
// Optionally remove orphans
vault_list → local_keys
infisical_keys = set of keys returned by Infisical
for key in local_keys - infisical_keys:
vault_delete key=<key>
5. セキュリティチェックリスト
同期のたびに、次の項目を確認してください:
-
INFISICAL_URLが設定され、空でない -
INFISICAL_CLIENT_IDが設定され、空でない -
INFISICAL_CLIENT_SECRETが設定され、空でない - アクセストークンがこのサイクルで新たに取得されている(サイクルをまたいで再利用しない)
- curl コマンドのエコー出力にシークレット値が表示されない(値を直接記述せず、変数を使用する)
- レスポンスボディをそのままログに記録しない(ログ記録の前に
secretValueフィールドを除去する)
6. よくある失敗パターン
「Failed to fetch secrets: 403 Forbidden」
Machine Identity は存在しますが、権限がありません。Infisical で以下を行ってください。
- Access Control → Machine Identities に移動します
- このエージェントの Identity を探します
- プロジェクトで
memberロール(読み取り専用の場合はviewer)を割り当てます
「Connection refused / Could not connect to server」
INFISICAL_URL が間違っているか、インスタンスが停止しています。URL にアクセスできることを確認してください。
curl -s "$INFISICAL_URL/api/status" | python3 -c "import sys,json; print(json.load(sys.stdin))"
「invalid character in secret name」
Infisical のシークレット名は [A-Z0-9_] に一致する必要があります。Vault に大文字と小文字が混在するキーがある場合は、プッシュする前に正規化してください。
echo "my_secret_key" | tr '[:lower:]' '[:upper:]'
「accessToken undefined in response」
認証に失敗しました。レスポンス本文にエラーメッセージが含まれています。以下を確認してください。
INFISICAL_CLIENT_IDとINFISICAL_CLIENT_SECRETが正しいこと- Infisical で Machine Identity が無効化されていないこと
- Machine Identity のトークン TTL が 0 に設定されていないこと
7. ナレッジグラフのエンティティ
値を公開せずに、フリート全体のシークレットのメタデータを追跡します。
エンティティの種類
service— Infisical インスタンス自体secret_project— Infisical のワークスペース/プロジェクトsecret— 名前付きシークレット(キーのみ。値は含みません)
関係の種類
secret→belongs_to→secret_projectsecret_project→hosted_by→servicesecret→synced_to→agent_vault
クエリの例
knowledge_query type=secret // list all known secrets
knowledge_query type=secret_project // list all projects
knowledge_query relation=belongs_to target=<project_id> // secrets in a project