Overview
This example creates an E2B sandbox with Claude Code, using Oshu Vault to securely inject your Anthropic API key. The sandbox only sees a sealed token — the real key never leaves the proxy.
Prerequisites
- E2B account and
E2B_API_KEY set
- Oshu Vault instance running
SECRETS_PROXY_API_KEY — your proxy management API key
ANTHROPIC_API_KEY — your real Anthropic key
Install Dependencies
npm install @e2b/code-interpreter @oshu/vault-sdk
Build the Template
E2B uses custom sandbox templates defined programmatically. Create a template definition:
// e2b-template.ts
import { Template } from "e2b";
const PROXY_BASE_URL = process.env.PROXY_BASE_URL ?? "https://pv.oshu.dev";
export const template = Template()
.fromDockerfile(
`FROM node:22-slim
RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL ${PROXY_BASE_URL}/v1/ca.pem \\
-o /usr/local/share/ca-certificates/proxy-ca.crt \\
&& update-ca-certificates
# Wrap the node binary so it trusts the system CA store
RUN mv /usr/local/bin/node /usr/local/bin/node.real \\
&& echo '#!/bin/sh' > /usr/local/bin/node \\
&& echo 'exec /usr/local/bin/node.real --use-openssl-ca "$@"' >> /usr/local/bin/node \\
&& chmod +x /usr/local/bin/node
RUN npm install -g @anthropic-ai/claude-code`,
);
Then build and push:
// build-e2b-template.ts
import { Template, defaultBuildLogger } from "e2b";
import { template } from "./e2b-template.js";
const buildInfo = await Template.build(template, {
alias: "oshu-vault-claude",
cpuCount: 2,
memoryMB: 2048,
onBuildLogs: defaultBuildLogger(),
});
console.log(`Template ready: ${buildInfo.alias}`);
npx tsx build-e2b-template.ts
Full Example
import { Sandbox } from "@e2b/code-interpreter";
import { SecretsProxyClient } from "@oshu/vault-sdk";
// --- Config ---
const PROXY_BASE_URL = "https://pv.oshu.dev";
const PROXY_HOST = "pv.oshu.dev";
const API_KEY = process.env.SECRETS_PROXY_API_KEY!;
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY!;
// 1. Create an Oshu Vault session
const client = new SecretsProxyClient({
baseUrl: PROXY_BASE_URL,
apiKey: API_KEY,
});
const session = await client.createSession({
secrets: { ANTHROPIC_API_KEY },
});
const proxyUrl = `https://${session.session_id}:${session.token}@${PROXY_HOST}`;
// 2. Create sandbox from template — CA cert + Claude Code already baked in
const sandbox = await Sandbox.create("oshu-vault-claude", {
envs: {
ANTHROPIC_API_KEY: session.sealed_secrets["ANTHROPIC_API_KEY"],
HTTP_PROXY: proxyUrl,
HTTPS_PROXY: proxyUrl,
},
});
try {
// 3. Run claude -p — no special flags, just works
const result = await sandbox.commands.run(
`claude -p "Write a hello world program in Python"`,
{ timeoutMs: 120_000 },
);
console.log(result.stdout);
} finally {
await client.deleteSession(session.session_id);
await sandbox.kill();
}
Custom Proxy URL
If your Oshu Vault instance is at a different URL, pass it as a build arg:
e2b template build -n oshu-vault-claude --build-arg PROXY_BASE_URL=https://your-proxy.example.com
What’s Happening
Template built with Claude Code + trusted CA
The template installs the proxy CA certificate into the system trust store and wraps the node binary with --use-openssl-ca so Node.js trusts it too. Claude Code is pre-installed. E2B caches this template.
Session created
The SDK sends your real ANTHROPIC_API_KEY to the proxy and gets back a sealed token like SEALED_7f3a9b2c....
Sandbox configured
The sandbox receives ANTHROPIC_API_KEY=SEALED_7f3a9b2c... and proxy env vars. No certificate setup needed at runtime.
Secret injected on-the-fly
When Claude Code calls the Anthropic API with x-api-key: SEALED_7f3a9b2c..., the proxy intercepts the request and replaces the sealed token with your real API key before forwarding.
The sandbox never sees your real API key. Even if the AI-generated code tries to log or exfiltrate ANTHROPIC_API_KEY, it only gets the useless sealed token.