MCP Phase 2a: X-Ghpool-Key agent authn + default-deny tool allowlist#26
Merged
Conversation
…wlist Slice 2a of #17 (read-only scope; writes remain gated on 2b): - [[mcp.agents]] config: id + key (secret-ref resolved at load) + tools allowlist. Empty = Phase 1 network-trust mode, fully backward compatible. - authenticate(): with agents configured, every /mcp request requires a valid X-Ghpool-Key (sha256-digest comparison); 401 JSON-RPC error otherwise, audit-logged. - Default-deny enforcement: tools/call not on the agent's allowlist -> 403 at the proxy, never reaches upstream. Empty allowlist denies all calls. - Per-agent X-MCP-Tools injection (exact allowlist, verified native filtering in #22) as defense-in-depth; deliberately NOT X-MCP-Toolsets (fails open on invalid names, #22 finding F). Global toolsets only apply in Phase 1 mode. - Audit attribution: [agent=<id> via <identity>] on every frame; DENIED warns for policy rejections. - Docs: config.example.toml [[mcp.agents]] + README Phase 2a section. 41 tests (10 new). Live-verified on zz k3s: 401 both paths, tools/list filtered 27->4, allowed call 200, denied call 403, kiro-cli end-to-end with key in mcp.json headers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Slice 2a of #17 (per the delivery plan): per-agent authentication via
X-Ghpool-Keyand a default-deny tool allowlist enforced at the proxy. Read-only scope is unchanged — writes remain gated on slice 2b.Checklist items closed from #17:
[2a]Agent authentication ·[2a]Per-agent default-deny policy (tool allowlist; repo allowlist is 2b) ·[2a]Outbound header allowlist (verified by test) ·[2a]tools/listfiltering viaX-MCP-Tools·[2a]TLS guidance (docs).Design
[[mcp.agents]]configured → Phase 1 network-trust mode, zero behavior change (verified by existing tests remaining green unmodified)./mcprequest requires a validX-Ghpool-Key. Keys use the existing secret-reference formats (env:/aws:secretsmanager:/k8s:), resolved at config load. Comparison is on SHA-256 digests so equality-check timing leaks nothing about the configured key. Failures:401with a JSON-RPC error body, audit-logged.tools/callfor a tool not on the agent's allowlist →403at the proxy, never reaches GitHub. Empty allowlist = deny all calls. The allowlist is also injected upstream asX-MCP-Tools(exact per-tool filtering, verified native in the MCP proxy Phase 0: compliance & compatibility spike (hosted endpoint contract, App tokens) #22 spike) sotools/listshows the agent only its tools — defense-in-depth, with the proxy check authoritative. Deliberately notX-MCP-Toolsets, which fails open on invalid names (MCP proxy Phase 0: compliance & compatibility spike (hosted endpoint contract, App tokens) #22 finding F).[agent=<id> via <identity>]; denials logWARN … DENIED.X-Ghpool-Keynever goes upstream (header set is built from an allowlist — test-asserted).Tested
keys_match, Phase 1 open mode, 401 missing/wrong key (+ upstream never called), allowed call passes withX-MCP-Toolsinjected and global toolsets suppressed, denied call 403 (+ upstream never called), empty allowlist denies all, non-tools/callmethods pass, multi-agent policy resolution. Clippy-D warningsclean.401, wrong key →401(JSON-RPC error bodies)tools/listfiltered 27 → 4 tools byX-MCP-Toolsissue_read→200; deniedsearch_code→403MCP tools/call issue_read [agent=kiro-zz via zz] [session=…]andMCP tools/call search_code DENIED [agent=kiro-zz]mcp.jsongained oneheadersline; kiro read issue MCP proxy Phase 2 gate: agent authn + default-deny policy + GitHub App backend + writes #17's title through the authenticated proxyDocs
config.example.toml[[mcp.agents]]reference; README "Per-agent authentication (Phase 2a)" section with key-delivery and TLS-termination guidance.Out of scope (2b, per #17)
Repo allowlists + resource resolution, GitHub App credential backend, session-to-agent binding, fail-closed durable audit, write classification/safe-retry — writes stay off until all of 2b lands.