Skip to content
ak5Public

About

Credential-injecting forward proxy for AI agents and other workloads

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

Charon

CI status Container image Rust 1.99 or newer MIT license

Charon ferrying souls across the river Styx

Charon is a transparent gateway and forward proxy that adds credentials to approved outbound requests. It also forwards secretless and caller-authenticated traffic through an exclusive workload gateway for ordinary proxy clients. It lets a workload call an API without putting the API credential in that workload's environment, filesystem, or container image.

AI agents are workloads from Charon's point of view. Charon can give an agent narrowly scoped access to an authenticated API without placing the long-lived credential inside the agent runtime. The same model works for CLIs, builds, development containers, and other programs.

For credential mediation, the workload sends an opaque capability reference instead of a real credential. Charon checks authorization, matches the request against local policy, obtains the credential from its unlocked KeePass database, and hydrates the reference only in the request sent upstream.

workload                         Charon                     API
no stored credential  ──▶  verify + apply policy  ──▶  authenticated request
capability reference        resolve credential + sanitize response

Charon is an early-stage project. Its explicit proxy, transparent TLS gateway, authorization, structured hydration, response mediation, KeePass credential storage, metadata-only receipts, and isolated tests are implemented.

Why use it?

AI agents and other software often need authenticated access to external services such as email, calendars, cloud platforms, customer-support systems, payment providers, or an organization's own APIs. Giving every workload a long-lived credential makes that credential available to the workload and to anything that compromises it.

Charon moves the credential into a smaller, separately operated process. A request is allowed only when all of these agree:

  • a signed, short-lived, single-use manifest in signed proxy mode, or an Infra-isolated listener bound to one workload in transparent/exclusive mode;
  • a named capability in Charon's configuration; and
  • the actual destination hostname, HTTP method, and path.

The workload cannot choose a secret, a secret-store item, or an unconfigured destination. Charon does not return brokered credentials to workloads and does not follow redirects after adding one.

Applications keep using their ordinary credential settings. The configured value is public policy identity, not a credential:

GH_TOKEN={{charon.github.read}}
POSTMARK_SERVER_TOKEN={{charon.postmark.send}}

An SDK or CLI treats these as normal values. Charon recognizes them only in the policy-declared authentication location and replaces them at the final outbound boundary.

Concepts

These names appear in the configuration and protocol:

Term Meaning
Workload The program making the outbound request, such as an AI agent, CLI, build, or development container.
Manifest A short-lived, signed authorization used by explicit-proxy clients. It identifies the workload and names one capability. Each manifest can be used once.
Capability A named permission in Charon's local policy, for example “read the current GitHub user.” It maps to one service and an exact set of methods and paths.
Capability reference Public syntax such as {{charon.github.read}}. It names local policy, never a database entry or secret.
Service An exact destination, typed hydration rule, KeePass reference, response mode, and resource limits.
KeePass store A read-only KDBX database unlocked by its owner through the HTTPS admin page. Only exact mapped Password fields resolve.
Realm One isolated Charon deployment: a process, configuration, KeePass database and unlocked memory, and policy.

The current pre-1.0 manifest also carries tenant, persona, workspace, and lease identifiers supplied by the issuer. They are integration context, not secret selectors or core Charon concepts. This part of the public contract is under review before 1.0.

How a signed credential request works

  1. A trusted issuer gives the workload a signed manifest for a named capability.
  2. The workload sends a normal proxy request to Charon with Proxy-Authorization: Charon <manifest> and the configured public capability reference in the configured authentication sink. In transparent mode, Infra routes an isolated workload to its policy-bound listener and no proxy setting or manifest header is required.
  3. Charon verifies the signature, expiry, realm identity, and single-use nonce.
  4. Charon resolves the capability from its own configuration and checks the request's exact host, method, and path.
  5. When configured, Charon requests a Telegram allow-once decision. It then resolves the policy-owned reference from its unlocked KeePass snapshot.
  6. Charon hydrates only the declared sink at the outbound boundary, mediates the response using its explicit streaming mode, and writes a metadata-only receipt.

For HTTPS, the workload connects through Charon using HTTP CONNECT and trusts the operator-provided Charon CA. The forward-proxy contract specifies that wire protocol. The transparent-gateway contract specifies interception, capability references, hydration, response modes, and the Infra routing boundary. Charon's ordinary health endpoints are described by OpenAPI.

Development

The project requires Rust 1.99 or newer. mise is optional; it installs the pinned toolchain and provides short names for common development commands.

mise install
mise run check

mise run <task> means “run a task defined in mise.toml.” For example, mise run dev runs the task named dev:

mise run dev

That command is equivalent to:

