← 返回作品集

當 pty-mcp 遇上 cred-mcp

AI agent 如何透過 HPKE 密封通道完成 SSH 登入、sudo、API 認證——明文全程不進 LLM context。

HPKE MCP 整合 AI 憑證安全 Go pty-mcp v0.11.6 cred-mcp v0.4.3

這不是 password manager,也不是 terminal wrapper。
這是一條把「操作能力」「憑證可見性」拆開的 AI infrastructure boundary。

問題

AI agent 要操作真實系統,就一定會碰到需要密碼的時刻:SSH 登入、sudo 提權、API key 認證。這個問題比想像中難解:

把密碼貼在 chat 裡

密碼進了 LLM context,出現在 conversation history、session log、甚至 API response 裡。

寫在 .env 讓 AI 讀

AI 讀了 .env 就等於密碼進了 context。任何讀過這段對話的 model 都看到了。

每次操作者手動貼

人坐在旁邊等 AI 告訴他「現在可以貼密碼了」——這不是自動化,是更繁瑣的手動流程。

用 send_secret 彈對話框

pty-mcp 的 send_secret 需要人工點擊——適合互動場景,但 agent 無法在無人值守時自動完成。

理想的解法是:AI 知道去哪拿密碼,可以自己完成整個工作流,但密碼明文從頭到尾都不進 LLM context。

解法:兩個 MCP server 的協作

pty-mcp 管 PTY——本地 shell、SSH、serial port,AI agent 的互動式終端。cred-mcp 管憑證——OS keychain、Vaultwarden,密碼不出明文。把兩者接起來,就得到一個 AI 可以完整自動操作、但密碼永遠不進 context 的系統。

接起來的機制是 HPKE(Hybrid Public Key Encryption)。整個設計有一個核心原則:AI 只充當不可信的快遞——它傳遞公鑰和密文,從不接觸明文。

HPKE 協議:完整流程

┌──────────────────────────────────────────────────────┐
│ AI Agent(Claude Code) │
└────────────┬──────────────────────────┬───────────────┘
│ MCP calls │ MCP calls
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ pty-mcp │ │ cred-mcp │
│(終端 + PTY)│ │(Vault + Keychain)│
└──────┬───────┘ └────────┬─────────┘
│ │
Ed25519 identity key Vaultwarden vault
X25519 session key consumer registry
│ │
└──────── HPKE ────────────┘
SealedBox(密文)
只有 pty-mcp 持有 session key 能解
1
pty-mcp 生成公鑰 bundle

AI 呼叫 get_credential_bundle(session_id),pty-mcp 生成 Ed25519 identity key(長期身份)和 X25519 session key(單次會話)。回傳的 ConsumerBundle 只含公鑰,AI 拿到的是可以公開的資訊。

2
cred-mcp 驗證身份、發授權 token

AI 呼叫 request_authorization(item_id, bundle),cred-mcp 對照 consumer registry:identity key 是否已登記?這個 consumer 是否允許請求這個 vault 項目?通過後發出單次使用的 auth token,綁定 (item, consumer, purpose)

3
cred-mcp 封裝密碼

AI 呼叫 vault_seal(item_id, bundle, token),cred-mcp 從 Vaultwarden 取出明文,用消費者的 X25519 session key 做 HPKE 加密(DHKEM-X25519 + HKDF-SHA256 + ChaCha20Poly1305),回傳 SealedBox。明文在 cred-mcp 程序內完成加密,不序列化進任何 response。

4
pty-mcp 解密並注入 PTY

AI 呼叫 inject_secret(session_id, sealed_box),pty-mcp 用本地保存的 session 私鑰解密,把明文直接 WriteRaw 進 PTY,立即清零記憶體。回傳 {"success": true}——AI 永遠沒看到密碼。

實際程式碼

場景一:SSH 登入需要密碼

