Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions docs/permit-mcp-gateway/http-egress-proxy/authorization.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Authorization & Trust
sidebar_label: Authorization & Trust
description: How egress rules, Permit.io policy, and human consent compose — including per-human trust ceilings that cap how much access a person can delegate to an agent.
sidebar_position: 5
---

# Authorization & Trust

An allowed outbound request passes through **two independent gates**. Both must say yes. This mirrors how the gateway authorizes MCP tool calls, so the same mental model — and the same Permit policy environment — governs both planes.

## The two gates

```mermaid
flowchart TB
Req["Outbound request"]
Rule{"1. Egress rule<br/>host / path / method"}
Permit{"2. Permit policy<br/>agent's role on the host"}
Ceiling{"Trust ceiling<br/>(delegated agents)"}
Allow["Forwarded"]
Deny["Denied"]

Req --> Rule
Rule -->|"no match or block"| Deny
Rule -->|"allow"| Permit
Permit -->|"deny"| Deny
Permit -->|"allow"| Ceiling
Ceiling -->|"over ceiling"| Deny
Ceiling -->|"within ceiling"| Allow
```

### Gate 1 — Egress rules

The [egress rules](./egress-rules) you author are the coarse "is this host/path/method even on the menu" check. A request with no matching `allow` rule is denied before any policy evaluation. This is the operator-controlled allow-list.

### Gate 2 — Permit.io policy

For requests that an `allow` rule permits, the gateway then asks your **Permit.io** policy whether *this agent* is allowed to perform *this kind of action* on *this host*. The request's method class maps to an action (read, write, delete, and so on), and the host becomes a Permit resource. Because every gateway host maps 1:1 to a Permit environment, you manage these policies in the same place as your MCP policies — see [Permit.io Integration](/permit-mcp-gateway/permit-integration).

This split means an operator can broadly allow a host at the proxy while your central policy still decides, per agent, what that host's access actually permits.

## Human consent and trust ceilings

Agents usually act **on behalf of a human**. The proxy supports the same delegation-with-consent model the gateway uses for MCP: a person explicitly authorizes an agent to make egress calls for them, and the access an agent gets through that person is capped by a **trust ceiling**.

### Trust ceilings

An admin sets, per human and per host, the **maximum** trust level that person is allowed to delegate — `low`, `medium`, or `high`. When a human consents to an agent, the access that agent receives is the **lesser** of what the human grants and the admin-defined ceiling. A person can never delegate more than their ceiling allows.

This has an important security property: an agent that acts for **several** humans does **not** get to combine their ceilings. Each human caps their own delegation independently, so one person's grant can't be used to escalate another's.

### Human consent

To have a human delegate egress access to an agent, run the consent flow:

```bash
asg proxy authorize <agent-client-id> --host api.github.com

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] authorize uses a required --hosts flag, not repeatable --host; --trust default is low

Problem: The example asg proxy authorize <agent-client-id> --host api.github.com and the prose "Pass multiple --host flags … The optional --trust low|medium|high flag … omit it to default to least privilege" do not match the implementation (agent-security/packages/agent-security-cli/src/commands/proxy.ts, authorizeCommand):

  • The option is --hosts (plural), comma-separated and required (demandOption: true), with per-host host:trust syntax — e.g. --hosts api.github.com:medium,api.openai.com:low. There is no repeatable --host.
  • --trust sets the default level for hosts given without an explicit :trust, and its default value is low (not an unset "least privilege").
  • The command also typically needs --consent-url https://<tenant>.agent.security (or AGENT_SECURITY_CONSENT_URL).

Suggestion:

asg proxy authorize <agent-client-id> \
  --hosts api.github.com:medium \
  --consent-url https://acme.agent.security

Describe --hosts as required/comma-separated with host:trust, and --trust as the default for hosts lacking an explicit level (default low).

```

This opens a browser where the human signs in and chooses what to allow:

1. **Sign in** — the human authenticates.
2. **Review the hosts** — the agent is requesting egress to specific hosts.
3. **Choose an access level** — defaulting to least privilege, and capped at the admin's ceiling for that human and host.
4. **Approve** — a short-lived, human-bound token is issued for the agent.

Pass multiple `--host` flags to request several hosts at once. The optional `--trust low|medium|high` flag lets the human (or the operator preparing the request) propose a lower cap than the ceiling; omit it to default to least privilege.

The result is a token whose access is bound to that specific human's consent — and which the human can revoke.

