ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

kr守护进程krd如何工作:单个Go进程管理三类UNIX socket详解

kr守护进程krd如何工作:单个Go进程管理三类UNIX socket详解

【免费下载链接】kr

DEPRECATED A dev tool for SSH auth + Git commit/tag signing using a key stored in Krypton.

项目地址:https://gitcode.com/gh_mirrors/kr/kr
点击查看免费下载

krd 是 kr 工具包的核心守护进程:它只是一个常驻的 Go 二进制文件,却同时管理三类 UNIX socket——控制通道、SSH agent 通道和主机认证通道,让 SSH 登录与 Git 签名请求都能安全地路由到手机上的 Krypton 应用。本文带你逐行看懂这个"一进程三 socket"的设计。

⚠️ 提示:kr 项目已标记为 DEPRECATED(开发已迁至 akr 项目),但 krd 的这套架构设计依然很有参考价值。

krd 启动流程:一个 main 函数串起三条监听线

krd 的入口在 src/krd/main.go,启动顺序非常清晰:

  1. 升级本地~/.ssh/config中的旧配置(见 src/daemon/sshconfig.go)
  2. 打开通知器并启动通知文件清理协程
  3. 依次调用DaemonListen()、AgentListen()、HostAuthListen()打开三个 socket
  4. 用两个 goroutine 分别托管 HTTP 控制服务和 SSH agent 服务,主协程阻塞等待退出信号

三类 socket 的文件名常量都定义在 src/common/socket/socket.go#L81-L118:

socket 文件常量角色客户端
~/.kr/krd.sockDAEMON_SOCKET_FILENAME控制平面:HTTP 风格的命令通道krCLI、krgpg
~/.kr/krd-agent.sockAGENT_SOCKET_FILENAMESSH agent:响应 List/Sign 等 agent 协议ssh(经IdentityAgent配置)
~/.kr/krd-hostauth.sockHOST_AUTH_FILENAME主机认证:接收主机公钥证据krssh代理

三个 socket 都放在~/.kr/目录下(目录权限 0700),并在每次监听前删除可能残留的旧 socket 文件,避免上次异常退出导致的"address in use"。

控制 socketkrd.sock:守护进程的大脑

krd.sock上跑的不是原始 TCP 协议,而是一个标准http.ServeMux,路由定义在 src/daemon/control/server.go#L44-L52:

  • GET /ping:健康检查,客户端用它判断 krd 是否存活
  • GET /version:返回 krd 版本号,kr用它检测"是否有旧版 krd 仍在运行"
  • GET/PUT/DELETE /pair:查询、发起、解除手机配对
  • POST /enclave:把签名请求(SSH 签名、Git commit/tag 签名、hosts 校验)转发到"enclave",最终送达手机

这条通道的意义在于:kr命令行和krgpg(Git 签名接口)都不需要各自实现复杂协议,只要拨号 + 发一个 HTTP 请求即可。连接封装在 src/common/socket/socket.go#L153-L171 的DaemonDialWithTimeout中——先pingDaemon探活,5 秒超时则报ping timed out,探活成功后才真正建连。

客户端侧的调用示例见 src/daemon/client/client.go,例如RequestKrdVersion()就是拨号后发GET /version。

agent socketkrd-agent.sock:伪装成 SSH agent,把私钥留在手机上