# 開啟本地 PTY,在裡面跑 ssh
session = create_local_session()
send_input(session.id, "ssh admin@prod-server")
read_output(session.id, wait_for: "password:")
# Step 1:生成公鑰 bundle
bundle = get_credential_bundle(session.id)
→ {identity_pub_key: "...", session_pub_key: "...", session_id: "..."}
# Step 2:取得授權
auth = request_authorization(item_id: "vault-prod-ssh", bundle: bundle)
→ {auth_token: "abc123", expires_in: 60}
# Step 3:封裝密碼
sealed = vault_seal(item_id: "vault-prod-ssh", bundle: bundle, token: auth.token)
→ {sealed_box: "AQID...", box_id: "xyz789"}
# Step 4:注入 PTY
inject_secret(session_id: session.id, sealed_box: sealed.sealed_box)
→ {"success": true}
# SSH 登入完成,AI 從未看過密碼
send_input(session.id, "ls -la /var/log")

場景二:sudo 提權

# 已在 SSH session 裡,需要 sudo
send_input(session.id, "sudo systemctl restart nginx")
→ "[sudo] password for admin:"
# 同樣的四步流程,這次注入 sudo 密碼
bundle = get_credential_bundle(session.id)
auth = request_authorization("vault-sudo-pass", bundle)
sealed = vault_seal("vault-sudo-pass", bundle, auth.token)
inject_secret(session.id, sealed.sealed_box)
→ nginx 重啟完成,密碼沒進任何 log

安全保證

明文不進 LLM context

所有 MCP tool response 只含 metadata 或密文。明文只短暫存在於 cred-mcp 的 vault read / seal 流程,以及 pty-mcp 的 decrypt / WriteRaw 流程;不進 tool response、LLM context、conversation history 或 audit log。

Session key 單次使用

每個 session_id 的 session key 只能用一次。重複呼叫 inject_secret 使用同一 session_id 必定報錯,防重放攻擊。

Auth token 單次使用 + 綁定

授權 token 消耗後作廢,且綁定 (item, consumer, purpose)——不能用來請求其他 vault 項目。

Consumer registry ACL

cred-mcp 用 registry YAML 管理哪些 consumer 可以請求哪些 vault 項目。未登記的 identity key 直接拒絕。

Audit log(雙端)

pty-mcp 記錄 bundle_generated / secret_injected;cred-mcp 記錄 authorization_issued / vault_sealed。不含明文或私鑰材料。

只有 pty-mcp 能解密

SealedBox 用 pty-mcp 的 X25519 session public key 加密。cred-mcp 不持有 pty-mcp 的 session private key——它只能封裝 SealedBox,產出的密文只有 pty-mcp 能解。

為什麼要這麼複雜?

最常見的反應是:「這四個 tool call 可不可以合成一個?」可以,但那樣就錯了。

四步拆開有明確理由:

這個設計的本質是:讓 AI 成為一個不可信的信差(untrusted courier)——它知道流程、會傳遞訊息,但接觸不到實際內容。

適用場景

企業為什麼需要這個

企業不可能把 AD、firewall、ERP、database 的帳密直接交給 LLM。過去的選擇只有兩個:

pty-mcp x cred-mcp 的目的,是讓 AI 可以執行被授權的操作,而不是取得可攜出的秘密。這個差距決定了企業能不能真正讓 AI agent 進入內網執行維運工作。

快速開始

# 1. 安裝兩個 MCP server
curl -fsSL https://raw.githubusercontent.com/raychao-oao/pty-mcp/main/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/raychao-oao/cred-mcp/main/install.sh | sh
# 2. 設定 cred-mcp(Vaultwarden 連線資訊放進 .mcp.json)
# 3. 建立 consumer registry
bundle = get_credential_bundle("any-session-id")
# 把 identity_pub_key 轉 hex 填入 ~/.config/cred-mcp/registry.yaml
# 4. 測試整合
session = create_local_session()
bundle = get_credential_bundle(session.id)
auth = request_authorization("your-vault-item-id", bundle)
sealed = vault_seal("your-vault-item-id", bundle, auth.token)
inject_secret(session.id, sealed.sealed_box)
pty-mcp 詳細介紹 cred-mcp 詳細介紹
← 返回作品集