Secret Proxying
Iron.sh lets you store credentials and have the egress proxy inject them into outbound requests on behalf of your workloads. The workload never sees the real secret. It only sees a placeholder value that is meaningless outside the proxy.
How It Works
When you create a secret, Iron.sh returns a proxy_value, an opaque placeholder string. At sandbox creation time, the platform sets the environment variable you specified (e.g. GITHUB_TOKEN) to this placeholder value inside the VM:
GITHUB_TOKEN=IRONSH_PROXY_github-mainWhen the workload makes an outbound HTTP request, the egress proxy scans all HTTP headers for known proxy values and replaces them with the real secret before forwarding upstream. There is no per-provider logic — the proxy is generic. The response travels back through the proxy unmodified.
┌──────────┐ ┌────────────┐ ┌──────────────┐
│ Sandbox │──req──▶ │ Egress │──req──▶ │ Provider │
│ │ │ Proxy │ │ (upstream) │
│ uses │ │ │ │ │
│ placeholder │ swaps in │ │ sees real │
│ value │◀──res── │ real secret│◀──res── │ credential │
└──────────┘ └────────────┘ └──────────────┘This means:
- The workload code and process environment never contain the actual credential.
- Even if the sandbox is compromised, the attacker only obtains the placeholder, which cannot be used outside the Iron.sh proxy.
- The real secret is only held by the proxy and is never written to disk inside the VM.
- Every secret replacement is recorded in the egress audit log, so you have a full trail of when and where credentials were injected.
Host Scoping
By default, secrets are injected on requests to any host allowed by your egress policy (hosts: ["*"]). To restrict a secret to specific destinations, provide a hosts array when creating the secret. Supported formats:
| Pattern | Example | Matches |
|---|---|---|
| Exact hostname | api.github.com | Only api.github.com |
| Wildcard (one level) | *.github.com | api.github.com, raw.github.com |
| Any host | * | All hosts allowed by egress policy |
If a request goes to a host not in the secret’s hosts list, the proxy value is left as-is and the upstream receives a meaningless placeholder.
Proxy Value Format
The proxy_value returned when you create a secret follows the pattern:
IRONSH_PROXY_<name>For example, a secret named github-main produces:
IRONSH_PROXY_github-mainThis value is safe to log, commit, or expose in CI output. It is inert outside the Iron.sh egress proxy.
Environment Variable Injection
When a sandbox starts, Iron.sh sets one environment variable per secret. The variable name is the env_var you specified when creating the secret, and its value is the proxy_value:
# Inside the sandbox
echo $GITHUB_TOKEN
# IRONSH_PROXY_github-mainYour workload uses the environment variable normally. Standard tools and libraries (e.g. git, npm, curl) read the token from the environment and include it in outbound requests. The proxy handles the rest.
If you update or add secrets while a sandbox is already running, existing shell sessions will not pick up the changes automatically. To reload secrets in an active shell, source the secrets profile:
source /etc/profile.d/irons-secrets.shAlternatively, start a new login shell. New SSH sessions will load the updated secrets automatically.
Example: GitHub Token
- Create a secret via the API or CLI:
curl -X POST https://api.iron.sh/v1/secrets \
-H "Authorization: Bearer $IRONS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "github-main",
"secret": "ghp_abc123def456...",
"env_var": "GITHUB_TOKEN",
"hosts": ["api.github.com", "github.com", "*.githubusercontent.com"]
}'-
Create a sandbox. The VM starts with
GITHUB_TOKEN=IRONSH_PROXY_github-mainin its environment. -
Inside the sandbox, clone a private repo:
git clone https://github.com/my-org/private-repo.gitGit reads GITHUB_TOKEN from the environment and sends it in the Authorization header. The egress proxy intercepts the request to github.com, replaces the placeholder with ghp_abc123def456..., and forwards it upstream. GitHub authenticates the request normally.
Secret Lifecycle
- Write-only. The real secret value is never returned by any API endpoint. Once stored, it can only be replaced or deleted.
- Update. Use
PATCH /v1/secrets/{secret_id}to rotate a secret. Theproxy_valuedoes not change, so running sandboxes continue to work without reconfiguration. - Delete. Use
DELETE /v1/secrets/{secret_id}to remove a secret. Sandboxes created after deletion will no longer have the environment variable set.
Interaction with Egress Rules
Secret proxying works alongside egress rules. For the proxy to intercept and inject a secret, the destination host must be allowed by your egress policy. If a request to a host is blocked by an egress rule, the proxy never sees it, and injection does not occur.
Make sure the hosts your secrets target are included in your egress allowlist.
Security Model
| Property | Guarantee |
|---|---|
| Secret at rest | Encrypted. Never stored on the VM’s file system. |
| Secret in transit | Injected over TLS between the proxy and the provider. Never sent in plaintext. |
| Sandbox exposure | Only the placeholder is visible inside the VM. |
| Placeholder outside proxy | Inert. Cannot be exchanged for the real secret without the proxy. |
| Audit trail | Every secret replacement is recorded in the egress audit log, including the target host, protocol, and timestamp. |