Skip to main content
Glama

infrabroker

CI Release Go Report Card License: GPL-3.0 Docs

Infrastructure access broker for AI agents — SSH & Kubernetes. The model never touches a credential. (formerly ssh-broker)

The agent requests an action — run a command on a host, query or change a cluster. infrabroker checks it against policy, executes it with a credential minted for that single operation — an ephemeral, scope-limited SSH certificate from its own CA, or a short-lived bound ServiceAccount token — and returns only the output. Keys, certificates and tokens live in the broker's memory and are discarded after the call: nothing enters the model's context, so a prompt-injected agent has nothing to exfiltrate.

One binary — infrabroker — exposes the same engine (internal/broker) and tool surface (internal/mcpserver) over three transports, chosen by subcommand. (The legacy per-transport binaries broker / mcp-broker / mcp-broker-http remain as thin deprecated wrappers over these subcommands, so existing configs keep working.)

  • MCP stdio (local, recommended for personal use) — infrabroker serve-mcp. Tools: ssh_execute, ssh_session_open / ssh_session_exec / ssh_session_close, ssh_list_servers, ssh_put_file / ssh_get_file; with clusters configured, also k8s_get / k8s_list / k8s_logs / k8s_apply / k8s_delete / k8s_list_clusters. No transport auth — isolation comes from the process being launched by the user (as the MCP spec recommends for stdio).

  • MCP HTTP + OAuth2/OIDC (remote, multi-user) — infrabroker serve-mcp-http, Streamable HTTP. Same tools, but each client authenticates with an OIDC bearer token validated locally against the issuer's JWKS; the user identity (and groups, for per-user RBAC) is propagated to the signer.

  • HTTP + mTLS — infrabroker serve-http, POST /v1/ssh_run (one-shot), for network agents authenticated with a client certificate.

Documentation

This README is a landing page. The detail lives in focused, single-source docs:

Document

Contents

QUICKSTART.md

First ssh_execute in under 10 minutes — single-binary local mode, no signer/PKI

ARCHITECTURE.md

Diagram, request flow, design decisions, sudo elevation, sessions, multi-CA

THREAT_MODEL.md

Actors, trust boundaries, security controls, and explicit non-goals/gaps

OPERATIONS.md

Runbook: startup, adding hosts, hot-reload, broker-ctl, PKI rotation, configs

MESH.md

Running infrabroker over a NetBird / Tailscale mesh — the session layer on top of the overlay path

SANDBOX.md

infrabroker with a sandboxed agent (ASP): the agent's code in a microVM, the credential and the action behind the broker — what each layer enforces, the OIDC recipe, the honest limits

HA.md

Why it is single-instance today: state inventory, the blockers, and what degrades under replication

API.md

HTTP endpoint reference for all services

USAGE.md

Guide to the MCP tools (SSH + Kubernetes), dry-run, and audit review (for the model / operator)

SECURITY.md

Vulnerability disclosure policy

CONTRIBUTING.md · CODING_STYLE.md

Workflow, versioning, Go style

Related MCP server: SSH Vault MCP

Why infrabroker

  • Anti-exfiltration (prompt injection): the ephemeral key/cert/token live only in the broker's memory; they never enter the model's context.

  • Kubernetes without kubeconfigs: the signer mints a short-lived bound ServiceAccount token (TokenRequest API) per operation; every cluster is default-deny with per-verb/resource/namespace policy and the same dry-run, approval and audit path as SSH.

  • Anti-reuse: each cert carries a TTL of minutes, source-address (broker or bastion IP), and — for one-shot — a force-command. Useless outside its host/time/IP.

  • Controlled escalation: allow_sudo / allowed_sudo_users live in the signer; a compromised broker cannot escalate where policy forbids it.

  • CA compromise bounded: one CA per host group (ca_keys), each key optionally in Azure Key Vault or ssh-agent (YubiKey PIV / SoftHSM / TPM) — the private key never leaves the HSM.

  • Audit / non-repudiation: append-only, Ed25519-chained log correlated by serial across signer, broker, and sshd.

The full threat model — including what the system deliberately does not defend — is in THREAT_MODEL.md.

How it works

