Configuration
AgentSec is configured via agentsec.yaml. Credential values are never stored in this file — they come from environment variables.
Full Example
version: 1
credentials:
slack:
description: "Slack API"
api_base: "https://slack.com/api"
# connector: direct (default -- injects credential into Authorization header)
# auth_header_format: "Bearer {value}" (default)
twitter:
description: "Twitter API v2"
connector: sidecar
api_base: "http://oauth-signer:8080"
telegram:
description: "Telegram Bot API"
connector: sidecar
api_base: "http://telegram-client:8082"
relative_target: true
openai-key:
description: "OpenAI API key"
api_base: "https://api.openai.com"
substitution:
body: true # allow <CREDENTIAL:openai-key> in request bodies
approval:
channel: telegram
timeout_seconds: 300
default_approvals_required: 1
policies:
slack:
auto_approve: ["GET"]
require_approval: ["POST", "PUT", "DELETE"]
auto_approve_urls:
- "/conversations.list"
- "/users.list"
approval:
allowed_approvers: ["123456789"]
telegram:
chat_id: "-100987654321"
twitter:
auto_approve: ["GET"]
require_approval: ["POST", "PUT", "DELETE"]
openai-key:
auto_approve: ["POST"]
require_approval: []
agents:
my-agent:
description: "Social media agent"
credentials:
- slack
- twitter
rate_limit_per_hour: 100
research-bot:
description: "Research assistant"
credentials:
- openai-keyCredentials
Each entry defines a service the proxy can authenticate to. The actual secret value comes from the AGENTSEC_CRED_{NAME} environment variable (name uppercased, hyphens become underscores).
| Field | Type | Default | Description |
|---|---|---|---|
description | string | required | Human-readable description |
api_base | string | none | Base URL for the API. Required for sidecar connectors |
connector | direct | sidecar | direct | Routing strategy (see How It Works) |
relative_target | bool | false | When true, X-AgentSec-Target is a path prepended with api_base. Requires connector: sidecar |
auth_header_format | string | "Bearer {value}" | Authorization header format for direct connectors. Use {value} as the credential placeholder |
substitution.headers | bool | true | Allow <CREDENTIAL:name> placeholders in headers (always true) |
substitution.body | bool | false | Allow <CREDENTIAL:name> placeholders in request bodies |
substitution.body_content_types | string[] | ["application/json", "application/x-www-form-urlencoded"] | Content types where body substitution is allowed |
Approval
Global approval channel configuration.
| Field | Type | Default | Description |
|---|---|---|---|
channel | string | required | Approval channel type. Only "telegram" in v0.1 |
timeout_seconds | int | 300 | Seconds to wait for approval before timing out (504) |
default_approvals_required | int | 1 | Number of approvals needed per request |
Policies
Per-credential policy rules. If a credential has no policy, all requests require approval (fail closed).
| Field | Type | Default | Description |
|---|---|---|---|
auto_approve | string[] | [] | HTTP methods that skip approval (e.g., ["GET"]). HEAD follows GET |
require_approval | string[] | [] | HTTP methods that always require approval |
auto_approve_urls | string[] | [] | URL substring patterns that skip approval regardless of method |
approval.allowed_approvers | string[] | [] | Telegram user IDs that can approve. Empty = anyone can approve |
approval.telegram.chat_id | string | global default | Override Telegram chat for this credential’s approvals |
See Policies & Approval for evaluation order and examples.
Agents
Each agent gets an API key (set via AGENTSEC_AGENT_KEY_{NAME}) and a whitelist of credentials it can access.
| Field | Type | Default | Description |
|---|---|---|---|
description | string | none | Human-readable description |
credentials | string[] | required | Credential names this agent can use |
rate_limit_per_hour | int | unlimited | Max requests per hour (429 if exceeded) |
Validation Rules
The proxy validates config at startup and rejects invalid configurations:
- Agent credential references must exist in the
credentialssection connector: sidecarrequiresapi_baseto be setrelative_target: truerequiresconnector: sidecar