即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载导读本文解读 WuKongIM 仓库中的架构决策记录 ADR 0044Use separate deployment and Codex SSH identities阐述自动化 Chat Lifecycle 云租期Cloud Lease为何要为部署运维与Codex 实时诊断各签发一把相互独立的临时 Ed25519 SSH 身份并深入其落地实现wkchatlifecycle的seal-deployment-identity/open-deployment-identity命令、materialize的公钥绑定以及stage-orchestrate.sh中的完整调用链。读完本文你将理解这套一把加密凭证给 GitHub 部署、一把本地私钥给 Codex 诊断、双双随租期失效的隔离模型以及它如何用 NaCl 密封盒保证凭证可审计、可绑定、不可越权。背景自动化 Chat Lifecycle 需要临时直接访问在 WuKongIM 的自动化 Chat Lifecycle 流程中系统会在阿里云按量付费PostPaid租用四台同规格主机三台 4 vCPU / 8 GiB 的 WuKongIM 服务节点 一台承载 worker、协调、监控、分析与公共代理职责的 4 vCPU / 8 GiB 主机见 ADR 0041Use four PostPaid hosts for automated chat lifecycle。为保证负载节点可直达、服务节点保持私有ADR 0042 明确自动化运行期间负载节点仅在租期内开放 22 端口 SSH 与 80 端口 HTTP三个服务节点保持私有离线、禁用密码与 root 密码登录租期结束时所有规则与 authorized keys 一并清除。在这种临时测试服务器、租期结束即销毁的拓扑下谁有权 SSH 进去、以什么身份进去直接决定了整个流程的可审计性与安全边界。ADR 0044 正是在此背景下回答部署动作与诊断动作应该用同一把钥匙吗的问题。双身份设计一把给部署一把给诊断ADR 0044 的结论可以浓缩为一句话每个 Chat Lifecycle Cloud Lease 授权两个相互独立的临时 SSH 身份——一把由 GitHub 加密持有的身份用于部署、监控、收尾与证据救援一把本地生成的 Ed25519 身份其私钥仅保留在 Codex 手中用于实时诊断。两者都随 Lease 过期失效并且只有在证明库存归零zero inventory之后才会被删除。拆开来看这把双身份模型包含四个关键属性维度部署身份Deployment Identity诊断身份Diagnostic / Codex Identity私钥持有方GitHub 侧以加密信封形式流转私钥主体经密封后随 Artifact 传递本地生成的 Ed25519 私钥仅保留在 Codex 手中用途Deployment部署、监控、finalization收尾、证据救援实时诊断live diagnosis生成方式由编排脚本ssh-keygen生成经seal-deployment-identity密封由本地脚本ssh-keygen生成公钥注入 Run Plan失效方式随 Lease 过期expires_at强校验随 Lease 过期删除时机证明 zero inventory 之后证明 zero inventory 之后这样分离的直接收益写在 ADR 原文中保持可审计性preserves auditability并防止 GitHub 的部署凭证变成 Codex 的诊断秘密。即使 Codex 的本地环境或诊断会话被攻破攻击者得到的也只是租期内的诊断身份而不是那条能驱动整个部署链路的 GitHub 部署凭证反过来GitHub Actions 工件链路上的泄露也不会直接暴露 Codex 的诊断私钥。部署身份的密封与打开源码级实现双身份机制的核心代码位于 cmd/wkchatlifecycle/deployment_identity.go由wkchatlifecycle工具以两个 cobra 子命令暴露seal-deployment-identity与open-deployment-identity。密封命令把部署私钥锁进加密信封seal-deployment-identity的职责是将一把 Lease 作用域内的部署 SSH 身份密封为加密信封其完整参数如下wkchatlifecycle seal-deployment-identity \ --recipient wrapping-key OpenSSH Ed25519 公钥 \ --identity mode-0600 部署 Ed25519 私钥 \ --request-id 请求身份 \ --lease-id Lease 身份 \ --source-sha 40 位十六进制源码提交 \ --plan-digest 64 位十六进制 Cloud Lease Plan 摘要 \ --expires-at 不可变的 Lease 过期时间 RFC3339 UTC对应源码中的 flag 定义见 deployment_identity.go 第 102-110 行七个参数全部markRequired强制必填。密封过程如下元数据校验validDeploymentIdentityMetadatarequest-id/lease-id需匹配accessIdentityPattern^[A-Za-z0-9][A-Za-z0-9._-]{0,95}$source-sha需为 40 位小写十六进制hex40Patternplan-digest需为 64 位十六进制hex64Patternexpires-at必须是UTC 时区的 RFC3339 时间第 182-189 行。解析 recipient 公钥parseEd25519PublicKey实现在 access.go 第 194-212 行只接受单条、无 authorized_keys 选项、无附加内容的ssh-ed25519公钥。读取部署私钥readPrivateIdentityBody强制私钥必须是常规文件且权限位不含 group/other 位info.Mode().Perm()0o077 ! 0即拒绝大小在 0 到 64 KiB 之间且必须是 Ed25519 类型第 208-245 行。计算部署公钥的 authorized_keys 文本与 SHA256 指纹ssh.MarshalAuthorizedKey/ssh.FingerprintSHA256。组装明文 payloaddeploymentIdentityPayload其中private_key_base64承载私钥主体。用box.SealAnonymous匿名密封不需要发送方密钥只需 recipient 公钥对明文加密算法标识为x25519-xsalsa20-poly1305-sealed-box常量accessEncryptionAlgorithmaccess.go 第 31 行。输出encryptedDeploymentIdentityEnvelope信封 JSON包含 schema、algorithm、request-id、lease-id、source-sha、plan-digest、recipient-fingerprint、deployment-public-key、deployment-fingerprint、expires-at 与 ciphertext-base64。信封 schema 常量定义在 deployment_identity.go 第 19-22 行wukongim.chat_lifecycle.deployment_identity/v1明文 payload schemawukongim.chat_lifecycle.encrypted_deployment_identity/v1信封 schema这意味着即使信封被放在 GitHub Actions Artifact 这种有界存储上也无法直接读出任何私钥材料——测试TestDeploymentIdentityEnvelopeRoundTripIsLeaseBoundAndPrivate专门断言加密后的部署身份不包含明文密钥材料bytes.Contains(sealed.Bytes(), privateBody)必须为 false。打开命令只有持 wrapping 私钥的人能还原open-deployment-identity是密封的逆操作参数为wkchatlifecycle open-deployment-identity \ --envelope 加密信封 JSON \ --identity mode-0600 wrapping-key Ed25519 私钥 \ --request-id / --lease-id / --source-sha / --plan-digest 精确匹配 \ --now 可信的当前 RFC3339 UTC 时间 \ --output 新部署私钥输出路径它的校验链第 114-172 行层层收紧信封 JSON 严格解析readStrictDisallowUnknownFields、拒绝尾随数据并通过validEncryptedDeploymentIdentityEnvelope验证 schema、算法、元数据格式、指纹前缀SHA256:、deployment_public_key必须以ssh-ed25519开头、密文长度有界。请求参数必须与信封中的request_id、lease_id、source_sha、plan_digest逐一精确相等。--now必须解析为 UTC 时区且必须早于信封中的expires_at——过期即拒绝实现随 Lease 过期失效。wrapping 私钥的 SHA256 指纹必须与信封recipient_fingerprint一致防止用错钥匙。box.OpenAnonymous解密失败ok false即拒绝。解密出的 payload 必须与信封完全匹配payloadMatchesEnvelope且私钥主体解码后重新推导出的公钥必须同时匹配信封的deployment_fingerprint与deployment_public_key——防止信封内容被篡改后解密出另一把钥匙。最后writePrivateAtomic以0600 权限、原子写临时文件 rename落盘且绝不覆盖已存在文件测试TestOpenDeploymentIdentityRejectsMismatchExpirationAndExistingOutput验证失败场景下不会创建输出、已有文件内容不被改动。诊断身份的注入materialize 与 access 命令Codex 诊断身份--codex-diagnostic-pubkey与部署身份--deployment-pubkey在 Run Plan 物化阶段被同时绑定。wkchatlifecycle materialize命令cmd/wkchatlifecycle/main.go 第 199-227 行接收两个独立参数--codex-diagnostic-pubkeyCodex 诊断 Ed25519 公钥--deployment-pubkey派生的部署 Ed25519 公钥两者均标记为必填与source-sha、operator、request-id、repository、bundle-digest、now、attempt一起传入chatlifecyclerun.Materialize。这把公钥入计划的设计意味着诊断公钥与部署公钥在计划层面就是两个独立字段后续分别进入bootstrap_access引导访问与部署激活流程互不混用。与部署身份配套的是同一工具中的seal-access/open-access命令cmd/wkchatlifecycle/access.go 第 70-156 行它们把 UI 凭据Manager / Demo 地址、operator 用户名、密码、租期过期时间以同样的box.SealAnonymous密封为encryptedAccessEnveloperecipient正是Codex 的 Ed25519 公钥。也就是说部署身份信封的 recipient 是 GitHub 侧的 wrapping 公钥由WK_CHAT_WRAPPING_PUBLIC_KEY提供访问凭据信封的 recipient 是 Codex 的诊断公钥两个信封体系都遵循密封在部署侧、由各自私钥持有者打开的对称结构。值得一提的是 access.go 第 214-296 行 实现了readEd25519Identity与ed25519PublicToX25519将 Ed25519 公钥的 Edwards y 坐标映射为 X25519 的 Montgomery u 坐标u (1y)/(1-y) over 2^255-19私钥侧通过SHA-512(seed)前 32 字节并做位掩码bit 0 248、bit 31 127、bit 31 | 64派生 X25519 私钥并用curve25519.X25519探测标量做合法性验证。这是用 OpenSSH Ed25519 密钥承载 NaCl sealed box的关键桥接也解释了为何所有身份必须严格限定为 Ed25519 类型。端到端调用链stage-orchestrate.sh 里的实际编排理解双身份如何落地的最终答案在编排脚本 scripts/chat-lifecycle/stage-orchestrate.sh 中。完整流程如下第一步生成部署密钥并物化计划第 476-490 行deployment_key$WK_CHAT_WORK_DIR/deployment-${chat_stage}-${attempt} ssh-keygen -q -t ed25519 -N -C wukongim-chat-lifecycle-${WK_CHAT_REQUEST_ID}-${chat_stage}-${attempt} -f $deployment_key chmod 0600 $deployment_key deployment_public_key$(${deployment_key}.pub)随后materialize同时注入两把公钥$WK_CHAT_TOOL materialize --template $WK_CHAT_TEMPLATE --source-sha $WK_CHAT_SOURCE_SHA \ --operator $WK_CHAT_OPERATOR --codex-diagnostic-pubkey $WK_CHAT_CODEX_DIAGNOSTIC_PUBKEY \ --request-id $WK_CHAT_REQUEST_ID --repository $GITHUB_REPOSITORY \ --bundle-digest $bundle_digest --deployment-pubkey $deployment_public_key \ --now $(date -u %Y-%m-%dT%H:%M:%SZ) --attempt $attempt \ --committed-micros $committed_micros第二步密封部署身份第 518-522 行$WK_CHAT_TOOL seal-deployment-identity \ --recipient $WK_CHAT_WRAPPING_PUBLIC_KEY --identity $deployment_key \ --request-id $WK_CHAT_REQUEST_ID --lease-id $planned_lease_id \ --source-sha $WK_CHAT_SOURCE_SHA --plan-digest $planned_plan_digest \ --expires-at $planned_expires_at $attempt_dir/encrypted-deployment-identity.json注意--expires-at直接取自 Run Plan 的lease_plan.expires_at把部署身份的寿命硬绑定到 Lease 过期时间--plan-digest取自 release selector保证信封与将要下发的 Lease Plan 一一对应。第三步把信封交给部署 Actions。脚本通过dispatch_and_wait cloud-deployment-activate.yml将encrypted_deployment_identity_json作为参数传给部署 workflow第 404 行随后从部署产物中取回encrypted-deployment-identity.json并用jq校验其 schema、request/lease/source/plan 绑定关系与公钥前缀第 564-569 行。部署侧再以open-deployment-identity打开信封还原部署私钥测试 scripts/chat_lifecycle_workflows_test.go 断言部署 workflow 必须包含open-deployment-identity与WK_CHAT_LIFECYCLE_WRAPPING_PRIVATE_KEY环境变量。第四步用部署身份建立 SSH 通道。脚本导出WK_CLOUD_SSH_KEY$deployment_key后调用 scripts/cloud-deployment/write-ssh-config.sh生成以wkdeploy用户、IdentitiesOnly yes、BatchMode yes、StrictHostKeyChecking accept-new、独立 known_hosts 的 SSH config三个服务节点通过ProxyJump wukong-load经负载节点跳转write-ssh-config.sh 第 44-70 行。后续所有ssh -F $WK_CLOUD_SSH_CONFIG操作——启动 stage 服务、轮询 run-start.json、读取 journal 游标——都走这把部署身份。第五步失败路径上的清理。release_failed_attempt在释放租期后立即rm -f部署私钥/公钥并删除attempt_dir下所有encrypted-deployment-identity.json第 289-293 行成功路径则在 handoff 完成后rm -f $deployment_key ${deployment_key}.pub第 748 行。cleanup_on_exit的 EXIT trap 保证即使脚本异常退出本地部署密钥也会被清除第 247-255 行。这正对应 ADR 中只在证明 zero inventory 后删除的约束——租期释放动作cloud-lease-release.yml会返回带zero_inventory字段的 release.json只有确认零库存后才算彻底收尾。本地实验室路径 scripts/chat-lifecycle/direct-lab.sh 同样贯彻双身份initialize_request_state一次生成两把密钥——diagnostic_ed25519注释wukongim-chat-lab-diagnostic-$request_id与deployment_ed25519注释wukongim-chat-lab-deployment-$request_id第 356-359 行并在start_request的 materialize 调用中分别以--codex-diagnostic-pubkey $($directory/diagnostic_ed25519.pub)与--deployment-pubkey $($directory/deployment_ed25519.pub)注入第 434-437 行。测试与契约隔离机制的可验证性双身份机制被多层测试锁定cmd/wkchatlifecycle/deployment_identity_test.goTestDeploymentIdentityEnvelopeRoundTripIsLeaseBoundAndPrivate完整密封→打开回环验证信封无明文私钥、schema 正确、Lease 绑定正确、打开后字节一致且权限为 0600TestSealDeploymentIdentityAcceptsCommentedRecipient允许 recipient 公钥带注释TestEd25519RecipientRejectsAuthorizedKeyOptionsAndAdditionalKeys拒绝带 authorized_keys 选项或多条公钥的模糊输入TestOpenDeploymentIdentityRejectsMismatchExpirationAndExistingOutput错误 wrapping 私钥、错误 request/lease、过期时间均拒绝打开且失败时绝不创建输出文件、绝不覆盖已有文件。cmd/wkchatlifecycle/access_test.go覆盖 access 信封的同类回环与拒绝路径。scripts/chat_lifecycle_workflows_test.go从编排脚本静态断言seal-deployment-identity、open-deployment-identity、encrypted-deployment-identity.json与WK_CHAT_LIFECYCLE_WRAPPING_PRIVATE_KEY等关键元素必须存在。scripts/chat_lifecycle_direct_lab_test.go 与 scripts/chat_lifecycle_direct_lab_deploy_integration_test.go断言本地请求状态目录必须同时包含diagnostic_ed25519与deployment_ed25519两套文件验证双身份是初始化状态的固有组成部分。安全边界小结从设计到实现ADR 0044 的双 SSH 身份隔离可以归纳为四层边界密钥来源隔离部署私钥由编排脚本在租期开始时生成密封后私钥主体只以密文形式存在于 Artifact诊断私钥由本地生成从不进入 GitHub 工件链。持有者隔离部署身份的 recipient 是 GitHub 侧 wrapping 公钥只有 GitHub 部署流程能打开Codex 诊断身份的公钥进入 Run Plan 的 bootstrap access私钥只留在 Codex 手中。租期绑定信封中的expires_at与lease_id、plan_digest、source_sha、request_id强绑定打开时必须逐项精确匹配且时间未过期。销毁纪律无论成功、失败还是 operator 手动终止部署密钥都在租期释放zero inventory 证明之后被立即删除绝不跨租期保留。这套机制与 ADR 0034run-scoped internal capability tokens、ADR 0037本地运行 Codex 加密分析会话 一脉相承所有特权都做成租期作用域、最小化持有、到期即毁。双身份正是这一原则在 SSH 访问层面的一次具体落地——既满足了操作者对临时测试服务器直接访问的要求又没有让任何单一凭证同时承担部署与诊断两种职责。赞分享即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载相关推荐WuKongIM Cloud Simulation 运行域内部能力令牌256 位隔离凭证的设计与落地WuKongIM Cloud Simulation 运行域内部能力令牌256 位隔离凭证的设计与落地 导读 WuKongIM 的 Cloud Simulati即时通讯后端WuKongIM 云部署离线 Bundle 密封与校验wkcloudbundle 命令的设计与实现WuKongIM 云部署离线 Bundle 密封与校验wkcloudbundle 命令的设计与实现 导读 cmd/wkcloudbundle 是 WuKong即时通讯后端如何4步让B站日常任务全自动BiliBiliToolPro部署完整指南如何4步让B站日常任务全自动BiliBiliToolPro部署完整指南 每天签到、看视频、投币少做一步就少一份经验坚持几天就忘了。BiliBiliTool后端任务调度工作流自动化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考