cargo run -- --config examples/charon.dev.toml

The development example contains synthetic paths and identifiers. Provision its KeePass file, private admin-state directory, and HTTPS certificate before starting it. Its workload proxy listens on 127.0.0.1:3129; the separate admin listener uses the configured HTTPS origin. The store starts locked. Tests create disposable synthetic KDBX files without requiring operator setup.

Run the individual checks directly if you do not use mise:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo deny check

Configuration

examples/charon.dev.toml is a minimal local configuration. examples/charon.toml shows the KeePass, HTTPS admin, TLS, identity, capability, and service settings used in an operator-managed explicit proxy. examples/transparent-gateway.toml shows a synthetic policy-bound transparent listener.

Configuration is deny-by-default:

  • destination hosts are exact names; wildcards are not supported;
  • capabilities list exact HTTP methods and paths;
  • remote destinations require HTTPS on port 443;
  • redirects are disabled;
  • request and response bodies have independent size limits; and
  • response parsing, compression, duration, idle time, and opaque media types are explicit policy;
  • unknown configuration fields are rejected.

KeePass and owner enrollment

Charon uses one concrete, read-only KeePass KDBX store. [keepass] names the private database and optional private key file. Each [[keepass.items]] maps a local secret_ref and realm persona to an exact canonical entry UUID. Charon reads only that entry's protected Password field; workloads cannot select entries.

The process boots locked. On first startup it prints a random enrollment code to the operator console, valid for five minutes. Retrieve it over SSH and open the configured HTTPS admin origin on your own device. Enter the code and create a passkey. Charon persists public registration data, never the passkey private key. Sign in with that passkey, enter the KeePass master password, and unlock. The master password is discarded after decryption; mapped values remain in secret-holding memory until explicit lock or process restart. Enroll a second passkey while signed in for recovery. There is no default admin password.

The admin listener needs a stable DNS origin, browser-trusted certificate, and its own TLS key. It is separate from workload listeners and the interception CA. Keep public passkey state in a private writable directory. See owner operations for configuration and recovery.

[admin] is required by the binary in either serving mode. mise run browser-admin-check separately verifies the UI with Chrome and Node 22+. The main quality gate does not run that browser-dependent test.

Telegram decisions

See BotFather setup and the two-password E2E fixture.

Optional [admin.telegram] settings select one positive private user/chat ID and exact capability or route names requiring approval. Store the bot token in an operator-only protected KeePass Password field and set keepass.telegram_bot_token_entry_id to its exact UUID, outside workload mappings. Start a private chat with the bot before using it. After HTTPS owner unlock, Charon sends an unlocked notification and allow-once/deny buttons for selected requests. Lock cancels pending approvals and stops the channel; restart requires another owner unlock. No bot token or master password is read from environment variables or password files. Each decision expires after at most two minutes; gateway deadlines may shorten it. Unavailable delivery, timeout, denial, and cancellation fail closed. Telegram never receives the vault password, enrollment code, or workload credential values.

Project boundaries

Charon owns the request-time data path: identity or isolated-listener binding, local policy, credential lookup, typed hydration, response mediation, proxying, metadata-only receipts, owner enrollment, and optional local Telegram decisions.

It does not own:

  • user, workspace, or lease management;
  • issuance of workload manifests;
  • secret-store provisioning and backup;
  • deployment or network policy; or
  • external control-plane approval rules and manifest issuance.

Those systems integrate through signed data and versioned contracts; Charon does not query an application's database on the request path. See the integration boundary map and machine-readable contracts.

Security

Charon handles credentials, so changes to authorization, proxying, KeePass storage, admin authentication, Telegram decisions, TLS, or logging deserve careful review. Please read SECURITY.md before reporting a vulnerability and see the threat model for the detailed guarantees, assumptions, and remaining risks.

The full local quality gate is:

mise run check

Other projects like Charon

  • Infisical Agent Vault: when to use its credential-management workflows and when to use Charon with KeePass.

Contributing and releases

Create feature branches from main and open pull requests to main. Required checks protect this single long-lived branch. Successful CI on merged commits publishes immutable container images; deployment remains an operator action. See the contribution policy.

Documentation

License

Charon is licensed under the MIT License.

Exclusive Hermes network gateway

The exclusive workload gateway provides a separate --gateway-config mode for ordinary HTTP(S) proxy clients, including reusable CONNECT tunnels. It binds one fixed isolated workload, supports secretless forwarding and typed credential sinks, and requires its own validated schema. Signed proxy authentication, transparent service lanes, and Hermes tool admission remain independent controls. Infra owns isolation, trust and cutover.

About

Credential-injecting forward proxy for AI agents and other workloads

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages