Skip to main content

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

1

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.
2

Session created

The SDK sends your real ANTHROPIC_API_KEY to the proxy and gets back a sealed token like SEALED_7f3a9b2c....
3

Sandbox configured

The sandbox receives ANTHROPIC_API_KEY=SEALED_7f3a9b2c... and proxy env vars. No certificate setup needed at runtime.
4

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.