这是最巧妙的一个设计。安装时 kr 会往~/.ssh/config写入如下配置(模板见 src/kr/sshconfig.go#L28-L36):

Host * IdentityAgent ~/.kr/krd-agent.sock ProxyCommand /usr/bin/krssh %h %p

IdentityAgent是 OpenSSH 7.3+ 的选项,让ssh直接把 krd 当作本地 agent 使用。于是 SSH 认证时发生的事是:

  1. ssh通过 agent 协议向 krd 发出Sign请求(要签的数据是 SSH 会话 ID)
  2. krd 的 Agent.Sign 先尝试回落到你原有的SSH_AUTH_SOCK(withOriginalAgent,见 src/daemon/ssh_agent.go#L36-L50),如果本地已有同一把公钥就直接用,行为透明
  3. 否则把SignRequest通过 enclave 通道发到手机,由用户在 Krypton App 上点"允许"或"拒绝"
  4. 签名原样返回给 ssh,私钥从未离开手机

agent 服务的主循环在 ServeKRAgent:每个新连接交给一个 goroutine 执行agent.ServeAgent,互不阻塞。

📌 顺带一提:krd 还有一套基于~/.kr/notify/krd-notify.log-*文件的"旁路通知"机制(src/common/socket/notify.go),因为 SSH 协议本身没有通道回传"手机已批准/已拒绝"这类消息,krd 就把提示写进通知文件,由krssh侧的读取协程实时打印到终端。

hostauth socketkrd-hostauth.sock:给主机身份"拍照存证"

第三个 socket 专门服务于 krssh 这个 SSH 代理。流程是:

  1. krssh作为ProxyCommand启动,双向透传 SSH 流量,同时旁路解析 SSH 包
  2. 当解析到 key exchange 的 KEX 应答报文(含主机公钥 + 签名,见 src/krssh/main.go#L65-L88 的tryParse),就组装成一个HostAuthJSON
  3. 通过HostAuthDial()拨号krd-hostauth.sock把它发给 krd(src/krssh/main.go#L55-L63)
  4. krd 收到后进入 onHostAuth:用主机公钥验证签名,写入最近的会话记录,并唤醒正在awaitHostAuthFor等待的签名流程

这样,用户手机上批准签名时看到的就不只是"某台机器要签名",而是这台机器的真实公钥指纹——即使有人伪造了主机名,签名请求里携带的主机证据也会暴露不匹配,krd 会通知krssh直接终止会话(HOST_KEY_MISMATCH)。

单进程如何稳住三条线:并发模型与自愈

看懂三个 socket 后,再看 main.go 的整体并发结构就一目了然了:

main 协程 ├── goroutine: controlServer.Start() + HandleControlHTTP(daemonSocket) ├── goroutine: daemon.ServeKRAgent(enclaveClient, agentSocket, hostAuthSocket) │ └── 内部还有 goroutine 循环 Accept hostauth 连接 └── 阻塞 <-stopSignal(SIGTERM/SIGKILL/...),收到后 controlServer.Stop()

几个工程细节值得学习:

  • 信号统一收口:signal.Notify监听os.Interrupt、SIGTERM等,退出前先停 enclave 客户端,保证配对状态干净落盘(见 src/krd/main.go#L90-L96)
  • 故障自愈:客户端拨号失败时会自动pkill krd并用nohup krd重启后重试,见 src/common/socket/socket_unix.go#L15-L34
  • 系统级托管:Linux 下用 systemd 单元(模板见 install/systemd-service-as-current-user.sh,Restart=on-failure按当前用户运行),macOS 下用 LaunchAgent(install/macos/share_ext/co.krypt.krd.plist),配合make start一键装好(Makefile#L42-L47)

常见问题速查

现象原因与处理
Could not connect to Krypton daemonkrd 没在运行,执行kr restart即可
ping timed outkrd 卡死或版本过旧,客户端会自动尝试重启 krd
An old version of krd is still running新旧 krd 共存,kr restart后重试
终端出现Krypton ▶ Requesting SSH authentication from phone正常工作流:等待你在 Krypton App 中批准

关键源码文件导航

  • 守护进程入口:src/krd/main.go
  • socket 路径与拨号逻辑:src/common/socket/socket.go
  • 自动重启逻辑(Linux/FreeBSD):src/common/socket/socket_unix.go
  • 控制服务与 HTTP 路由:src/daemon/control/server.go
  • SSH agent 实现:src/daemon/ssh_agent.go
  • krssh 代理与主机证据采集:src/krssh/main.go
  • krgpg Git 签名接口:src/krgpg/main.go
  • 客户端请求封装:src/daemon/client/client.go
  • 通知文件机制:src/common/socket/notify.go

总结

krd 用一个 Go 进程 + 三个职责分离的 UNIX socket,把"控制命令、SSH agent、主机证据回传"三条数据流解耦:CLI 工具走 HTTP 风格控制面,ssh 走标准 agent 协议,主机验证走轻量 JSON 通道。三者共享同一个 enclave 客户端,最终都汇聚到手机端的 Krypton App 做人工批准——这正是"私钥永不离开手机"这一安全模型的工程落点。

【免费下载链接】kr

DEPRECATED A dev tool for SSH auth + Git commit/tag signing using a key stored in Krypton.

项目地址:https://gitcode.com/gh_mirrors/kr/kr
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进