8.6 KiB
ql3-identity 本机 Identity/Credential 管理
ql3-identity 是一次命令、一次进程的 Owner-only 管理入口。它不启动管理服务,也不把
credential token 写入 argv、stdout、stderr、command JSON 或 SQLite。
前置条件
- 已完成 Fresh Setup,当前 credential 属于
defaultProject 的 active Owner; - deployment root、其子目录、SQLite、Owner credential presentation 与 command file 均由当前 real/effective UID 拥有;
- 目录权限为
0700,文件权限为0600; - Owner pepper keyring 中存在与 SQLite active pepper 完全匹配的材料;
- managed credential delivery 使用独立、规范化、非 symlink 的
0700目录。
实例 Authority Project
Identity 与 API credential 是实例级对象,不属于任意单个业务 Project。
ql3-identity 只接受实例 authority Project 的当前 Owner:
- 新部署以全库最早成功消费的 Owner bootstrap challenge 所属 Project 为 authority;
- 没有任何 consumed bootstrap challenge 的旧库兼容回退到迁移内建的
default; - 后续给其他 Project 授予 Owner 不会转移该 authority;
- secondary Project Owner 使用自己的
projectId调用时,返回统一 authorization error,并记录instance_authority_project_required; - 当前没有 authority Project 转移命令,不要通过直接编辑数据库模拟转移。
command 中的 projectId 必须填写该 authority Project。它会在服务授权和最终 SQLite
事务各验证一次;直接调用 repository 不能绕过。
所有示例中的 UUID、subject 和路径都必须替换。command file 创建完成后执行:
ql3-identity run --command-file /srv/qinglong3/commands/identity.json
查询当前版本
后续 mutation 所需的 expectedCurrentVersion 必须通过受支持的 inspect 命令取得,
不要直接查询 SQLite。Identity 精确查询示例:
{
"schemaVersion": 1,
"operation": "identity.inspect",
"options": {
"deploymentRoot": "/srv/qinglong3",
"databasePath": "/srv/qinglong3/qinglong3.sqlite",
"profile": "edge",
"ownerPepperKeyringDirectory": "/srv/qinglong3/owner-keys",
"credentialFilePath": "/srv/qinglong3/owner-credential.json"
},
"request": {
"projectId": "default",
"target": { "type": "agent", "id": "agent-planner" },
"requestId": "identity-inspect-agent-planner",
"auditEventId": "10111111-1111-4111-8111-111111111111"
}
}
Credential 精确查询把 operation 改为 credential.inspect,request 改为:
{
"projectId": "default",
"credentialId": "agent-planner-primary",
"requestId": "credential-inspect-agent-planner",
"auditEventId": "10222222-2222-4222-8222-222222222222"
}
成功命中只返回 subject、status/state、version 和时间窗;不存在返回:
{
"schemaVersion": 1,
"operation": "credential.inspect",
"projectId": "default",
"found": false
}
found:false 只会在 Owner authorization 与事务内 credential/Project/RoleBinding
围栏全部通过后返回。输出不会包含 secret digest、pepper key ID、token、数据库路径
或交付路径。每次人工查询使用新的 auditEventId;inspect 不是 mutation,也不使用
mutationId、failureAuditEventId 或 expectedCurrentVersion。
注册 Identity
{
"schemaVersion": 1,
"operation": "identity.register",
"options": {
"deploymentRoot": "/srv/qinglong3",
"databasePath": "/srv/qinglong3/qinglong3.sqlite",
"profile": "edge",
"ownerPepperKeyringDirectory": "/srv/qinglong3/owner-keys",
"credentialFilePath": "/srv/qinglong3/owner-credential.json"
},
"request": {
"projectId": "default",
"target": { "type": "agent", "id": "agent-planner" },
"expectedCurrentVersion": 0,
"mutationId": "11111111-1111-4111-8111-111111111111",
"requestId": "identity-register-agent-planner",
"failureAuditEventId": "11111111-1111-4111-8111-111111111112"
}
}
identity.enable 和 identity.disable 使用相同结构,并把
expectedCurrentVersion 设为当前 Identity version。仍有 active Owner binding 的
User Identity 不能被禁用。
签发或轮换 Credential
{
"schemaVersion": 1,
"operation": "credential.issue",
"options": {
"deploymentRoot": "/srv/qinglong3",
"databasePath": "/srv/qinglong3/qinglong3.sqlite",
"profile": "edge",
"ownerPepperKeyringDirectory": "/srv/qinglong3/owner-keys",
"credentialFilePath": "/srv/qinglong3/owner-credential.json",
"credentialDeliveryDirectory": "/srv/qinglong3/managed-credentials"
},
"request": {
"projectId": "default",
"target": { "type": "agent", "id": "agent-planner" },
"credentialId": "agent-planner-primary",
"expectedCurrentVersion": 0,
"lifetimeMs": 86400000,
"mutationId": "22222222-2222-4222-8222-222222222221",
"requestId": "credential-issue-agent-planner",
"failureAuditEventId": "22222222-2222-4222-8222-222222222222"
}
}
轮换时把 operation 改为 credential.rotate,并使用当前 credential version。
lifetimeMs 范围为 60 秒至两年。
成功输出示例:
{
"schemaVersion": 1,
"operation": "credential.issue",
"status": "inserted",
"projectId": "default",
"target": { "type": "agent", "id": "agent-planner" },
"credentialId": "agent-planner-primary",
"version": 1,
"state": "active",
"expiresAtMs": 1780000000000,
"delivery": {
"fileName": "managed-credential-22222222-2222-4222-8222-222222222221.ready.json",
"digest": "64-char-lowercase-sha256"
}
}
输出没有绝对路径和 token。ready 文件位于 command 指定的 delivery directory,
权限为 0600,其 JSON 可以直接作为后续 credentialFilePath。如果 CLI 在 commit
后中断,必须原样重放同一个 command;不要更换 mutation、request、target、version
或 lifetime。
确认交付
consumer 已复制、安装并真实验证 ready credential 后,提交确认:
{
"schemaVersion": 1,
"operation": "credential.delivery.acknowledge",
"options": {
"deploymentRoot": "/srv/qinglong3",
"databasePath": "/srv/qinglong3/qinglong3.sqlite",
"profile": "edge",
"ownerPepperKeyringDirectory": "/srv/qinglong3/owner-keys",
"credentialFilePath": "/srv/qinglong3/owner-credential.json",
"credentialDeliveryDirectory": "/srv/qinglong3/managed-credentials"
},
"request": {
"projectId": "default",
"credentialMutationId": "22222222-2222-4222-8222-222222222221",
"expectedDeliveryDigest": "replace-with-issue-output-digest",
"mutationId": "33333333-3333-4333-8333-333333333331",
"requestId": "credential-delivery-ack-agent-planner",
"failureAuditEventId": "33333333-3333-4333-8333-333333333332"
}
}
数据库 acknowledgement 先提交,随后 pending/ready 文件才删除。响应丢失时原样
重放;cleanup:"absent" 表示数据库已经确认且文件已在前一次执行中安全删除。
不要在 consumer 尚未验证前 acknowledge,也不要把唯一正在用于本命令认证的 credential presentation 提前删除。
撤销 Credential
credential.revoke 不需要 delivery directory 或 lifetime:
{
"schemaVersion": 1,
"operation": "credential.revoke",
"options": {
"deploymentRoot": "/srv/qinglong3",
"databasePath": "/srv/qinglong3/qinglong3.sqlite",
"profile": "edge",
"ownerPepperKeyringDirectory": "/srv/qinglong3/owner-keys",
"credentialFilePath": "/srv/qinglong3/owner-credential.json"
},
"request": {
"projectId": "default",
"target": { "type": "agent", "id": "agent-planner" },
"credentialId": "agent-planner-primary",
"expectedCurrentVersion": 1,
"mutationId": "44444444-4444-4444-8444-444444444441",
"requestId": "credential-revoke-agent-planner",
"failureAuditEventId": "44444444-4444-4444-8444-444444444442"
}
}
撤销 Owner 当前使用的 credential 前,必须先签发并验证另一把有效 credential。 数据库会拒绝撤销 active Owner 的最后一把凭据。
运维规则
- 先使用 exact inspect 取得当前 version,再创建 mutation command;不要把数据库表当作 产品 API;
- command file 是不可变 mutation 载体;响应不确定时只允许原样重放;
- 不编辑 pending/ready 文件,不按 mtime 自动清理;
mutation_conflict表示相同 mutation ID 已用于不同语义,必须人工调查;owner_continuity_required表示操作会造成 Owner 无法接管;credential_or_policy_fence_rejected表示认证后 authority 已变化,应重新认证并使用 新 mutation;- managed delivery 上限是 64 个条目;长期未确认项需要人工核对,不得用通用目录 GC 删除。