Secret Policies API
Secret policies tell matching proxies how to apply a credential at the egress boundary, so workloads never see the real value. See Credential Proxying for the runtime semantics, and Static Secrets for source backends.
Each policy is either in inject mode (the proxy adds a header or query parameter to matching requests) or replace mode (the proxy swaps a placeholder token in the URL path for the real value). The two modes are mutually exclusive: a policy carries either an inject_config or a replace_config, never both.
Base path: /v1/policies/secrets
The Secret Policy Object
Inject mode:
{
"id": "spol_01H...",
"name": "openai-key",
"active": true,
"priority": 0,
"match_tags": ["production"],
"mode": "inject",
"rules": [
{ "host": "api.openai.com", "paths": ["/v1/*"], "methods": ["POST"] }
],
"source": { "type": "env", "var": "OPENAI_API_KEY" },
"inject_config": {
"header": "Authorization",
"formatter": "Bearer {{ .Value }}"
},
"created_at": "2026-05-08T12:00:00Z",
"updated_at": "2026-05-08T12:00:00Z"
}Replace mode:
{
"id": "spol_01H...",
"name": "telegram-bot",
"active": true,
"priority": 0,
"match_tags": ["production"],
"mode": "replace",
"rules": [
{ "host": "api.telegram.org", "paths": ["/bot*"], "methods": [] }
],
"source": { "type": "env", "var": "TELEGRAM_BOT_TOKEN" },
"replace_config": { "proxy_value": "PROXY-BOT-TOKEN" },
"created_at": "2026-05-08T12:00:00Z",
"updated_at": "2026-05-08T12:00:00Z"
}Fields
| Field | Type | Description |
|---|---|---|
id | string | Server-assigned opaque ID, prefixed with spol_. |
name | string | URL-safe name, unique within the organization. Must match [a-z0-9]+(-[a-z0-9]+)*. |
active | boolean | When false, the policy is stored but not delivered to proxies. Defaults to true. |
priority | integer | Tie-breaker when more than one policy applies. Lower wins. Required. |
match_tags | string[] | Tags a proxy must carry for the policy to apply. Empty applies to every proxy. |
mode | string | "inject" or "replace". |
rules | object[] | Request rules that scope which traffic the credential applies to. Same shape as network policy rules. |
source | object | Where the proxy reads the real credential from. See Source object. |
inject_config | object | Present only in inject mode. See Inject config. |
replace_config | object | Present only in replace mode. See Replace config. |
created_at | string | RFC 3339 timestamp. |
updated_at | string | RFC 3339 timestamp. |
Source Object
The source object tells the proxy where to resolve the real credential at startup. The exact set of fields depends on the source type. See Static Secrets / Secret Sources for the full list of supported backends.
| Field | Type | Description |
|---|---|---|
type | string | One of env, aws_sm, aws_ssm. Defaults to env. |
var | string | Environment variable name. Required when type is env. |
secret_id | string | AWS Secrets Manager ARN. Required when type is aws_sm. |
name | string | Parameter Store name. Required when type is aws_ssm. |
region | string | AWS region override. |
json_key | string | JSON key to extract from a JSON-encoded secret value. |
ttl | string | Cache TTL like 15m, 1h. Format: digits followed by h, m, or s. |
with_decryption | boolean | Decrypt SecureString parameters (Parameter Store only). |
Inject Config
Used when mode is "inject". Set either header or query_param, not both.
| Field | Type | Description |
|---|---|---|
header | string | Header name to set. |
query_param | string | Query parameter name to append. |
formatter | string | Go template that produces the header value. Receives .Value and a base64 helper. Required for non-trivial header formats. |
Replace Config
Used when mode is "replace". The proxy looks for proxy_value in the URL path and replaces it with the resolved secret before forwarding.
| Field | Type | Description |
|---|---|---|
proxy_value | string | URL-safe placeholder that appears in workload requests. Must be alphanumeric, -._~, or %XX escapes. Required. |
List Secret Policies
GET /v1/policies/secretsReturns every secret policy in the calling organization, ordered by priority ascending.
Query Parameters
| Name | Type | Description |
|---|---|---|
name | string | Exact match on policy name. |
active | boolean | When supplied, returns only policies with that active state. |
curl https://api.iron.sh/v1/policies/secrets \
-H "Authorization: Bearer $IRON_API_KEY"Create a Secret Policy
POST /v1/policies/secretsRequest Body
| Field | Type | Required |
|---|---|---|
name | string | Yes |
priority | integer | Yes |
mode | string | Yes (inject or replace) |
source | object | Yes |
inject_config | object | When mode is inject |
replace_config | object | When mode is replace |
active | boolean | No |
match_tags | string[] | No |
rules | object[] | No |
Submitting a payload with both inject_config and replace_config is allowed: the server clears the config that does not match mode. Submit only the one for the mode you set to keep request bodies obvious.
Example: Bearer Token Injection
curl https://api.iron.sh/v1/policies/secrets \
-H "Authorization: Bearer $IRON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "stripe-key",
"priority": 42,
"mode": "inject",
"match_tags": ["production", "payments"],
"rules": [
{ "host": "api.stripe.com", "paths": ["/v1/*"], "methods": ["POST"] }
],
"source": { "type": "env", "var": "STRIPE_API_KEY" },
"inject_config": {
"header": "Authorization",
"formatter": "Bearer {{ .Value }}"
}
}'Example: Path Token Replacement
curl https://api.iron.sh/v1/policies/secrets \
-H "Authorization: Bearer $IRON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "telegram-bot",
"priority": 50,
"mode": "replace",
"rules": [
{ "host": "api.telegram.org", "paths": ["/bot*"], "methods": [] }
],
"source": { "type": "env", "var": "TELEGRAM_BOT_TOKEN" },
"replace_config": { "proxy_value": "PROXY-BOT-TOKEN" }
}'Returns 201 Created with the new policy in data.
Retrieve a Secret Policy
GET /v1/policies/secrets/:idReturns 200 OK with the policy in data, or 404 Not Found with code secret_policy_not_found.
Update a Secret Policy
PUT /v1/policies/secrets/:idGET the policy, modify the fields you want to change, and PUT the full representation back. Send the same fields you would on create. To switch between modes, change mode and supply the matching inject_config or replace_config: the server clears the other config block automatically.
Example: Switch from Inject to Replace
curl -X PUT https://api.iron.sh/v1/policies/secrets/spol_01H... \
-H "Authorization: Bearer $IRON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "openai-key",
"priority": 0,
"active": true,
"match_tags": ["production"],
"mode": "replace",
"rules": [
{ "host": "api.openai.com", "paths": ["/v1/*"], "methods": ["POST"] }
],
"source": { "type": "env", "var": "OPENAI_API_KEY" },
"replace_config": { "proxy_value": "proxy-openai-token" }
}'Delete a Secret Policy
DELETE /v1/policies/secrets/:idReturns 204 No Content. Connected proxies stop applying the policy within seconds.