AI model ──tool call──> broker ──mTLS──> [control-plane] ──mTLS──> signer
   (no credential)      (ephemeral key      (approval +          (CA key +
                         in RAM, never        guardrails,          policy + RBAC,
                         on disk)             no CA key)           signs the cert)
                            │
                            └── SSH with the ephemeral cert ──> bastion ──> target host
                                                                 └─ stdout/stderr/exit_code ─> model

The broker sends an intent ({host, role, purpose, command?, sudo?, pty?, pubkey, …}); the signer derives every certificate constraint from policy and returns the signed cert. The ephemeral private key is generated in the broker and never leaves it. See ARCHITECTURE.md for the request flow, the design decisions, and the per-hop ProxyJump certificate diagrams.

Feature overview

Capability

One-liner

More

Ephemeral certificates

Ed25519 pair in RAM per operation; minutes-long, scoped cert. No reusable secret.

ARCHITECTURE

External signer

A separate cmd/signer holds the CA key and policy; the broker never does.

ARCHITECTURE

Multi-CA + HSM

One CA key per host group via ca_keys; local PEM, Azure Key Vault, or ssh-agent/HSM.

ARCHITECTURE

AI-action firewall

Per-host or composable-by-group command policy (allow/deny/require_approval), POSIX-sh AST parsing, dry-run. Authoritative for one-shot.

ARCHITECTURE · USAGE

Human-in-the-loop approval

Optional control plane gates require_approval commands behind out-of-band approval; the signer enforces it.

ARCHITECTURE · API

Action budgets (behaviour guardrails)

Budget how much an agent can do: per-CN sign-rate cap plus per-subject rate limit and novelty escalation (a subsequent new host / novel command → approval); observe or enforce. Network tools budget what an agent can reach or spend; this budgets the actions themselves.

OPERATIONS · ARCHITECTURE

Kill switch

Freeze a subject (caller CN, end user, session id or certificate serial): no new certificates, grants revoked, and live sessions are force-closed within revocation_poll_seconds.

OPERATIONS

Sealed exec

Opt-in per host (sealed_exec): every session command carries a signer-signed envelope that infrabroker-shim verifies on the target, so per-command authorization survives a compromised broker.

THREAT_MODEL gap 1 · deploy

Approval bridge

approval-bridge posts pending approvals to Slack (Socket Mode) with Allow / Deny buttons; outbound-only, so nothing with approval authority becomes internet-facing.

OPERATIONS

Secret redaction

On by default: credentials inline in commands are masked in audit logs, session recordings and approval notifications (best-effort pattern matching, not DLP).

THREAT_MODEL gap 8

RBAC

Broker-CN groups (mTLS) + per-end-user OIDC groups; fail-closed.

ARCHITECTURE

sudo / PTY

Policy-gated elevation (sudo -n) and PTY allocation, per host.

ARCHITECTURE

Kubernetes broker

k8s_* tools with per-operation bound SA tokens, default-deny verb/resource/namespace policy, dry-run.

USAGE §10

Session recording

shell/pty sessions to ASCIIcast v2 (.cast), indexed by session_id.

USAGE §8

Chained audit

Append-only, Ed25519-signed, SHA-256-chained; correlated by serial.

USAGE §7 · API

Hot reload

signer.json re-read (and validated) without restart, via POST /v1/reload or SIGHUP.

OPERATIONS §3

Comparison with existing solutions

Several tools address SSH access control or AI-agent credential security, but none cover the full combination that infrabroker targets in a lightweight, self-hosted package.

Feature

infrabroker

Teleport

Vault + SSH engine

StrongDM

ssh-mcp

Ephemeral cert in memory (no disk)

✅

✅

✅

❌

❌

Separate broker / signing service

✅

✅

Partial

❌

❌

MCP-native (AI agents)

✅

✅ (2025)

✅ (2025)

❌

✅

OAuth2/OIDC on MCP transport

✅

✅

✅

❌

❌

Per-command policy + dry-run (AI-action firewall)

✅

❌

❌

❌

❌

Human-in-the-loop approval for AI commands

✅

❌

❌

❌

❌

Per-agent behavioral guardrails (anomaly/rate)

✅

❌

❌

❌

❌

Session recording (ASCIIcast v2, stdin+stdout+stderr)

✅

✅

❌

Partial

❌

Cryptographically chained audit log

✅

❌

❌

Partial

❌

Single-binary / simple self-hosted

✅

❌

❌

❌

✅

HSM/KMS for CA key

✅ (AKV, ssh-agent/HSM)

✅

