关于 infisical-sync-skill
面向使用 Infisical 的 Agent,提供密钥同步的 API 操作、安全检查和状态追踪参考。涵盖认证、密钥管理、错误处理及本地加密 vault 操作。
主要功能
- 01Universal Auth 认证流程
- 02密钥列表、创建、更新与删除
- 03同步状态与哈希追踪
- 04加密 vault 操作参考
- 05安全检查与故障排查
适用场景
- 01将 Infisical 密钥同步到本地 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 使用 Machine Identities,通过 Universal Auth 进行 Agent 到 Agent 的通信。
端点: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 | 禁止访问 | Machine identity 缺少权限——检查 Infisical 访问控制 |
| 404 | 未找到 | 密钥或项目不存在 |
| 429 | 请求过多 | 等待 60 秒后重试一次 |
| 500/503 | 服务器错误 | 记录日志,并在 30 秒后重试一次;如果仍然失败则通知 |
在信任响应正文之前,始终检查 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
- 找到此 Agent 的身份
- 为其分配项目的
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_]。如果密钥库中有大小写混合的键,请在推送前将其规范化:
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