### Revocation

A human can revoke an agent's delegated access at any time from their account. Revocation is enforced **immediately**: in-flight and subsequent requests using a revoked delegation are denied, not just future token issuance. This is the egress equivalent of revoking an MCP consent.

## How automated agents differ

Not every agent acts for a human. A CI job or backend service can be issued a token directly with [`asg proxy token create`](./quickstart#4-mint-an-agent-access-token). Such a token isn't bound to a human, so the per-human trust ceiling doesn't apply — its access is governed purely by the egress rules and the agent's own Permit policy. Use direct tokens for machine-to-machine automation, and the consent flow whenever a real person is accountable for what the agent does.

---

## What's next

- [**Egress Rules**](./egress-rules) — the operator allow-list that forms the first gate.
- [**Permit.io Integration**](/permit-mcp-gateway/permit-integration) — the policy model behind the second gate.
- [**Security**](./security) — the protections that wrap both gates.
110 changes: 110 additions & 0 deletions docs/permit-mcp-gateway/http-egress-proxy/cli.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: The asg CLI
sidebar_label: asg CLI
description: Install and use the asg command-line tool — the operator's front door for enabling the HTTP Egress Proxy, managing rules and credentials, minting agent tokens, and wiring agents into the proxy.
sidebar_position: 2
---

# The `asg` CLI

`asg` is the command-line tool for managing the Permit MCP Gateway, including the entire HTTP Egress Proxy control plane. Anything you can do in the **Proxy** section of the [dashboard](https://app.agent.security) — enable the proxy, manage rules and credentials, mint tokens, run diagnostics — you can do with `asg`, scripted and CI-friendly.

The CLI is the operator and automation surface. End users who simply delegate access to an agent normally do that through the browser consent flow, not the CLI.

## Install

```bash
npm install -g @permit-io/agent-security-cli
```

Verify the install:

```bash
asg --help
asg proxy --help
```

## Configure

`asg` resolves settings in priority order: environment variables, then a config file at `~/.agent-security/`, then built-in defaults.

```bash
# Point at your gateway and store an admin token (saved with restrictive permissions).
asg config set gateway-url https://gateway.example.com
asg login --token <admin-token>

# Verify the token against the gateway.
asg whoami
```

You can also supply settings through environment variables, which is the preferred approach in CI:

| Variable | Purpose |
| --- | --- |
| `AGENT_SECURITY_API_KEY` | Admin token used to authenticate control-plane commands. |
| `AGENT_SECURITY_GATEWAY_URL` | Your gateway's admin URL. |
| `AGENT_SECURITY_SUBDOMAIN` | Default host subdomain, so you can omit it from each command. |
| `AGENT_SECURITY_CONSENT_URL` | Consent origin used by `asg proxy authorize` (usually auto-derived). |
| `AGENT_SECURITY_PROXY_TOKEN_FILE` | Path to the agent's proxy token file (set by `asg proxy env`). |

:::warning Treat the admin token as a high-value secret
Prefer the interactive prompt or `AGENT_SECURITY_API_KEY` over passing the token as a `--token` flag — command-line flags are visible to other users on the machine via the process list. The CLI scrubs secret-shaped strings from its own error output, but the process list is outside its control.
:::

## Output and exit codes

Every command supports machine-readable output so agents and CI can drive it deterministically:

```bash
asg proxy rules list acme --json --quiet
```

- `--json` emits structured JSON to stdout.
- `--quiet` drops decorative output (spinners, hints).
- `--yes` accepts confirmation prompts non-interactively.

Exit codes are stable:

| Code | Meaning |
| --- | --- |
| `0` | Success |
| `1` | User error — bad input, missing token, cancelled prompt, or a human-denied approval |
| `2` | Server error — gateway unreachable, 5xx, or network failure |

## The `asg proxy` command tree

| Command | What it does |
| --- | --- |
| `asg proxy config <host> --enable\|--disable` | Turn proxy mode on or off for a host. |
| `asg proxy rules list\|add\|update\|delete\|reorder` | Manage egress rules. See [Egress Rules](./egress-rules). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] asg proxy rules has no update or reorder subcommand

Problem: This row lists asg proxy rules list|add|update|delete|reorder, but the implemented rules group registers only list, add, and delete (agent-security/packages/agent-security-cli/src/commands/proxy.ts, the rulesGroup builder chains rulesListCommand, rulesAddCommand, rulesDeleteCommand). There is no rules update and no rules reorder. The egress-rules.mdx page shows both (asg proxy rules reorder ... and asg proxy rules update ...), which will fail.

Suggestion: Document only list|add|delete. If reorder/update are dashboard-only, say so (the dashboard does support drag-to-reorder and inline edit per the same page) rather than implying CLI parity.

| `asg proxy credentials list\|create\|update\|delete` | Manage stored upstream secrets (write-only). See [Credentials](./credentials). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] asg proxy credentials command group does not exist

