A reference solution that runs Anthropic Claude self-hosted sandbox tool execution inside AWS Lambda MicroVMs. It implements the orchestrator + ephemeral MicroVM per session pattern: an event-driven control plane in your AWS account launches a fresh, isolated MicroVM for each Claude session, while orchestration stays on Anthropic's control plane.
This allows your agents to access resources through your AWS environment without exposing connectivity, while you retain full monitoring and governance over those resources.
This is a working reference intended for learning and adaptation.
AWS Lambda MicroVMs is a compute service that provides serverless, ephemeral execution environments with strong VM-level isolation. Each MicroVM runs Amazon Linux 2023 with full OS access for up to 8 hours and can be launched, suspended, resumed, and terminated programmatically. It is purpose-built for running user-supplied or AI-generated code in isolated sandboxes — this solution uses one MicroVM per Claude session so sessions never share state.
Key differentiators:
- Launch from snapshot — MicroVMs boot from a pre-captured memory and disk snapshot, enabling rapid start times by skipping application initialization entirely.
- 4× vertical scaling without re-provisioning — scale a running MicroVM's CPU and memory up to 4× its initial allocation without terminating or re-creating the compute environment.
The control plane is event-driven — there is no poller. The only inbound traffic is the webhook call; the rest of the workflow is pull-based. The flow:
- A Claude session reaches the running state and Anthropic sends a
session.status_run_startedwebhook to an Amazon API Gateway endpoint. - API Gateway invokes the launcher Lambda. The launcher verifies the webhook signature in-process using the signing secret from SSM Parameter Store, denying invalid or stale deliveries.
- The launcher calls
RunMicrovmto launch one MicroVM for that session, passing the session dispatch viarunHookPayload. It dedupes on the webhook event id (DynamoDB-backed) and stays within the RunMicrovm rate limit. - The MicroVM receives the dispatch on its
/runhook: it fetches the environment key from SSM Parameter Store using its own execution role, claims the matching session from the Anthropic work queue, executes the agent's tool calls in/workspace, posts results back to Anthropic, and then callsTerminateMicrovmon itself to release compute immediately. The idle policy is only the fallback if that call can't be made.
Credential boundaries. The organization-scoped API key is used only by the operator (registering the webhook, creating sessions) and never reaches AWS compute. The environment key and the webhook signing secret live in AWS Systems Manager Parameter Store as SecureString parameters. The launcher reads only the signing secret (to verify the inbound webhook) and never handles the environment key — it passes only a reference (the parameter name) to the environment-key parameter into the MicroVM. The MicroVM's execution role reads only the environment key. The organization API key is never placed on any AWS compute.
- An AWS account with permissions for S3, IAM, SSM Parameter Store, API Gateway, Lambda, WAF, CloudWatch Logs, and AWS Lambda MicroVM.
- AWS CLI v2+ configured with the Lambda MicroVMs service model installed
(
aws configure add-model). - The AWS SAM CLI.
- An existing Claude Managed Agents agent
(note its agent ID) and a
self_hostedenvironment (note itsenv_...id). - A webhook signing secret and an environment key, both generated in the Claude Console.
zipavailable locally (used to package the MicroVM image source).
.
├── template.yaml # SAM template: launcher + REST API, WAF,
│ # MicroVM execution role, image
│ # build role + artifact bucket
├── src/
│ ├── microvm-image/ # Contents zipped into the MicroVM image
│ │ ├── Dockerfile # AL2023 + Node worker, /workspace, /mnt/session/outputs
│ │ └── worker/worker.mjs # HTTP lifecycle-hook server (EnvironmentWorker)
│ ├── functions/ # Launcher Lambda (sam build packages this)
│ │ ├── launcher.py # Verifies webhook signature; RunMicrovm per session
│ │ ├── requirements.txt # Launcher deps (anthropic[webhooks], powertools, bundled boto3/botocore)
│ │ ├── shared/ # Payload, rate limiter, MicroVM client, types
│ │ └── wheels/ # Vendored boto3/botocore wheels (lambda-microvms client)
│ ├── scripts/
│ │ ├── build-image.sh # Zip + upload + create-microvm-image
│ │ └── verify.py # Operator-side: create a session to exercise the flow
├── docs/ # Architecture diagram + notes
├── README.md LICENSE CONTRIBUTING.md CODE_OF_CONDUCT.md
└── pyproject.toml requirements.txt
samconfig.toml and .aws-sam/ are generated locally by SAM and are git-ignored.
The deploy is one IaC step plus three out-of-band steps:
- Deploy the control plane (SAM)
- Register the webhook and create the SecureString parameters (Console + CLI)
- Build the MicroVM image (CLI)
- Verify end-to-end
sam build
sam deploy --guided --capabilities CAPABILITY_NAMED_IAM --parameter-overrides "AnthropicEnvironmentId=env_..."--guided prompts for the stack name and region and writes your answers to
samconfig.toml (git-ignored), so subsequent deploys are just sam build && sam deploy. The stack outputs include WebhookUrl, ArtifactBucketName,
BuildRoleArn, EnvironmentKeyParamName, and SigningParamName.
- In the Claude Console,
generate the environment key for your
self_hostedenvironment. - Register the stack's
WebhookUrl(from the deploy outputs) as a webhook endpoint subscribed tosession.status_run_started. The Console will provide a webhook signing secret (whsec_...). - Create both SSM SecureString parameters using the names from the deploy
outputs. CloudFormation cannot create
SecureStringparameters, so this is a post-deploy step; the stack's IAM roles are already scoped to these names.
aws ssm put-parameter --type SecureString --name "<EnvironmentKeyParamName>" --value "<environment-key>"
aws ssm put-parameter --type SecureString --name "<SigningParamName>" --value "<webhook-signing-secret>"To rotate a value later, re-run with --overwrite. Both parameters use the
default alias/aws/ssm KMS key; pass --key-id <cmk> to use a customer-managed
key instead.
./src/scripts/build-image.shThe script zips src/microvm-image/, uploads to S3, and creates the image with
lifecycle hooks enabled. Monitor the build in CloudWatch under
/aws/lambda/microvms/<image-name>; the image transitions
IN_PROGRESS → SUCCESSFUL.
export ANTHROPIC_API_KEY="sk-ant-..." # organization-scoped, operator only
export ANTHROPIC_ENVIRONMENT_ID="env_..."
export AGENT_ID="agent_..."
python src/scripts/verify.py --createThis creates a session, triggers the webhook, launches a MicroVM, and runs the
agent end-to-end. Confirm with aws lambda-microvms list-microvms /
get-microvm.
Launcher Lambda environment (set by the SAM template):
| Variable | Description |
|---|---|
ANTHROPIC_ENVIRONMENT_ID |
The self-hosted environment id. |
MICROVM_IMAGE_IDENTIFIER |
Name, ID, or ARN of the built MicroVM image. |
SIGNING_PARAM_NAME |
SSM SecureString parameter name of the webhook signing secret (used to verify inbound webhooks). |
ENVIRONMENT_KEY_PARAM_NAME |
SSM SecureString parameter name of the environment key. Passed by reference into the MicroVM; the launcher does not read its value. |
MICROVM_EXECUTION_ROLE_ARN |
Execution role assigned to each MicroVM (used in-VM to read the environment key). |
ANTHROPIC_BASE_URL (optional) |
Override the default Claude API endpoint. |
The organization API key is operator-only and is never placed on any AWS compute.
| Symptom | Likely cause / fix |
|---|---|
| Webhook returns 401 | Signature verification failed in the launcher. Confirm the signing secret in SSM Parameter Store matches the Console, and that the delivery is fresh. |
| No MicroVM launches | Check the launcher logs; confirm the webhook is registered for session.status_run_started and the image identifier is correct. |
| Duplicate launches | Shouldn't occur — the launcher dedupes on webhook event id; retries reuse the id. |
Image build fails S3_* |
Build role/bucket issue. Confirm the artifact is in the same region, not in Glacier, and the Build role grants s3:GetObject. |
Image build fails ARCHIVE_DOCKERFILE_NOT_FOUND |
Dockerfile must be at the root of app.zip; build-image.sh zips from inside microvm-image/. |
Costs are driven primarily by MicroVM run time (per AWS Lambda MicroVMs pricing), plus standard API Gateway, Lambda, SSM Parameter Store, and S3 usage. Because each session runs in its own MicroVM that is suspended/terminated at session end, cost scales with concurrent sessions and their duration. Monitor with AWS Cost Explorer.
- The organization API key never reaches AWS compute or a MicroVM; only the per-session id and a reference to the environment-key parameter are forwarded.
- The webhook is authenticated by signature verification in the launcher Lambda; invalid or stale deliveries are denied (401) before any MicroVM is launched.
- Secrets live in AWS Systems Manager Parameter Store as SecureString parameters
with least-privilege access (launcher → signing secret only; MicroVM execution
role → environment key only). Each role's
kms:Decryptis bounded to its own parameter via thePARAMETER_ARNencryption context. - Each session runs in its own isolated MicroVM. The worker self-terminates
(
lambda:TerminateMicrovm, granted on the execution role) when the session ends; the idle policy is the fallback and the 8-hour maximum duration bounds any VM. - The S3 artifact bucket blocks public access and enables versioning and server-side encryption.
- The public webhook endpoint sits behind an AWS WAF WebACL (AWS managed rule sets plus a per-IP rate limit) and API Gateway request validation, which reject malformed and abusive traffic before it reaches the launcher. These are defense-in-depth: the webhook signature check remains the authentication.
This library is licensed under the MIT-0 License. See the LICENSE file.