✅

—

—

Teleport is the closest commercial equivalent — short-lived SSH certs, RBAC, and since 2025 Secure MCP; its Jan-2026 Agentic Identity Framework targets the same threat model. The difference is operational weight: Teleport needs a dedicated control-plane cluster, recording proxy, and web UI — orders of magnitude heavier than a Go binary + signer.

HashiCorp Vault SSH secrets engine is an SSH CA with full HSM/KMS support and (2025) its own MCP server, but it provides only the signing piece — you still build the execution layer (engine.go, session.go, the MCP tools) yourself.

StrongDM hides credentials but stores long-lived secrets rather than generating ephemeral certs in memory, making it weaker against exfiltration. Smallstep SSH CA is a lightweight OIDC-integrated SSH CA (close to cmd/signer) with no execution broker or MCP layer. ssh-mcp exposes SSH to LLMs over MCP but uses a static SSH key — the exact vulnerability this broker prevents. CyberArk PAM offers comparable JIT cert access but is a closed enterprise platform for human operators, not AI workloads.

Where it fits: MCP-native AI-agent access + in-memory ephemeral certs + separate signer + ASCIIcast recording + chained audit, as a small set of Go binaries without a cluster. Enterprise features (web UI, multi-region HA) are on the roadmap (see HANDOFF.md).

Install

  • Prebuilt binaries — each release ships infrabroker_<ver>_{linux,darwin}_{amd64,arm64}.tar.gz with all binaries, plus the installer tarball (infrabroker-v<ver>.tar.gz) that deploy/install.sh consumes for the systemd production path.

  • go install — go install github.com/luisgf/infrabroker/cmd/infrabroker@latest (pure Go, no CGO; same for the other cmd/ binaries).

  • Container — ghcr.io/luisgf/infrabroker (docker or podman, multi-arch; entrypoint is the stdio MCP frontend). See CONTAINERS.md, including a compose demo that runs the full stack against a toy host: cd examples/compose && docker compose up --build -d (or make demo).

  • From source — the Quickstart below.

Register with Claude Code in one line — native binary or container:

claude mcp add infrabroker -- ~/bin/infrabroker serve-mcp -config /secure/path/config.json
claude mcp add infrabroker -- docker run -i --rm -v /secure/path:/config \
  ghcr.io/luisgf/infrabroker -config /config/config.json

Quickstart

Fastest path (local, single binary): QUICKSTART.md takes you from git clone to your first ssh_execute in under 10 minutes with one binary and one config.json — no signer service, no PKI. The steps below set up the full remote stack (a separated signer); the containerised demo is under Install.

# 1. Build (make injects the version from the git tag into every binary)
make install                 # → ~/bin/{infrabroker,signer,broker,broker-ctl,mcp-broker,...}
# or a single binary:        make signer
# (plain `go build ./cmd/...` also works; it reports a dev-<commit> version)

# 2. Generate the local PKI + the two-service config (signer.json + config.json)
infrabroker init             # writes pki/, signer.json, config.json; --force to redo
# add --import-ssh-config to import hosts from ~/.ssh/config (Include followed;
# ProxyJump/ProxyCommand hosts are skipped with a note), --register-mcp to run
# `claude mcp add` for you

# 3. Start the signing service (must be running before the broker)
./signer.sh start

# 4. Add a host and reload
broker-ctl host add --name web01 --addr web01.example.com:22 --user deploy --scan \
  --groups prod-web --sudo
broker-ctl reload

# (--config is a global flag, before the subcommand; every binary takes --version)
broker-ctl --config /secure/path/signer.json host list
broker-ctl --version            # short; add --verbose for build details

Register the stdio MCP with your client:

// Claude Code — ~/.claude.json
"infrabroker": { "type": "stdio", "command": "/Users/<you>/bin/infrabroker",
                "args": ["serve-mcp", "-config", "/secure/path/config.json"] }

// OpenCode — ~/.config/opencode/opencode.json  (note: type "local", command is an array)
"infrabroker": { "type": "local",
                "command": ["/home/<you>/bin/infrabroker", "serve-mcp", "-config", "/secure/path/config.json"],
                "enabled": true }

Full setup — local vs external signing mode, the remote OAuth frontend, host fields, sudoers, PKI, and broker-ctl — is in OPERATIONS.md. Tool usage for the model is in USAGE.md.