Problem: This row documents asg proxy credentials list|create|update|delete, but the asg CLI registers no credentials subcommand under proxy. The actual proxy command tree is config, rules (list/add/delete), container-config, env, doctor, connect, preset (list/apply), token (create), authorize, and ca (status/download/rotate/trust-shell) — verified in agent-security/packages/agent-security-cli/src/commands/proxy.ts (the proxyCommand group registration). Static credentials are created via the dashboard, asg proxy connect (OAuth), or asg proxy preset apply; there is no CLI command to create a static header/query/basic_auth credential. Readers who copy asg proxy credentials create (used throughout Quick Start and Credentials) will hit "unknown command".

Suggestion: Remove the credentials row, or replace it with the real surface (OAuth via asg proxy connect, preset packs via asg proxy preset apply, and the dashboard for static secrets), and fix the dependent examples in quickstart.mdx and credentials.mdx.

| `asg proxy connect <provider>` | Connect an OAuth provider (`github_app`, `notion`, `google`, `atlassian`) and store the resulting credential. |
| `asg proxy token create <host> --client-id <id>` | Mint a short-lived agent proxy token (`--out <file>` writes it securely). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] token create requires --subject and has no --out flag

Problem: This row shows asg proxy token create <host> --client-id <id> with "--out <file> writes it securely". The implemented command (agent-security/packages/agent-security-cli/src/commands/proxy.ts, tokenCreateCommand) requires both --client-id and --subject (both demandOption: true), and defines no --out option — the token is printed to stdout and you redirect it (the command's own example is asg proxy token create acme --client-id ci-runner --subject svc-ci --quiet > token). As written, the documented invocation fails (missing required --subject) and --out is rejected as an unknown flag. The same --out pattern is repeated in quickstart.mdx step 4.

Suggestion: Document --client-id <id> --subject <sub> as required, and replace --out <file> with the redirect form (--quiet > token-file, then chmod 600). Note the optional --ttl (default 900s, max 3600).

| `asg proxy authorize <client_id>` | Run the browser consent flow so a human can delegate access to an agent within a trust ceiling. |
| `asg proxy preset list\|apply` | Browse and apply preset rule + credential packs for common providers. |
| `asg proxy env <host>` | Print the `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` environment for the current shell. |
| `asg proxy container-config <host>` | Emit Docker, Docker Compose, or Kubernetes ConfigMap bootstrap config. |
| `asg proxy ca status\|download\|rotate\|trust-shell` | Manage the per-host TLS-interception certificate authority. See [Connecting Agents](./connecting-agents#https-interception). |
| `asg proxy doctor <host>` | Diagnose proxy setup end to end. |

Run `asg proxy <command> --help` for the full flag list of any command.

## Passing the host subdomain

Most commands take the host subdomain as a positional argument (e.g. `asg proxy config acme`). If you've set a default with `asg config set subdomain acme` (or `AGENT_SECURITY_SUBDOMAIN`), you can omit it. Commands that already take another positional accept the host as a `--subdomain` flag instead.

## Shell completions

Enable tab-completion for your shell:

```bash
asg completion --shell zsh >> ~/.zshrc # or: --shell bash >> ~/.bashrc
```

---

## What's next

- [**Egress Rules**](./egress-rules) — the rule model in depth.
- [**Credentials & Connections**](./credentials) — static secrets, OAuth connections, and request signing.
- [**Connecting Agents**](./connecting-agents) — `asg proxy env`, `container-config`, and `doctor` in context.
96 changes: 96 additions & 0 deletions docs/permit-mcp-gateway/http-egress-proxy/connecting-agents.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
title: Connecting Agents
sidebar_label: Connecting Agents
description: Route an agent's outbound traffic through the HTTP Egress Proxy — shell, Docker, and Kubernetes setup, the proxy access token, HTTPS interception, and the doctor diagnostic.
sidebar_position: 6
---

# Connecting Agents

The proxy uses the standard `HTTP_PROXY` / `HTTPS_PROXY` convention, so most HTTP client libraries route through it automatically once the environment is set. Connecting an agent has two parts: **the environment variables** that point traffic at the gateway, and **a proxy access token** the agent presents to authenticate.

## The pieces

| Piece | What it is |
| --- | --- |
| `HTTP_PROXY` / `HTTPS_PROXY` | Point your agent's outbound HTTP and HTTPS at the gateway. |
| `NO_PROXY` | Hosts that should bypass the proxy (e.g. localhost). |
| Proxy access token | A short-lived token the agent presents to the proxy. Minted with [`asg proxy token create`](./quickstart#4-mint-an-agent-access-token) or the [consent flow](./authorization#human-consent), and referenced via a token file. |

You rarely set these by hand — `asg proxy env` and `asg proxy container-config` generate them for you.

## Shell / local process

```bash
eval "$(asg proxy env acme)"
```

This exports `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, and the path to the agent's token file into the current shell. Any process launched from that shell now routes its outbound traffic through the proxy. Mint the token first (step 4 of the [Quick Start](./quickstart)).

## Docker and Kubernetes

Generate ready-to-use container configuration:

```bash
# Docker env file or Compose snippet.
asg proxy container-config acme --format docker-env
asg proxy container-config acme --format docker-compose

# Kubernetes ConfigMap.
asg proxy container-config acme --format k8s-configmap
```

Mount or reference the emitted configuration in your agent's container so the proxy variables are present in its environment. Supply the proxy token through your platform's normal secret mechanism (a mounted file or secret), and point `AGENT_SECURITY_PROXY_TOKEN_FILE` at it.

## HTTPS interception

By default the proxy handles HTTPS in **passthrough** mode: it authenticates and applies host-level rules, but the encrypted tunnel is forwarded opaquely — the proxy does not see the request path or body, and it can't inject a credential or scrub the response inside the tunnel.

To apply **full** governance to HTTPS — path-level rules, credential injection, response scrubbing, and approval gates inside the encrypted connection — switch the relevant rule to **intercept** mode. You set a rule's TLS mode in the [dashboard](https://app.agent.security) rule editor (**Proxy → Rules**, edit the rule, set **TLS mode** to **Intercept**); the CLI creates rules in passthrough mode.

In intercept mode the proxy terminates the agent's TLS using a **certificate authority issued for your host** and re-applies every check to the decrypted request. For your agent to trust those connections, it must trust that CA certificate — manage it with the CLI:

```bash
# Inspect your host's interception CA.
asg proxy ca status acme

# Download the CA certificate to install in your agent's trust store.
asg proxy ca download acme --output ./agent-security-ca.pem

# Print a shell snippet that points common tools at the CA.
asg proxy ca trust-shell acme

# Rotate the CA, keeping the previous one valid during a grace window.
asg proxy ca rotate acme --grace-days 7
```

:::note Choosing a mode
Use **passthrough** when host-level control is enough, or for very large uploads, downloads, and long-lived streaming connections. Use **intercept** when you need path-level rules, credential injection, or response scrubbing on HTTPS traffic. Mode is per rule, so you can mix the two across your rule set.
:::

## Diagnose with `doctor`

When something isn't connecting, run the built-in diagnostic:

```bash
asg proxy doctor acme
```

`doctor` checks, end to end:

- Gateway reachability
- Whether the proxy is enabled for the host
- How many rules and credentials are configured
- Your local proxy environment variables
- The interception CA's status and expiry, and whether your environment trusts it
- The token file's permissions and the token's expiry

Each check reports a clear pass/fail with a suggested fix, so it's the first thing to run whenever an agent's traffic isn't behaving.

---

## What's next

- [**Quick Start**](./quickstart) — the end-to-end setup these commands fit into.
- [**Security**](./security) — what the proxy enforces on the traffic you route through it.
- [**The `asg` CLI**](./cli) — full command reference.
99 changes: 99 additions & 0 deletions docs/permit-mcp-gateway/http-egress-proxy/credentials.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Credentials & Connections
sidebar_label: Credentials & Connections
description: Store upstream API secrets in the gateway and inject them into outbound requests server-side — static keys, OAuth connections, and AWS request signing — so your agents never hold the credentials they use.
sidebar_position: 4
---

# Credentials & Connections

The proxy can attach an upstream API's credential to outbound requests **server-side**, so your agents call third-party APIs without ever holding the keys. You store the secret once in the gateway; an [egress rule](./egress-rules) names it; the proxy injects it on the way out and [scrubs it](./security#response-scrubbing) from the response on the way back.

This is one of the proxy's most important properties: **the secret never leaves the gateway**. It isn't in the agent's prompt, environment, or memory, so it can't leak through logs or be exfiltrated by prompt injection.

## Credentials are write-only

Once stored, a secret can never be read back through the API, the CLI, or the dashboard — only **overwritten** or **deleted**. Listing credentials shows their names, target hosts, and whether a secret is set — never the secret value itself. This holds for everyone, including admins.

## Static credentials

A static credential is a fixed secret (an API key, bearer token, or basic-auth password) that you supply. You choose **how** it's injected:

| Injection method | What it does |
| --- | --- |
| **`header`** | Adds a request header. You set the header name and a value template containing `{secret}` (e.g. `Authorization: Bearer {secret}`). |
| **`query`** | Adds a query-string parameter. You set the parameter name. |
| **`basic_auth`** | Sets HTTP Basic authentication from a username plus the stored secret. |

```bash
# Bearer token in an Authorization header.
asg proxy credentials create stripe acme \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MEDIUM] Static-credential example uses the non-existent asg proxy credentials create command

Problem: Both static-credential examples here invoke asg proxy credentials create ... --injection ... --header-name/--param-name ... --value-template ... --secret-file .... The CLI implements no credentials subcommand under proxy (agent-security/packages/agent-security-cli/src/commands/proxy.ts) — these flags and the command don't exist. The injection methods (header/query/basic_auth) and write-only semantics described in the prose are real (they're dashboard form fields and gateway behavior), but they are not reachable through this CLI command.

Suggestion: Present static-credential creation as a dashboard task (Proxy → Credentials), keep the injection-method table as conceptual reference, and reserve the CLI examples for asg proxy connect (OAuth) and asg proxy preset apply which do exist.

--host api.stripe.com \
--injection header \
--header-name Authorization \
--value-template "Bearer {secret}" \
--secret-file ./stripe.key

# API key as a query parameter.
asg proxy credentials create weather acme \
--host api.weather.example \
--injection query \
--param-name apikey \
--secret-file ./weather.key
```

Each credential is **bound to one or more hosts** — it's only ever injected on requests to those hosts, so a credential for one API can never be sent to another.

:::tip Supply secrets without exposing them
Prefer `--secret-file` (or piping the secret in) over `--secret` on the command line, so the value doesn't land in your shell history or the process list.
:::

## OAuth connections

For providers that use OAuth, you don't paste a static token — you run a browser-based connect flow that completes the OAuth handshake and stores the resulting grant. The proxy then injects a valid access token on each request and handles refresh for you.

Supported providers:

- `github_app`
- `notion`
- `google`
- `atlassian`

```bash
asg proxy connect github_app acme \
--key github \
--client-id <oauth-client-id> \
--client-secret-file ./github-client-secret \
--host api.github.com
```

This opens a browser to authorize the connection, then stores the credential under the key you chose (`github` above) — ready to be referenced from an [egress rule](./egress-rules).

**Dashboard:** **Proxy → Credentials** lets you create OAuth connections and static credentials through a guided form.

## AWS request signing

For AWS APIs, the proxy can sign outbound requests with **AWS SigV4**, so your agents can call AWS services without ever holding AWS keys. Rather than storing a long-lived access key, the gateway mints **temporary credentials** (via STS `AssumeRole`) and signs each request server-side.

You configure AWS request signing in the [dashboard](https://app.agent.security) under **Proxy → Credentials** as an AWS credential, then bind it to the relevant AWS host(s) like any other credential.

## Preset packs

Presets bundle a ready-made set of rules plus a credential placeholder for a common provider, so you can wire up a known API in one step instead of authoring rules by hand. Browse and apply them:

```bash
asg proxy preset list
asg proxy preset apply <preset-name> acme --secret-file ./provider.key
```

`apply` previews what it will create before writing, so you can review the rules and credential it adds.

**Dashboard:** **Proxy → Presets**.

---

## What's next

- [**Egress Rules**](./egress-rules) — reference a credential from an `allow` rule with `--credential`.
- [**Security**](./security#response-scrubbing) — how injected secrets are scrubbed from responses.
- [**Connecting Agents**](./connecting-agents) — route an agent's traffic so injection takes effect.
Loading