@volcengine/agent-identity 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README-cn.md ADDED
@@ -0,0 +1,388 @@
1
+ # Agent Identity 插件
2
+
3
+ UserPool OIDC 登录、TIP (Trusted Identity Provider) 令牌(通过 Identity GetWorkloadAccessTokenForJWT 获取)、凭据 3LO(GetResourceOauth2Token/Oauth2Callback)以及 OpenClaw 的会话管理。
4
+
5
+ 集成 [火山引擎智能体身份和权限管理平台](https://www.volcengine.com/docs/86848)。术语映射:用户池 (UserPool)、入站授权 (OIDC login)、出站授权 (credential fetch)、工作负载令牌 (TIP)、凭据托管 (credential hosting)、权限管控 (CheckPermission)。
6
+
7
+ > For English documentation, see [README.md](README.md)
8
+
9
+ ## 功能特性
10
+
11
+ - **OIDC 登录**:`/identity login` 返回 IdP 授权 URL。用户打开 URL 后,IdP 重定向到 `/identity/oauth/callback`。
12
+ - **LLM 前置认证拦截(`before_dispatch`)**:在 LLM 调用前拦截未认证消息,节省 token 开销。直接在静态回复中返回 OIDC 登录 URL。在不支持 `before_dispatch` 的旧版 OpenClaw 上自动回退到 `before_agent_start`。
13
+ - **TIP 令牌**:`before_dispatch` / `before_agent_start` 钩子在会话中有已登录用户时获取 TIP 令牌。
14
+ - **凭据 3LO**:`/identity fetch <provider>` 返回授权 URL。IdP 重定向到 Identity 提供的回调地址(控制台配置)。
15
+ - **凭据绑定**:`/identity set <provider> <envVar>` 将存储的凭据绑定到环境变量。凭据按工具调用粒度安全注入,并发多用户会话之间互相隔离。
16
+ - **本地身份服务(UDS)**:可选的 HTTP-over-Unix-Domain-Socket 服务,将 TIP 令牌、OIDC 会话令牌及所有插件工具暴露给本地其他进程。支持 Linux `SO_PEERCRED` + `/proc` 进程级校验和可配置进程白名单。
17
+ - **加密会话存储**:`sessions.json` 使用 AES-256-GCM 加密存储在磁盘上。旧版明文文件首次加载时自动迁移。
18
+ - **内存 TIP 缓存**:TIP 令牌仅存储在内存中(不持久化到磁盘)。TIP 是短效令牌,可随时从用户 session token 重新获取。
19
+ - **动态 UserPool**:通过 `userPoolName` + `clientName` 解析 OIDC 配置(无需手动配置 clientId)。
20
+ - **凭证加载**:从环境变量、文件或 STS AssumeRole 加载 AK/SK(veadk 风格)。
21
+
22
+ ## HTTP 端点
23
+
24
+ 仅暴露 OIDC 登录回调。凭据 OAuth 使用 Identity 回调。其余逻辑在 slash 命令中执行。
25
+
26
+ | 路径 | 方法 | 描述 |
27
+ | -------------------------- | ---- | ------------------------- |
28
+ | `/identity/oauth/callback` | GET | OIDC 登录回调(IdP 重定向到此) |
29
+
30
+ ## Slash 命令
31
+
32
+ 单一命令 `/identity`(别名 `/id`)及其子命令。无参数时默认:`status`。
33
+
34
+ | 子命令 | 描述 |
35
+ | ------------------------------- | -------------------------------------------------------------------- |
36
+ | _(无)_ | 显示帮助。 |
37
+ | `whoami` | 显示当前会话身份(sub、TIP 状态)。 |
38
+ | `login` | 已登录:刷新 TIP。未登录:返回需打开的 OIDC IdP URL。 |
39
+ | `status` | 登录状态、TIP、凭据。会话存在时尝试刷新 TIP。 |
40
+ | `logout` | 清除当前会话的 session 和 TIP。 |
41
+ | `list-tips` | 列出所有有效 TIP 令牌及其委托链、过期时间和环境变量绑定。 |
42
+ | `config` | 显示 identity 插件配置(敏感信息脱敏)。 |
43
+ | `list-credentials` 或 `list [page]` | 分页列出控制台 provider 及已绑定的凭据。使用 `list 2` 加载更多。 |
44
+ | `list-roles` | 列出 STS 角色类凭据提供方(非 OAuth/API key)。可选按名称前缀过滤。 |
45
+ | `get-role <provider> [--use-tip] [--show-secrets]` | 获取某角色提供方的 STS 临时凭据(默认脱敏)。 |
46
+ | `fetch <provider> [--flow=...]` | 添加凭据。flow 根据 provider 类型自动推断;可用 `--flow` 覆盖。 |
47
+ | `set <provider> <envVar>` | 将凭据绑定到环境变量供工具注入。无凭据时从 `process.env[envVar]` 导入。 |
48
+ | `unset <provider>` | 移除 provider 的环境变量绑定。 |
49
+
50
+ ## OIDC 登录流程
51
+
52
+ 1. 用户在聊天中发送 `/identity login`(如 Telegram、Discord)
53
+ 2. 命令根据 channel/sender 推导 sessionKey,构建 IdP 授权 URL,保存 state
54
+ 3. 命令返回 IdP URL,用户在浏览器中打开
55
+ 4. 用户在 UserPool IdP 完成登录
56
+ 5. IdP 携带 `code` 和 `state` 重定向到 `/identity/oauth/callback`
57
+ 6. 插件交换 code,创建会话,显示成功页并向聊天发送消息
58
+
59
+ ## 凭据获取流程
60
+
61
+ **OAuth2(用户联邦或 M2M):**
62
+
63
+ 1. 用户发送 `/identity fetch google` 或 `/identity fetch google --flow=oauth2-m2m`(在 `/identity login` 之后)
64
+ 2. 命令使用 TIP 调用 Identity API,返回授权 URL 或直接返回 token
65
+ 3. 若有授权 URL:用户打开,IdP 重定向到 Identity 回调(控制台 provider 配置)
66
+ 4. Identity 处理回调,获取 token;用户可再次执行 fetch 拉取凭据
67
+
68
+ **API Key:**
69
+
70
+ 1. 用户发送 `/identity fetch openai`(控制台 provider 类型为 api_key)或 `/identity fetch openai --flow=apikey`
71
+ 2. 命令使用 TIP 调用 GetResourceApiKey,直接存储 API key
72
+
73
+ flow 根据 ListCredentialProviders 的 Type 和 Flow 自动推断。可通过 `--flow=oauth2-user|oauth2-m2m|apikey` 覆盖。
74
+
75
+ ## 开通火山引擎 Agent Identity 服务
76
+
77
+ 使用本插件前,需先在火山引擎开通 **智能体身份和权限管理平台** 并完成授权。详见:
78
+
79
+ - [开通智能体身份和权限管理平台并完成授权](https://www.volcengine.com/docs/86848/2123358?lang=zh)
80
+
81
+ ## 获取火山引擎 AK/SK
82
+
83
+ 插件调用 Identity API 需要火山引擎访问密钥(Access Key / Secret Key)。获取方式:
84
+
85
+ - [创建 Access Key - 火山引擎文档](https://www.volcengine.com/docs/6291/65568?lang=zh)
86
+
87
+ 在控制台创建 AK/SK 后,可通过配置传入,或使用环境变量 `VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`。
88
+
89
+ ## 安装
90
+
91
+ ```bash
92
+ openclaw plugins install @m1a0rz/agent-identity
93
+ ```
94
+
95
+ 开发模式(link):
96
+
97
+ ```bash
98
+ openclaw plugins install --link .
99
+ ```
100
+
101
+ ## 配置
102
+
103
+ ### 步骤二:配置插件(最小可用配置)
104
+
105
+ 插件通常需要三类配置:
106
+
107
+ **A. 平台侧访问配置(Identity)**:用于获取 TIP Token、拉取/托管凭据、做权限校验(可选)。
108
+
109
+ - `endpoint`(可选):Identity API 根地址(例如 `https://id.cn-beijing.volcengineapi.com`)。**优先级最高**。
110
+ - `regionMetadataUrl`(可选):返回 **纯文本 region id**(如 `cn-beijing`)的 HTTP(S) URL。仅当 **未配置 `endpoint`** 时使用:客户端拼接 `https://id.{region}.volcengineapi.com`。单次请求约 10s 超时;失败或正文无效(如 `unknown`)时回退到 `https://id.cn-beijing.volcengineapi.com`。示例:`http://100.96.0.96/latest/region_id`(需网关能访问)。
111
+ - `accessKeyId` / `secretAccessKey`:用于访问 Identity API。**可选**,可使用环境变量或凭据文件(见下)。
112
+ - `workloadPoolName` / `workloadName`:用于签发 TIP Token。默认:`default`、`openclaw-agent`。
113
+ - `audience` / `durationSeconds`:可选,令牌受众与有效期。
114
+ - `credentialsFile`:凭据 JSON 文件路径。默认:`VOLCENGINE_CREDENTIALS_FILE` 环境变量或 `/var/run/secrets/iam/credential`。
115
+ - `credentialsMetadataUrl`:远程凭据拉取的完整 URL。与 `roleTrn` 同时配置时,从 URL 拉取(响应:`AccessKeyId`、`SecretAccessKey`、`SessionToken`),再用 `roleTrn` 做 AssumeRole 获取最终凭据。流程与 AK/SK + roleTrn 一致。404 时回退到凭据文件。按 ExpiredTime 缓存。需显式配置。
116
+ - `roleTrn`:STS AssumeRole 的 Role TRN。设置后(且未设置 `workloadName`)不传 workload name,后端使用 roleName。优先级:`workloadName` > `roleTrn` > params。与 `credentialsMetadataUrl` 配合时用于 AssumeRole,或与显式 AK/SK 配合。
117
+ - `sessionToken`:STS 会话令牌(或使用 `VOLCENGINE_SESSION_TOKEN` 环境变量)。
118
+
119
+ **Identity API 地址解析**:已配置 `endpoint` → 否则用 `regionMetadataUrl` 拉取 region 拼接 URL → 否则 `https://id.cn-beijing.volcengineapi.com`。**SigV4 签名用 region** 从解析后的主机名匹配 `id.{region}.volcengineapi.com` 推断;否则为 `cn-beijing`。
120
+
121
+ **工作负载池(凭据 / STS)**:`workloadPoolName`(默认 `default`)用于限定 `ListCredentialProviders`、`ListRoleCredentialProviders` 以及 `GetResourceOauth2Token`、`GetResourceApiKey`、`GetUserCredential`、`GetRoleCredentials` 等接口的 `PoolName`。若配置了 `userpool.userPoolName`,角色提供方列表还会在客户端按用户池再过滤。
122
+
123
+ **凭据解析顺序**(AK/SK):1)显式 config → 2)环境变量(`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`)→ 3)远程元数据(`credentialsMetadataUrl` + `roleTrn`,从完整 URL 拉取后做 AssumeRole;404 时回退)→ 4)凭据文件(config 的 `credentialsFile`,或 `VOLCENGINE_CREDENTIALS_FILE` 环境变量,或 `/var/run/secrets/iam/credential`)。凭据文件格式(VeFaaS):`access_key_id`、`secret_access_key`、`session_token`(可选)、`role_trn`(可选,用于 AssumeRole)。`RUNTIME_IAM_ROLE_TRN` 环境变量可在从文件加载时提供 role TRN。
124
+
125
+ **B. 用户登录配置(UserPool / OIDC)**:用于 `/identity login` 的用户登录与会话建立。
126
+
127
+ - `discoveryUrl`(或 `userPoolName` + `clientName` 动态解析模式)
128
+ - `clientId` / `clientSecret`(动态模式下可自动解析)
129
+ - `callbackUrl`:OpenClaw 网关对外可访问的回调地址,例如 `http://127.0.0.1:18789/identity/oauth/callback`
130
+ - `scope`:一般包含 `openid profile email`
131
+ - `identityProvider`(可选):授权 URL 中 `identity_provider` 对应的 IdP 名称;不填则使用 `ListIdentityProviders` 返回的第一条。
132
+ - `useRelayCallback`(可选):经 UserPool relay / `redirect_relay_uri` 的 OIDC 回调流程。默认 false。
133
+
134
+ **C. 权限校验与风险审批(AuthZ,可选)**:用于 TIP + CheckPermission + 风险评估与用户审批。各开关独立,无统一 `enable`。
135
+
136
+ - `agentCheck`:在 `before_agent_start` 中对 agent 执行 CheckPermission(resource type agent)。校验已认证用户是否有权限调用当前 agent。使用 TIP 委托链最外层 actor 作为 resource id。默认 false。
137
+ - `toolCheck`:对工具调用执行 CheckPermission(resource type tool)。默认 false。
138
+ - `skillReadCheck`:对 SKILL.md 读取执行 CheckPermission(resource type skill)。解析 system prompt 中的 available_skills。默认 false。
139
+ - `requireRiskApproval`:高风险工具调用需用户审批。默认 false。
140
+ - `namespaceName`:CheckPermission Cedar 策略命名空间。默认 `default`。
141
+ - `lowRiskBypass`:内置低风险工具是否跳过 TIP+CheckPermission。默认 true。
142
+ - `lowRiskTools`:额外视为低风险的工具名列表。
143
+ - `enableLlmRiskCheck`:规则返回 medium 时是否用 LLM 二次评估。默认 false。
144
+ - `llmRiskCheck`:LLM 配置(`endpoint`、`api`、`model`、`apiKey`、`timeoutMs`、`cacheTtlMs`)。`enableLlmRiskCheck` 为 true 时必填。
145
+ - `approvalTtlSeconds`:审批链接/命令的 TTL(秒)。默认 300。
146
+
147
+ **预期结果**:配置完成后,插件可正常发起登录、获取 TIP Token。开启 AuthZ 相关开关后,agent/工具/skill 权限检查与高风险审批生效。高风险工具调用通过 OpenClaw 原生 `requireApproval` 机制处理(UI 覆层、Telegram 按钮、Discord 交互、`/approve` CLI)。
148
+
149
+ ---
150
+
151
+ 在 `openclaw.json` 的 `plugins.entries.agent-identity.config` 下添加:
152
+
153
+ ```json
154
+ {
155
+ "plugins": {
156
+ "entries": {
157
+ "agent-identity": {
158
+ "config": {
159
+ "identity": {
160
+ "endpoint": "https://id.cn-beijing.volcengineapi.com",
161
+ "workloadPoolName": "default",
162
+ "workloadName": "openclaw-agent"
163
+ },
164
+ "userpool": {
165
+ "discoveryUrl": "https://userpool-xxx.userpool.auth.id.cn-beijing.volces.com",
166
+ "clientId": "<client-id>",
167
+ "clientSecret": "<client-secret>",
168
+ "callbackUrl": "https://gateway.example.com/identity/oauth/callback",
169
+ "scope": "openid profile email"
170
+ },
171
+ "authz": {
172
+ "agentCheck": false,
173
+ "toolCheck": false,
174
+ "skillReadCheck": false,
175
+ "requireRiskApproval": false,
176
+ "namespaceName": "default",
177
+ "lowRiskBypass": true,
178
+ "enableLlmRiskCheck": false,
179
+ "approvalTtlSeconds": 300
180
+ },
181
+ "localServer": false,
182
+ "localServerAllowlist": [],
183
+ "localServerFailOpen": true
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ **Identity 凭据**:省略 `accessKeyId`/`secretAccessKey` 时,使用环境变量(`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`)或凭据文件(`VOLCENGINE_CREDENTIALS_FILE` 或 `/var/run/secrets/iam/credential`)。
192
+
193
+ ### identity 配置(必填与可选)
194
+
195
+ | 参数 | 类型 | 必填 | 含义 |
196
+ |------|------|------|------|
197
+ | `endpoint` | string | 否 | Identity API 根地址。不填则通过 `regionMetadataUrl` 或默认 `https://id.cn-beijing.volcengineapi.com` |
198
+ | `regionMetadataUrl` | string | 否 | 返回纯文本 region 的 URL;在未配置 `endpoint` 时拼接 `https://id.{region}.volcengineapi.com` |
199
+ | `accessKeyId` | string | 否* | 火山引擎 Access Key。不填时从 `VOLCENGINE_ACCESS_KEY` 或 `credentialsFile` 读取 |
200
+ | `secretAccessKey` | string | 否* | 火山引擎 Secret Key。不填时从 `VOLCENGINE_SECRET_KEY` 或 `credentialsFile` 读取 |
201
+ | `workloadPoolName` | string | 否 | 工作负载池名称,默认 `default` |
202
+ | `workloadName` | string | 否 | 工作负载名称。设置时优先于 roleTrn。两者都未设置时默认:agentId 或 `openclaw-agent` |
203
+ | `audience` | string[] | 否 | TIP token 的 audience |
204
+ | `durationSeconds` | number | 否 | TIP token 有效期(秒),默认 3600 |
205
+ | `roleTrn` | string | 否 | STS AssumeRole 的 Role TRN。设置后(且未设置 workloadName)不传 workload name,后端使用 roleName。优先级:workloadName > roleTrn > params |
206
+ | `credentialsFile` | string | 否 | 凭证 JSON 文件路径。默认 `VOLCENGINE_CREDENTIALS_FILE` 或 `/var/run/secrets/iam/credential` |
207
+ | `credentialsMetadataUrl` | string | 否 | 远程凭据拉取的完整 URL。与 `roleTrn` 同时配置时拉取后做 AssumeRole。404 时回退到 `credentialsFile` |
208
+ | `sessionToken` | string | 否 | STS 临时会话令牌(或 `VOLCENGINE_SESSION_TOKEN`) |
209
+ | `subagentTipPropagation` | boolean | 否 | 将 TIP 和 session 传播到子 agent。默认 false |
210
+ | `webchatSessionExchange` | boolean | 否 | 启用 `identity.session.put` / `identity.session.get` gateway WS 方法供 webchat 客户端使用。默认 false |
211
+ | `personalSessionMode` | boolean | 否 | 个人/单用户模式:TIP、OIDC session、凭据仅存储在 `agent:main:main`(不做按发送者或 per-channel-peer 隔离)。子 agent 会话不变。默认 false;多租户或群聊共享场景勿开启。 |
212
+ | `localServer` | boolean | 否 | 启用本地 UDS 身份服务。默认 false。详见[本地身份服务(UDS)](#本地身份服务uds)。 |
213
+ | `localServerAllowlist` | string[] | 否 | 额外允许访问 UDS 服务的进程名/路径。`curl` 始终允许。 |
214
+ | `localServerFailOpen` | boolean | 否 | 无法识别对端进程时是否放行。默认 true。 |
215
+
216
+ \* AK/SK 至少通过 `accessKeyId`+`secretAccessKey`、环境变量、`credentialsMetadataUrl`+`roleTrn` 或 `credentialsFile` 之一提供。
217
+
218
+ **环境变量**:`VOLCENGINE_ACCESS_KEY`、`VOLCENGINE_SECRET_KEY`、`VOLCENGINE_SESSION_TOKEN`、`VOLCENGINE_CREDENTIALS_FILE`、`RUNTIME_IAM_ROLE_TRN`(从文件加载时用于 AssumeRole)。设置 `IDENTITY_STS_DEBUG=1` 可打印完整 STS AssumeRole 请求/响应用于调试。
219
+
220
+ ### userpool 配置(OIDC 登录)
221
+
222
+ **Explicit 模式**(必填):`discoveryUrl`、`clientId`、`clientSecret`、`callbackUrl`、`scope`
223
+
224
+ **Dynamic 模式**(必填):`userPoolName`、`clientName`、`callbackUrl`;`autoCreate` 默认 true
225
+
226
+ OAuth2 credential fetch 使用控制台配置的 redirect URL 和 scopes。可通过 `/identity fetch <provider> --redirectUrl` 和 `--scopes` 覆盖。
227
+
228
+ ### authz 配置(可选,各开关独立)
229
+
230
+ | 参数 | 类型 | 含义 |
231
+ |------|------|------|
232
+ | `agentCheck` | boolean | 在 `before_agent_start` 中对 agent 执行 CheckPermission(resource type agent)。校验用户是否有权限调用当前 agent,使用 TIP 委托链最外层 actor 作为 resource id。默认 false。 |
233
+ | `toolCheck` | boolean | 对工具调用执行 CheckPermission(resource type tool)。默认 false。 |
234
+ | `skillReadCheck` | boolean | 对 SKILL.md 读取执行 CheckPermission(resource type skill)。默认 false。 |
235
+ | `requireRiskApproval` | boolean | 高风险工具调用需用户审批。默认 false。 |
236
+ | `namespaceName` | string | CheckPermission Cedar 命名空间。默认 `default`。 |
237
+ | `lowRiskBypass` | boolean | 内置低风险工具是否跳过 TIP+CheckPermission。默认 true。 |
238
+ | `lowRiskTools` | string[] | 额外视为低风险的工具名列表。 |
239
+ | `enableLlmRiskCheck` | boolean | 规则返回 medium 时用 LLM 二次评估。默认 false。 |
240
+ | `llmRiskCheck` | object | LLM 配置:`endpoint`、`api`、`model` 等。`enableLlmRiskCheck` 为 true 时必填。 |
241
+ | `approvalTtlSeconds` | number | 审批 TTL(秒)。默认 300。 |
242
+
243
+ ### 工作负载与 TIP
244
+
245
+ TIP token 通过 `GetWorkloadAccessTokenForJWT` 获取。工作负载行为:
246
+
247
+ - **workloadName**(可选):发送给 API 的工作负载名称。优先级:config.workloadName > config.roleTrn > params(会话 agentId 或 `"openclaw-agent"`)。当 config.workloadName 设置时,优先于 roleTrn。
248
+ - **roleTrn**(可选):设置后(且未设置 workloadName),插件**不**传递 workload name,后端使用 roleName。用于委托执行(如 VeFaaS、K8s IRSA)。
249
+ - **自动创建工作负载**:当 `GetWorkloadAccessTokenForJWT` 返回 404(工作负载不存在)时,插件调用 `CreateWorkloadIdentity` 创建工作负载(Category: Agent),然后重试。仅在使用 workload name 时生效(设置了 workloadName 或两者都未设置)。并发创建产生的 Duplicated (409) 会被忽略。
250
+
251
+ ### 飞书通知
252
+
253
+ 当用户从飞书聊天运行 `/identity` 时,登录成功和凭据获取的跟进消息会通过飞书发送。凭据从 openclaw.json 的 `channels.feishu` 读取(与 feishu 扩展相同:`appId`、`appSecret`,可选 `accounts`)。agent-identity 无需额外配置。
254
+
255
+ **审批消息**(当高风险工具被拦截时):插件从 `before_tool_call` 返回 `requireApproval`,OpenClaw 框架在所有渠道原生处理审批 UI(exec 覆层、Telegram 按钮、Discord 交互、`/approve` CLI)。无需插件侧推送逻辑。
256
+
257
+ ### WebChat Session Exchange(Gateway WS 方法)
258
+
259
+ 当 `identity.webchatSessionExchange` 为 `true` 时,插件注册两个 gateway WebSocket 方法,允许 webchat 客户端直接注入和获取 session token,无需走 OIDC 重定向流程:
260
+
261
+ | 方法 | 参数 | 响应 | 描述 |
262
+ | --- | --- | --- | --- |
263
+ | `identity.session.put` | `{ sessionKey, idToken, refreshToken?, senderId?, channel? }` | `{ sub, expiresAt, effectiveSessionKey, hasTip }` | 将 OIDC id_token 注入到插件 session;可选传入 `refreshToken`(加密存储),用于静默续期。通过 `buildEffectiveSessionKey` 解析实际存储 key(与 hooks/commands 相同的隔离逻辑)。 |
264
+ | `identity.session.get` | `{ sessionKey, senderId?, channel? }` | `{ userToken, sub, expiresAt, effectiveSessionKey, hasRefreshToken }` | 获取指定 session 已存储的 user token。`hasRefreshToken` 表示是否存有 refresh token;响应中不会返回 refresh token 明文。 |
265
+
266
+ - `senderId` 默认值为 `"openclaw-control-ui"`。对于 main session,实际存储 key 为 `agent:main:main:user:<senderId>`。
267
+ - `channel` 可选;当 session 来源于可发送消息的渠道(feishu、telegram 等)时传入,可启用 per-channel-peer key 提升。
268
+
269
+ 两个方法均**限制为 webchat WS 连接**(`isWebchatConnect` 检查),非 webchat 客户端会收到 `FORBIDDEN` 错误。
270
+
271
+ **配置:**
272
+
273
+ ```json
274
+ {
275
+ "identity": {
276
+ "webchatSessionExchange": true
277
+ }
278
+ }
279
+ ```
280
+
281
+ **典型流程(BFF → webchat → plugin):**
282
+
283
+ 1. BFF 完成 3LO 登录并获取用户的 OIDC `id_token`
284
+ 2. Webchat 客户端调用 `identity.session.put`,传入 session key 和 `id_token`(若需静默续期,可一并传入 token 响应中的 `refresh_token` 作为 `refreshToken`)
285
+ 3. 插件校验 token,存储 session,并获取 TIP
286
+ 4. 后续该 session 中的 agent 运行拥有有效身份——无需手动登录
287
+
288
+ ### WebChat / TUI
289
+
290
+ 用户从 WebChat 或 TUI 运行 `/identity` 时,跟进消息不会投递;插件无 API 推送至这些渠道。请使用 `/identity status` 确认结果。
291
+
292
+ ## 工具
293
+
294
+ 面向 Agent 的用法见 [`skills/SKILL.md`](skills/SKILL.md)。本插件注册的工具有:
295
+
296
+ - **identity_whoami** — 会话身份(sub、TIP)
297
+ - **identity_status** — 登录、TIP、凭据、绑定
298
+ - **identity_login** / **identity_logout** — OIDC 登录或刷新 TIP;清除会话
299
+ - **identity_list_credentials** — OAuth/API key 类 provider 与已存凭据(支持 `page`、`name`、`flow`、`type` 过滤)
300
+ - **identity_list_roles** — STS 角色类凭据提供方(`name` 前缀过滤)
301
+ - **identity_fetch** — 添加凭据(`provider`、`flow`、`redirectUrl`、`scopes`、`returnValue`)
302
+ - **identity_get_role_credentials** — 某角色提供方的 STS 临时凭据(`providerName`、`useTip`)
303
+ - **identity_get_tip_token** / **identity_get_session_token** — 原始 TIP JWT 或会话 user token(进阶场景)
304
+ - **identity_config** — 当前生效配置(脱敏)
305
+ - **identity_config_suggest** — 可合并的配置片段(`intent`、`lang`)
306
+ - **identity_set_binding** / **identity_unset_binding** — 工具注入用的环境变量绑定
307
+ - **identity_risk_check** / **identity_list_risk_patterns** — 风险评估(可选插件能力)
308
+ - **identity_list_tips** — 所有有效 TIP 与绑定(运维 / 多会话排查)
309
+
310
+ ## 钩子
311
+
312
+ - **before_dispatch** - 无状态 LLM 前置认证拦截。在 LLM 调用前检查 TIP 令牌是否有效。未找到 TIP 时,以静态回复(包含 OIDC 登录 URL)阻断消息,LLM 零 token 消耗。开启 `authz.agentCheck` 后同时执行 agent 级 CheckPermission。设置特性标志使 `before_agent_start` 跳过冗余认证逻辑。
313
+ - **before_agent_start** - 面向不支持 `before_dispatch` 的旧版 OpenClaw 的回退认证拦截。当 `before_dispatch` 活跃时,此钩子的认证逻辑为空操作。仍负责获取 TIP 令牌和执行 agent CheckPermission。
314
+ - **subagent_spawned** - 在子 agent 创建时将 TIP 传播到子会话。
315
+ - **before_tool_call** - 群组上下文注入、可选 AuthZ(TIP 检查、CheckPermission、通过 `requireApproval` 处理风险审批)、工具调用级凭据注入。高风险工具调用返回 `requireApproval` 给 OpenClaw 框架,由框架原生处理审批 UI。
316
+ - **after_tool_call** - 清理工具调用级凭据注入状态。
317
+
318
+ ## 本地身份服务(UDS)
319
+
320
+ 当 `identity.localServer` 为 `true` 时,插件启动一个基于 Unix Domain Socket 的 HTTP 服务,允许本地其他进程(脚本、插件、CLI 工具)访问身份令牌和执行插件工具,无需经过 OpenClaw 消息通道。
321
+
322
+ ### 配置
323
+
324
+ | 参数 | 类型 | 描述 |
325
+ |------|------|------|
326
+ | `localServer` | boolean | 启用本地 UDS 服务。默认 false。 |
327
+ | `localServerAllowlist` | string[] | 额外允许连接的进程名或路径。支持精确匹配和 glob 后缀(如 `"python*"`)。`curl` 默认始终允许。 |
328
+ | `localServerFailOpen` | boolean | 无法识别对端进程时,是否允许连接(依赖 0600 socket 权限兜底)。默认 true。设为 false 为严格模式。 |
329
+
330
+ **Socket 路径**:`~/.openclaw/plugins/identity/identity.sock`(权限 `0600`,仅 owner 可访问)。
331
+
332
+ ### 端点
333
+
334
+ | 方法 | 路径 | 描述 |
335
+ |------|------|------|
336
+ | `GET` | `/token` | 主会话的 TIP 令牌 |
337
+ | `GET` | `/token?session=<key>` | 指定会话的 TIP 令牌 |
338
+ | `GET` | `/session` | 主会话的 OIDC session(id_token) |
339
+ | `GET` | `/status` | 服务健康状态与可用会话概览 |
340
+ | `GET` | `/tools` | 列出所有可用工具名称、描述及 JSON Schema |
341
+ | `POST` | `/tool/<name>` | 执行指定工具。Body:`{ "params": {...}, "session": "..." }` |
342
+
343
+ ### 进程级校验(Linux)
344
+
345
+ 在 Linux 上,服务通过以下方式校验连接进程:
346
+
347
+ 1. **`SO_PEERCRED`**(内核级):通过 `getsockopt` 零开销获取对端 PID/UID/GID。需注册原生 provider。
348
+ 2. **`/proc` 文件系统**:从 `/proc/<pid>/exe`、`/proc/<pid>/comm`、`/proc/<pid>/status` 获取进程名和路径,无需 spawn 外部进程。
349
+
350
+ 解析后的进程信息与内置白名单(`curl`)及 `localServerAllowlist` 自定义条目做匹配。当 `localServerFailOpen` 为 true(默认)时,无法识别的对端将被放行(socket 文件权限提供基础安全保障)。
351
+
352
+ ### 使用示例
353
+
354
+ ```bash
355
+ # 获取 TIP 令牌
356
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/token
357
+
358
+ # 获取 OIDC session 令牌
359
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/session
360
+
361
+ # 列出可用工具
362
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock http://localhost/tools
363
+
364
+ # 执行工具
365
+ curl --unix-socket ~/.openclaw/plugins/identity/identity.sock \
366
+ -X POST http://localhost/tool/identity_whoami \
367
+ -H 'Content-Type: application/json' \
368
+ -d '{"params": {}, "session": ""}'
369
+ ```
370
+
371
+ 更多语言示例见 [`demo/local-server/`](demo/local-server/)(Python、Go、TypeScript、Java、Rust)。
372
+
373
+ ## 数据存储
374
+
375
+ 插件数据位于 `~/.openclaw/plugins/identity/`:
376
+
377
+ | 文件 | 描述 |
378
+ |------|------|
379
+ | `sessions.json` | 加密存储的 sessionKey → userToken 映射。加载/保存时清理过期条目。 |
380
+ | `credential-env-bindings.json` | 按 session:`{ [sessionKey]: { [provider]: envVar } }` |
381
+
382
+ **仅内存存储(不持久化到磁盘):**
383
+
384
+ | 数据 | 描述 |
385
+ |------|------|
386
+ | TIP 令牌 | sessionKey → TIP token 缓存。短效,按需从 session token 重新获取。 |
387
+ | 凭据 | 按 session(api_key、oauth2)。gateway 重启后丢失;logout 时清除。 |
388
+ | OIDC state | 临时数据,5 分钟 TTL。 |