---
title: "Secrets"
description: "Configure HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, 1Password Connect, and OS Keyring as secret sources for agentsh."
doc_version: "1.0"
last_updated: "2026-05-20"
canonical: "https://www.agentsh.org/docs/secrets/"
---

# Secrets

Configure HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, 1Password Connect, and OS Keyring as secret sources for agentsh. Secrets are addressed via a URI scheme and consumed by HTTP services and other features that need credentials.

## Overview

The agentsh secrets layer is a unified abstraction over multiple secret stores. It lets operators reference credentials by URI — `vault://kv/github#token`, `aws-sm://prod/api-key`, `op://Personal/GitHub#token` — without embedding secrets in policy files or environment variables.

The most common consumer is [HTTP services](https://www.agentsh.org/docs/policy-reference/#http-services), which use `secret.ref` and `secret.format` fields on an `http_services:` entry to bind a service to a secret URI. When a session starts, agentsh fetches the real secret from the upstream provider, generates a paired fake credential, and stores both in a per-session substitution table. The agent only ever sees the fake; the daemon swaps in the real value at the network edge.

**When to use the secrets layer instead of plain environment variables:**

- Credentials live in an existing enterprise secret store (Vault, AWS Secrets Manager, etc.) and you want a single source of truth.

- Multiple agentsh policies need the same secret and you don't want to copy it into each policy file.

- You want secrets to live in the agentsh daemon (where they can be substituted in and out of agent traffic) rather than baked into every shell environment the agent inherits.

- You want secret rotation handled by the upstream secret store, not by editing config files.

## URI Scheme

Every secret reference in agentsh is a URI of the form `<provider>://<host>[/<path>][#<field>]`. The provider scheme determines which provider handles the lookup; the host and path together identify the secret within that provider (interpretation varies per provider — for Vault it's mount point + key path, for AWS Secrets Manager it's a path-style secret name); the optional fragment selects a field within a structured secret (e.g., the `token` field of a multi-field Vault KV entry). The host component is required — a URI like `vault:///github` with no host is rejected at parse time.

| Provider | URI prefix | Example | `#field` support |
| --- | --- | --- | --- |
| HashiCorp Vault | `vault://` | `vault://kv/github#token` | Yes (KV multi-field entries) |
| AWS Secrets Manager | `aws-sm://` | `aws-sm://prod/github-token` | Yes (JSON-shaped secrets) |
| GCP Secret Manager | `gcp-sm://` | `gcp-sm://github-token` | Yes (JSON-shaped secrets) |
| Azure Key Vault | `azure-kv://` | `azure-kv://github-token` | Yes (JSON-shaped secrets) |
| 1Password Connect | `op://` | `op://Personal/GitHub#token` | Yes (item field selector) |
| OS Keyring | `keyring://` | `keyring://agentsh/github-token` | No (rejected — entries are scalar) |

Resolution dispatches to the corresponding provider's lookup function based on the URI scheme. Providers are registered in the **policy file** under the top-level `providers:` key (see each provider section below for the schema). The secrets `providers:` key is unrelated to `proxy.providers` in `config.yml`, which configures Anthropic and OpenAI API base URLs.

## Providers

agentsh supports six provider backends. Each provider has its own schema, authentication methods, and URI format. The sub-sections below cover each in turn.

### HashiCorp Vault

[HashiCorp Vault](https://www.vaultproject.io/) is the most flexible backend agentsh supports. Use it when your organization already runs Vault or when you need fine-grained policies on individual secrets.

#### Schema

```yaml
providers:
  vault:                       # provider name (referenced by URIs)
    type: vault
    address: https://vault.example.com:8200
    namespace: my-namespace    # optional, Vault Enterprise only
    auth:
      method: token            # token | approle | kubernetes
      # --- for method: token ---
      token: hvs.CAESI...
      # token_ref: keyring://agentsh/vault_token  # chained alternative
      # --- for method: approle ---
      # role_id: my-role-id
      # secret_id: my-secret-id
      # role_id_ref: ...        # chained alternative
      # secret_id_ref: ...      # chained alternative
      # --- for method: kubernetes ---
      # kube_role: agentsh-prod
      # kube_mount_path: kubernetes        # default: "kubernetes"
      # kube_token_path: /var/run/secrets/kubernetes.io/serviceaccount/token
      #                                    # default shown
```

#### Authentication methods

- **`token`** — static token. Required field: `token` (or `token_ref` for chained sourcing). Use this for development or when sourcing the token from another provider via `token_ref` (see [Provider Chaining](https://www.agentsh.org/docs/secrets/#chaining)).

- **`approle`** — AppRole authentication. Required fields: `role_id` (or `role_id_ref`) and `secret_id` (or `secret_id_ref`). Use this for service-to-service authentication where the agentsh daemon has its own AppRole credentials. Both fields support chaining.

- **`kubernetes`** — Kubernetes ServiceAccount authentication. Required field: `kube_role`. Optional: `kube_mount_path` (defaults to `kubernetes`) and `kube_token_path` (defaults to `/var/run/secrets/kubernetes.io/serviceaccount/token`). Use this when running agentsh in a Kubernetes pod with a configured ServiceAccount.

#### URI format

`vault://<mount>/<path>[#<field>]`

Where `<mount>` is the Vault KV mount point (e.g., `kv`, `secret`) and `<path>` is the path to the secret within that mount. The optional fragment `#<field>` selects a single field from the secret's JSON body.

#### Example

```yaml
providers:
  vault:
    type: vault
    address: https://vault.corp.internal:8200
    auth:
      method: kubernetes
      kube_role: agentsh-prod
      kube_mount_path: kubernetes

# Reference the secret in an http_services entry:
http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: vault://kv/github#token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

[HashiCorp Vault documentation →](https://developer.hashicorp.com/vault/docs)

### AWS Secrets Manager

[AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) is the right backend when agentsh runs in AWS and your secrets already live in Secrets Manager.

#### Schema

```yaml
providers:
  awssm:
    type: aws-sm
    region: us-east-1
```

The only required field is `region`. There is no `auth:` block — authentication is delegated to the AWS SDK default credential chain.

#### Authentication

The AWS-SM provider calls `awsconfig.LoadDefaultConfig`, so it picks up credentials from the standard AWS SDK chain in this order:

1. Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`)

2. The shared credentials file (`~/.aws/credentials`), respecting `AWS_PROFILE`

3. EC2 instance profile credentials

4. ECS task role credentials (when running under ECS)

5. EKS service account credentials (IRSA, when running under EKS with a service account annotation)

To use a specific profile or assumed role, set the corresponding env vars or shared-config entries *outside* agentsh before invocation — the SDK will discover them. agentsh itself does not have a profile or role-arn field.

#### URI format

`aws-sm://<secret-name>[#<json-field>]`

Where `<secret-name>` is the Secrets Manager secret ID (the name or full ARN). The optional fragment selects a single field from a JSON-shaped secret. If omitted, the entire secret value is returned as a string.

#### Example

```yaml
providers:
  awssm:
    type: aws-sm
    region: us-east-1

http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: aws-sm://prod/github-token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

[AWS Secrets Manager documentation →](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html)

### GCP Secret Manager

[Google Cloud Secret Manager](https://cloud.google.com/security/products/secret-manager) is the right backend when agentsh runs in GCP and your secrets live in Secret Manager.

#### Schema

```yaml
providers:
  gcpsm:
    type: gcp-sm
    project_id: my-gcp-project
```

The only required field is `project_id`. There is no `auth:` block — authentication is delegated to Google Application Default Credentials (ADC).

#### Authentication

The GCP-SM provider calls `secretmanager.NewClient`, which uses Application Default Credentials. ADC discovers credentials from, in order:

1. The `GOOGLE_APPLICATION_CREDENTIALS` environment variable, if set, pointing at a service account JSON key file

2. The user credentials configured by `gcloud auth application-default login`

3. The attached service account on a GCE/GKE/Cloud Run/Cloud Functions instance

4. GKE Workload Identity, if configured

To use a specific service account, set `GOOGLE_APPLICATION_CREDENTIALS` in the environment before invoking agentsh. agentsh itself does not have a service-account-file field.

#### URI format

`gcp-sm://<secret-name>[#<field>]`

Where `<secret-name>` is the Secret Manager secret ID (just the name; the project comes from `project_id` in the provider config). The provider always reads `versions/latest`. The optional `#<field>` fragment selects a single JSON key when the secret value is JSON-shaped.

#### Example

```yaml
providers:
  gcpsm:
    type: gcp-sm
    project_id: my-prod-project

http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: gcp-sm://github-token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

[GCP Secret Manager documentation →](https://cloud.google.com/secret-manager/docs)

### Azure Key Vault

[Azure Key Vault](https://azure.microsoft.com/en-us/products/key-vault) is the right backend when agentsh runs in Azure and your secrets live in Key Vault.

#### Schema

```yaml
providers:
  azurekv:
    type: azure-kv
    vault_url: https://my-vault.vault.azure.net
```

The only required field is `vault_url`. There is no `auth:` block — authentication is delegated to `DefaultAzureCredential`.

#### Authentication

The Azure-KV provider calls `azidentity.NewDefaultAzureCredential`, which discovers credentials from the standard `DefaultAzureCredential` chain in order:

1. Environment variables (`AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET` for a service principal; or `AZURE_USERNAME`/`AZURE_PASSWORD` for a user)

2. Workload identity (when running on AKS with workload-identity federation enabled)

3. Managed identity (when running on a VM, App Service, Container Instance, or Function App with a managed identity)

4. Azure CLI (`az login`) credentials

5. Azure PowerShell (`Connect-AzAccount`) credentials

6. Azure Developer CLI (`azd`) credentials

To use a service principal explicitly, set the corresponding env vars outside agentsh. agentsh itself does not have a tenant-id/client-id/client-secret field set.

#### URI format

`azure-kv://<secret-name>[#<field>]`

Where `<secret-name>` is the Key Vault secret identifier (alphanumerics and hyphens only). The vault itself is determined by `vault_url` in the provider config, not by the URI. **Path components are not allowed** — a URI like `azure-kv://name/extra` is rejected. The optional `#<field>` fragment selects a single JSON key when the secret value is JSON-shaped.

#### Example

```yaml
providers:
  azurekv:
    type: azure-kv
    vault_url: https://prod-secrets.vault.azure.net

http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: azure-kv://github-token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

[Azure Key Vault documentation →](https://learn.microsoft.com/en-us/azure/key-vault/general/)

### 1Password Connect

[1Password Connect](https://developer.1password.com/docs/connect/) is the right backend for teams that use 1Password as their secrets store. agentsh talks to a self-hosted Connect server, not directly to the 1Password cloud. The provider type string is `op`, matching the URI scheme.

#### Schema

```yaml
providers:
  op:
    type: op
    server_url: https://op-connect.internal:8080
    api_key: eyJhbGciOi...
    # Or, recommended: chain api_key_ref to another provider
    # api_key_ref: keyring://agentsh/op_api_key
```

Required fields: `server_url` and exactly one of `api_key` or `api_key_ref`. The two are mutually exclusive — the parser rejects a config that sets both.

#### Authentication

1Password Connect uses a single API key (formerly called a Connect token) issued by your 1Password Connect server. The key authorizes agentsh to read items from the vaults the key has been granted access to. Two ways to provide it:

- **`api_key`** — the API key value, embedded in the config. Convenient for development but not recommended for production because it leaves the key in plaintext on disk.

- **`api_key_ref`** — a [chained secrets URI](https://www.agentsh.org/docs/secrets/#chaining) that resolves the API key from another provider (typically the OS keyring or Vault). Recommended for production.

#### URI format

`op://<vault>/<item>[#<field>]`

Where `<vault>` is the 1Password vault name, `<item>` is the item title within that vault, and the optional `#<field>` fragment selects a single field within that item (e.g., `password`, `token`, or a custom field name). If the fragment is omitted, the default credential field for the item is returned.

#### Example

```yaml
providers:
  kr:
    type: keyring
  op:
    type: op
    server_url: https://op-connect.corp.internal:8080
    api_key_ref: keyring://agentsh/op_api_key

http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: op://Engineering/GitHub#token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

[1Password Connect documentation →](https://developer.1password.com/docs/connect/)

### OS Keyring

The OS keyring provider reads secrets from the operating system's native secret store via the [freedesktop.org Secret Service API](https://specifications.freedesktop.org/secret-service/latest/) on Linux, the macOS Keychain, or the Windows Credential Manager. It is the right backend for development and for cases where you want to bootstrap other providers without storing tokens in plaintext.

#### Schema

```yaml
providers:
  kr:
    type: keyring
```

The keyring provider takes no configuration. It uses the OS-native secret store of the host running agentsh. There are no auth methods to configure — the OS handles authentication based on the user session.

#### URI format

`keyring://<service>/<account>`

Where `<service>` is the service name (typically `agentsh` or a sub-namespace) and `<account>` is the account or key name within that service. The mapping to the OS keyring depends on the platform:

- **Linux:** calls the freedesktop Secret Service API. The `service` and `account` become attributes on the secret entry.

- **macOS:** calls the Keychain via the Security framework. `service` maps to the keychain item's service name; `account` maps to the account.

- **Windows:** calls the Credential Manager. `service` and `account` together form the target name.

#### Storing a secret in the keyring

The keyring provider only reads — secrets must be stored in the OS keyring out of band. Common ways to store:

```bash
# Linux (using secret-tool from libsecret)
echo "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" | secret-tool store \
    --label="agentsh GitHub token" service agentsh account github-token

# macOS
security add-generic-password -s agentsh -a github-token \
    -w "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Windows (PowerShell)
cmdkey /generic:agentsh:github-token /user:agentsh \
    /pass:"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

#### Example

```yaml
providers:
  kr:
    type: keyring

http_services:
  - name: github
    upstream: https://api.github.com
    secret:
      ref: keyring://agentsh/github-token
      format: "ghp_{rand:36}"
    inject:
      header:
        name: Authorization
        template: "Bearer {{secret}}"
```

The keyring provider is also the canonical way to bootstrap other providers — see [Provider Chaining](https://www.agentsh.org/docs/secrets/#chaining) for an example of using the keyring to source a Vault token.

[freedesktop.org Secret Service specification →](https://specifications.freedesktop.org/secret-service/latest/)

## Provider Chaining

One provider can source its own credentials from another provider via `_ref` fields. Any field whose name ends in `_ref` is parsed as a secret URI and resolved before the parent provider is initialized. This lets you avoid putting bootstrap credentials in plaintext config files.

The canonical example: a Vault token sourced from the OS keyring.

```yaml
providers:
  kr:
    type: keyring
  vault:
    type: vault
    address: https://vault.corp.internal:8200
    auth:
      method: token
      token_ref: keyring://agentsh/vault_token
```

**How it resolves:**

1. `kr` is a keyring provider that needs no credentials of its own — it talks to the OS Secret Service.

2. When agentsh initializes the `vault` provider, it sees `token_ref` instead of `token` and resolves the URI by calling the `kr` provider.

3. The keyring returns the value stored under `agentsh/vault_token`, which is then passed to the Vault client as the auth token.

**Cycle detection.** Provider chains are validated at startup. If provider A's `_ref` resolves to provider B and B's `_ref` resolves back to A, agentsh refuses to start with an explicit cycle error. Self-references (a provider chained to itself) are also rejected.

**What can be chained.** Any field whose name ends in `_ref` on a provider's `auth` block. The full set of chained fields:

- **Vault:** `token_ref`, `role_id_ref`, `secret_id_ref`

- **1Password Connect:** `api_key_ref`

- **AWS Secrets Manager, GCP Secret Manager, Azure Key Vault:** no chained fields — auth is handled by the cloud SDK's default credential chain unconditionally

- **OS Keyring:** no chained fields — takes no auth config at all

## Lifecycle

**When secrets are fetched.** Secrets are fetched at session start, before the agent process is launched. When a session loads a policy that declares any `http_services:` entries with `secret` fields, the daemon constructs each provider in topological order (so chained `*_ref` providers build before their consumers), iterates over every declared service, fetches its referenced secret from the upstream provider, generates a paired fake credential, and stores both in a per-session substitution table. A secret declared in a policy file is fetched even if no rule ever uses it during the session — the bootstrap is unconditional. After each entry is added to the table, the temporary copy of the real secret is wiped from memory; the table itself retains the only copy.

**Caching and rotation.** Resolved secrets stay in the per-session substitution table for the lifetime of the session. They are not refreshed mid-session even if the upstream provider's value rotates — rotation takes effect on the next session. The table is zeroed at session cleanup.

**Failure mode.** Provider errors at bootstrap fail closed: if any fetch fails, any fake-generation fails, or any provider construction fails, all already-loaded entries are zeroed and session creation returns the underlying error. The agent process is never launched. There is no in-session "operation denied" path for a missing or unreachable secret — the entire session simply does not start. On success, agentsh emits a `secrets_initialized` log event with the session ID and the count of services bootstrapped.

## Sitemap

- [Canonical HTML](https://www.agentsh.org/docs/secrets/)
- [Site map](https://www.agentsh.org/sitemap.md)
- [Full documentation](https://www.agentsh.org/llms-full.md)