API

Full reference: API.md.

Service

Endpoint

Auth

Description

Signer

POST /v1/sign

mTLS

Request an ephemeral SSH certificate

Signer

GET /v1/hosts

mTLS

List accessible hosts (filtered by caller groups)

Signer

POST /v1/reload

mTLS

Hot-reload signer.json without restart

Control plane

POST /v1/sign, /v1/approvals/{id}, …

mTLS

Forwarding + human approval

Broker HTTP

POST /v1/ssh_run

mTLS

Execute a one-shot SSH command

MCP HTTP

/.well-known/oauth-protected-resource

None

OAuth2 discovery (RFC 9728)

MCP HTTP

Streamable HTTP

OIDC Bearer

MCP tools

Security

The security posture — trust boundaries, the layered controls (RBAC, command policy, approval gate, guardrails, source-address/TTL pinning, chained audit, default-on secret redaction), and the explicit non-goals (mode=exec sessions are broker-preflighted but not host-enforced unless the host opts into sealed_exec, no KRL, secret redaction is best-effort regex matching rather than a guarantee, …) — is documented in THREAT_MODEL.md.

To report a vulnerability, see SECURITY.md. CI enforces gofmt, go vet, go test -race, and govulncheck on every push and PR.

Testing

make test                      # go test -race ./...  (cert build, policy/RBAC/sudo/PTY, hops, …)
bash lab/run_signer_lab.sh     # external signer: broker without ca_key + policy + denial
bash lab/run_mcp_lab.sh        # bastion + target (ProxyJump) MCP scenario
bash lab/run_lab.sh            # HTTP/mTLS frontend

License

Copyright (C) 2026 Luis González Fernández.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0 as published by the Free Software Foundation. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See LICENSE for the full text.

Available Tools

7 tools
ssh_executeA
Destructive

Execute a single command on a Linux host via SSH with an ephemeral credential. Prefer this tool over ssh_session_open when you only need to run one command or independent commands. Returns stdout, stderr and exit_code. exit_code != 0 means remote command failure, NOT a tool error; treat it like a process that exits with an error. BEFORE calling: use ssh_list_servers to learn the host capabilities. sudo=true ONLY if allow_sudo=true; if allow_sudo=false, DO NOT retry with sudo and inform the user. pty=true ONLY if allow_pty=true and the command needs a TTY (with pty, stdout and stderr are merged). ttl_seconds is optional; omit to use the maximum allowed by the host policy.

Inputs: server (required), command (required), pty, sudo, +3 more. Returns: serial, stderr, stdout, decision, +2 more

ssh_get_fileA
Read-only

Read a file from a Linux host via SSH with an ephemeral credential. Returns the content as text, or base64 (base64=true in the result) when the file is not valid UTF-8. REQUIRES allow_file_transfer=true on the host (see ssh_list_servers); if false DO NOT retry, the signer will reject it. The read runs as the host's configured SSH user (no sudo); the file must be readable by that user. A file larger than max_bytes (default: the broker's file_transfer_max_bytes, 512 KiB) is an ERROR, not a truncation. The content's sha256 is recorded in the audit log.

Inputs: path (required), server (required), max_bytes, ttl_seconds. Returns: size, base64, serial, sha256, +2 more

ssh_list_serversA
Read-only

List the hosts accessible to the caller with their capabilities (hosts outside the user's RBAC groups are not listed). ALWAYS call before ssh_execute or ssh_session_open. Fields per host: allow_sudo=true → the host accepts NOPASSWD sudo elevation (sudo=true may be used); allow_sudo=false → DO NOT attempt sudo, the signer will reject it. allow_pty=true → the host accepts PTY (pty=true or mode=pty may be used); allow_pty=false → DO NOT attempt PTY. allow_file_transfer=true → ssh_put_file and ssh_get_file may be used; allow_file_transfer=false → DO NOT attempt file transfers, the signer will reject them. jump → name of the bastion through which the host is reached (informational).

Returns: servers

ssh_put_fileA
Destructive

Write a file on a Linux host via SSH with an ephemeral credential. Creates or OVERWRITES the destination file with the given content. Use content_base64=true for binary data (the content field is decoded before writing). REQUIRES allow_file_transfer=true on the host (see ssh_list_servers); if false DO NOT retry, the signer will reject it. The write runs as the host's configured SSH user (no sudo); the destination must be writable by that user. On hosts with a command policy the transfer command (cat > path) must also be allowed by the policy. Content is limited by the broker's file_transfer_max_bytes (default 512 KiB). The content's sha256 is recorded in the audit log.

Inputs: path (required), server (required), content (required), mode, +2 more. Returns: serial, sha256, warnings, bytes_written

ssh_session_closeA

Close a persistent SSH session and release the connection. Always call when done working with a session; an unclosed session keeps its SSH connection until it is reaped when the opening certificate expires, or by the idle or maximum-lifetime timeout (whichever comes first).

Inputs: session_id (required). Returns: ok

ssh_session_execA
Destructive

Execute a command in a session opened with ssh_session_open. Returns stdout, stderr and exit_code. exit_code != 0 means remote command failure, NOT a tool error. The command is preflighted against the current signer policy before execution; target and bastion access, end-user groups, sudo, sudo_user, PTY, and the host's physical route are revalidated, and audit-mode policy warnings are returned in warnings. If a policy is enabled after a shell/pty session was opened, later commands in that session are rejected. Session state (current directory, environment variables) persists across calls when mode=shell or mode=pty.

Inputs: command (required), session_id (required). Returns: serial, stderr, stdout, decision, +2 more

ssh_session_openA

Open a persistent SSH session that reuses the connection across commands. Use when you need multiple commands with shared state (e.g. cd to a directory and then operate in it) or interactive programs. For isolated commands prefer ssh_execute (simpler, stronger isolation guarantee). Available modes: exec (default, independent commands), shell (stateful sh: cd and variables persist), pty (shell with TTY for interactive programs). sudo=true ONLY if allow_sudo=true (see ssh_list_servers); if allow_sudo=false DO NOT retry. mode=pty ONLY if allow_pty=true. Every ssh_session_exec is preflighted against the current signer policy, so policy reloads revalidate target and bastion access, end-user groups, sudo, sudo_user, PTY, and the host's physical route for already-open sessions. On command-policy hosts, mode=exec is allowed; mode=shell and mode=pty are rejected. Returns session_id for use with ssh_session_exec. IMPORTANT: always close the session with ssh_session_close when done; an open session holds an SSH connection and is otherwise closed when the certificate that opened it expires, or after an idle or maximum-lifetime timeout (whichever comes first).

Inputs: server (required), mode, sudo, sudo_user, +1 more. Returns: serial, session_id

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.5/5.0

    Scored across 7 tools

    Disambiguation5/5

    Each tool targets a distinct operation: single command execution, session-based execution, session lifecycle, file transfer, and host discovery. The descriptions explicitly guide tool selection, e.g., preferring ssh_execute for isolated commands and ssh_session_open for stateful sessions, leaving no ambiguity.

    Naming Consistency3/5

    Naming is mixed: ssh_get_file, ssh_put_file, and ssh_list_servers follow a verb_noun pattern, while ssh_session_open, ssh_session_exec, and ssh_session_close reverse the order to noun_verb. ssh_execute also lacks a noun. The prefix is consistent and readable, but the conventions are not uniform.

    Tool Count5/5

    Seven tools is ideal for an SSH broker: host discovery, single command execution, file transfer (get/put), and persistent session management (open/exec/close). Each tool serves a clear purpose without unnecessary overlap or bloat.

    Completeness5/5

    The surface covers the full remote-administration lifecycle: list hosts, run commands directly or via sessions, transfer files in both directions, and manage session resources. No critical operations are missing for the stated domain.

    Maintenance

    ActivityActive
    ResponsivenessUsually handled

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Self-hostable control plane for managing the full lifecycle of non-human identities (AI agents), with short-lived credential issuance, attestation, and an MCP authorization gateway for per-tool access control.
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to securely access encrypted secrets (SSH keys, API tokens, passwords) with real-time user approval via Passkey, and supports SSH remote execution through the MCP protocol.
      MIT
    • F
      license
      Not graded
      quality
      B
      maintenance
      Give AI agents Zero-Trust access to production infrastructure without the risks of granting them shell access. Actions are bounded by policy and an on-host runner.
      391
      -
    • A
      license
      Not graded
      quality
      B
      maintenance
      Local credential broker that enables AI agents to securely run CLI tools like SSH and MySQL without exposing passwords to the AI context, environment variables, or process listings.
      3
      MIT