This repository is a student lab / proof-of-concept that demonstrates a secure AWS pattern for launching Claude Managed Agent work inside isolated Lambda MicroVM sessions. It is not claiming to be a fully production-ready enterprise platform.
Current verified deployment values:
| Item | Current value |
|---|---|
| AWS Region | us-east-1 |
| AWS Account | <ACCOUNT_ID> |
| Terraform backend bucket | class-7-state-files |
| Terraform backend key | lambda-labs/microvm.tfstate |
| API Gateway webhook URL | https://fkj0engflg.execute-api.us-east-1.amazonaws.com/prod/claude/webhook |
| Artifact bucket | microvm-artifacts-bucket |
| Artifact S3 URI | s3://microvm-artifacts-bucket/microvm-artifacts/app.zip |
| Claude environment key secret ARN | arn:aws:secretsmanager:us-east-1:<ACCOUNT_ID>:secret:lambda-microvm-lab-dev/claude/environment-key-HbbDkY |
| Claude webhook signing secret ARN | arn:aws:secretsmanager:us-east-1:<ACCOUNT_ID>:secret:lambda-microvm-lab-dev/claude/webhook-signing-secret-r9XywX |
| MicroVM image name | class7-microvm-image |
| MicroVM image ARN | arn:aws:lambda:us-east-1:<ACCOUNT_ID>:microvm-image:class7-microvm-image |
| MicroVM image state | CREATED |
| Latest active image version | 1.0 |
| Launcher Lambda log group | /aws/lambda/lambda-microvm-lab-dev-microvm-launcher |
| API Gateway log group | /aws/apigateway/lambda-microvm-lab-dev-claude-webhook |
| MicroVM log group | /aws/lambda/microvms/class7-microvm-image |
| CloudTrail bucket | lambda-microvm-lab-dev-cloudtrail-d06df742 |
| CloudTrail trail ARN | arn:aws:cloudtrail:us-east-1:<ACCOUNT_ID>:trail/lambda-microvm-lab-dev-microvm-trail |
Latest validation evidence:
- Terraform initialized and validated successfully.
- Terraform apply completed with
46 added, 0 changed, 0 destroyed. - Lambda MicroVM image state is
CREATED. - Latest active MicroVM image version is
1.0. - Manual unsigned webhook test returned
401 Invalid webhook signature. - Manual MicroVM runtime smoke test reached
RUNNING. - Direct MicroVM
/healthendpoint returnedHTTP/1.1 200 OK.
This project builds a Terraform-managed AWS lab environment that connects Claude Managed Agents to isolated AWS Lambda MicroVM runtime sessions.
In everyday terms, this project creates a secure βAI workroomβ in AWS. When Claude needs to run a task, a webhook request goes to API Gateway, a Python Lambda launcher verifies the request, and the workload runs inside a short-lived Lambda MicroVM instead of a shared server.
How can a company let AI agents safely perform useful technical work without giving them uncontrolled access to internal systems?
Built a Terraform-managed AWS student lab that securely connects Claude Managed Agents to isolated Lambda MicroVM runtime environments. The project uses API Gateway, Lambda, IAM, Secrets Manager, S3, CloudWatch, and CloudTrail to package, launch, monitor, and audit AI workload sessions in AWS.
A company may want an AI assistant to review support tickets, inspect logs, or troubleshoot cloud alerts. Instead of allowing the AI to run directly on a long-lived shared server, this project launches a temporary isolated MicroVM session with controlled IAM permissions, secrets access, logging, and audit trails.
Terraform apply
β Package app/Dockerfile + app/app.js
β Create app.zip
β Upload app.zip to S3
β CloudFormation creates AWS::Lambda::MicrovmImage
β Lambda MicroVM image becomes versioned and launchable
Claude Managed Agent
β Sends session.status_run_started webhook
β API Gateway REST API receives POST /claude/webhook
β Python launcher Lambda verifies webhook signature
β Launcher Lambda calls RunMicroVM
β Lambda MicroVM starts one isolated session
β MicroVM worker runs the student lab Node.js service
β Results/status flow back over HTTPS
S3 Stores the packaged MicroVM app artifact.
Secrets Manager Stores Claude environment key and webhook signing secret.
IAM Provides least-privilege roles and policies.
CloudWatch Stores logs, metrics, and alarms.
CloudTrail Audits management events and Lambda MicroVM data events.
API Gateway Exposes the Claude webhook route.
Lambda Runs the Python launcher.
Alternate infographic version:
The diagrams show the lab in three stages:
- Build Pipeline β Terraform packages the app (
app.zip) to the S3 artifact bucket, then CloudFormation (AWS::Lambda::MicrovmImage) produces the Lambda MicroVM image. - Runtime Request Flow β Claude webhook traffic enters through API Gateway to
the Python launcher Lambda, which verifies the signature and calls
RunMicroVMto start the isolated MicroVM worker on port8080(ALL_INGRESS/INTERNET_EGRESSnetwork connectors). Results return to Claude over HTTPS. - Supporting AWS Services β IAM, Secrets Manager, CloudWatch, and CloudTrail provide security, logging, and audit.
- S3 artifact bucket for the MicroVM application package.
- S3 object for
microvm-artifacts/app.zip. - Lambda MicroVM image using CloudFormation
AWS::Lambda::MicrovmImage. - Python launcher Lambda for Claude webhook events.
- API Gateway REST API endpoint at
/prod/claude/webhook. - Secrets Manager secret containers for the Claude environment key and webhook signing secret.
- Least-privilege IAM roles for MicroVM build, MicroVM runtime, launcher Lambda, and API Gateway CloudWatch logging.
- CloudWatch log groups, metric filters, and alarms.
- CloudTrail trail with management events and Lambda MicroVM data events.
- JavaScript MicroVM worker stub for student-lab validation.
| Tool | Requirement | Purpose |
|---|---|---|
| Terraform 1.14+ | Required | Deploy AWS infrastructure. |
| AWS CLI v2 | Required | Run validation, logs, MicroVM commands, and secrets updates. |
| Python 3.14 | Required for this lab | Package the launcher Lambda dependencies. |
| Git Bash | Recommended on Windows | Run the lab commands consistently. |
jq |
Recommended | Parse JSON outputs from AWS CLI. |
| Claude Console | Required for full Claude integration | Create Managed Agent, self-hosted environment, and webhook. |
| AWS Console | Optional | Capture screenshots and visually inspect resources. |
| VS Code | Required | Edit Terraform, Python, JavaScript, and Markdown files. |
| .venv-lambda-build | Recommended | Python virtual environment for packaging the launcher Lambda. |
microvm/
βββ app/
β βββ app.js
β βββ Dockerfile
βββ deliverables/
β βββ microvm-run.json
β βββ microvm-token.json
βββ docs/
β βββ architecture/
β β βββ lambda_microvm_architecture_infographic.png
β β βββ microvm-lab-flowchart.svg
β βββ runbooks/
β βββ CLI_COMMANDS.md
βββ images/
β βββ aws-verifications.jpg
β βββ base-image-versions.jpg
β βββ claude-console-agent-environment.jpg
β βββ claude-console-environment.jpg
β βββ claude-console-webhook-subscribe.jpg
β βββ claude-console-webhook.jpg
β βββ claude-secrets-describe-pt1.jpg
β βββ claude-secrets-describe-pt2.jpg
β βββ claude-secrets.jpg
β βββ cloudtrail-selectors.jpg
β βββ cloudwatch-alarms-pt1.jpg
β βββ cloudwatch-alarms-pt2.jpg
β βββ launcher-lambda-logs.jpg
β βββ manual-microvm-health.jpg
β βββ manual-microvm-id.jpg
β βββ manual-microvm-launch.jpg
β βββ manual-microvm-outputs.jpg
β βββ manual-microvm-running.jpg
β βββ s3-bucket-verification.jpg
β βββ terraform-apply.jpg
β βββ terraform-destroy.jpg
β βββ terraform-init-fmt-validate.jpg
β βββ terraform-outputs.jpg
β βββ terraform-plan.jpg
β βββ webhook-smoke-test.jpg
βββ launcher/
β βββ lambda_function.py
β βββ requirements.txt
βββ scripts/
β βββ build_launcher_package.py
β βββ prepare_build_dirs.py
βββ terraform/
β βββ 1-authentication.tf
β βββ 2-provider.tf
β βββ 3-variables.tf
β βββ 4-locals.tf
β βββ 5-random.tf
β βββ 6-s3.tf
β βββ 7-cloudwatch.tf
β βββ 8-iam.tf
β βββ 9-microvm-image.tf
β βββ 10-secrets.tf
β βββ 11-api-gateway.tf
β βββ 12-lambda.tf
β βββ 13-cloudtrail.tf
β βββ 14-outputs.tf
β βββ terraform.tfvars
β βββ terraform.tfvars.example
βββ .gitignore
βββ README.md
βββ RUNBOOK.md
Do not commit generated or local-only files:
build/
terraform/.terraform/
*.tfstate
*.tfstate.*
*.tfplan
terraform.tfvars
lambda-response.json
microvm-run.json
microvm-token.json
*.zip
Commit terraform/terraform.tfvars.example, but do not commit real Claude secrets.
For more detailed instructions, see RUNBOOK.
export AWS_REGION="us-east-1"
export AWS_PROFILE="default"aws sts get-caller-identity --region "$AWS_REGION"aws s3api head-bucket \
--bucket class-7-state-files \
--region "$AWS_REGION"aws lambda-microvms list-managed-microvm-image-versions \
--image-identifier arn:aws:lambda:us-east-1:aws:microvm-image:al2023-1 \
--region "$AWS_REGION" \
--output tableThis lab currently uses:
microvm_base_image_version = "1"cd terraform
terraform init -upgrade
terraform fmt -recursive
terraform validate
terraform plan
terraform applyExpected latest successful result:
Apply complete! Resources: 46 added, 0 changed, 0 destroyed.
Do not place real Claude secret values directly inside terraform.tfvars.
Current secret containers:
Claude environment key secret:
arn:aws:secretsmanager:us-east-1:<ACCOUNT_ID>:secret:lambda-microvm-lab-dev/claude/environment-key-HbbDkY
Claude webhook signing secret:
arn:aws:secretsmanager:us-east-1:<ACCOUNT_ID>:secret:lambda-microvm-lab-dev/claude/webhook-signing-secret-r9XywX
Store the Claude environment key:
aws secretsmanager put-secret-value \
--secret-id "$CLAUDE_ENVIRONMENT_SECRET_ARN" \
--secret-string "REPLACE_WITH_CLAUDE_ENVIRONMENT_KEY" \
--region "$AWS_REGION"Store the Claude webhook signing secret:
aws secretsmanager put-secret-value \
--secret-id "$CLAUDE_WEBHOOK_SIGNING_SECRET_ARN" \
--secret-string "REPLACE_WITH_CLAUDE_WEBHOOK_SIGNING_SECRET" \
--region "$AWS_REGION"-
Open Claude Console.
-
Open the Claude Managed Agent.
-
Open or create the self-hosted environment.
-
Copy the environment ID and set
anthropic_environment_idinterraform.tfvars. -
Register the current Terraform output webhook URL:
https://fkj0engflg.execute-api.us-east-1.amazonaws.com/prod/claude/webhook -
Subscribe the webhook to:
session.status_run_started -
Copy the webhook signing secret from Claude Console and store it in AWS Secrets Manager.
WEBHOOK_URL="$(terraform output -raw claude_webhook_url | tr -d '\r')"
curl --ssl-no-revoke -i -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
--data-raw '{"type":"session.status_run_started","session_id":"manual-test"}'Expected result:
HTTP/1.1 401 UnauthorizedExpected body:
{"error": "Invalid webhook signature"}This is a passing result because manual curl requests are not signed by Claude.
MICROVM_IMAGE_ARN="$(terraform output -raw microvm_image_arn | tr -d '\r')"
MICROVM_RUNTIME_ROLE_ARN="$(terraform output -raw microvm_runtime_role_arn | tr -d '\r')"
aws lambda-microvms run-microvm \
--image-identifier "$MICROVM_IMAGE_ARN" \
--image-version "1.0" \
--execution-role-arn "$MICROVM_RUNTIME_ROLE_ARN" \
--ingress-network-connectors "arn:aws:lambda:${AWS_REGION}:aws:network-connector:aws-network-connector:ALL_INGRESS" \
--egress-network-connectors "arn:aws:lambda:${AWS_REGION}:aws:network-connector:aws-network-connector:INTERNET_EGRESS" \
--idle-policy '{"maxIdleDurationSeconds":900,"suspendedDurationSeconds":0,"autoResumeEnabled":false}' \
--maximum-duration-in-seconds 28800 \
--run-hook-payload '{"source":"manual-lab-test","session_id":"manual-test"}' \
--region "$AWS_REGION" \
> microvm-run.json
MICROVM_ID="$(cat microvm-run.json | jq -r '.microvmId')"
MICROVM_ENDPOINT="$(cat microvm-run.json | jq -r '.endpoint')"Wait for RUNNING:
while true; do
STATE="$(aws lambda-microvms get-microvm \
--microvm-identifier "$MICROVM_ID" \
--region "$AWS_REGION" \
--query 'state' \
--output text)"
echo "MicroVM state: $STATE"
if [ "$STATE" = "RUNNING" ]; then
break
fi
if [ "$STATE" = "TERMINATED" ]; then
echo "MicroVM terminated before becoming reachable. Check MicroVM logs."
break
fi
sleep 5
doneCreate a token and test /health:
aws lambda-microvms create-microvm-auth-token \
--microvm-identifier "$MICROVM_ID" \
--expiration-in-minutes 30 \
--allowed-ports '[{"port":8080}]' \
--region "$AWS_REGION" \
> microvm-token.json
$ TOKEN="$(cat microvm-token.json | jq -r '.authToken."X-aws-proxy-auth"')"
curl -i --ssl-no-revoke "https://${MICROVM_ENDPOINT}/health" \
-H "X-aws-proxy-auth: $TOKEN" \
-H "X-aws-proxy-port: 8080"Expected response:
HTTP/1.1 200 OK
Content-Type: application/json{"ok":true,"service":"lambda-microvm-claude-agent-lab","lab_mode":true,"message":"Student lab MicroVM worker is running."}Launcher logs:
LAUNCHER_LOG_GROUP="$(terraform output -raw launcher_lambda_log_group_name | tr -d '\r')"
MSYS_NO_PATHCONV=1 aws logs tail "$LAUNCHER_LOG_GROUP" \
--follow \
--region "$AWS_REGION" \
--format shortCloudTrail selectors:
aws cloudtrail get-event-selectors \
--trail-name "lambda-microvm-lab-dev-microvm-trail" \
--region "$AWS_REGION" \
--output jsonExpected selectors:
Log management events
Log Lambda MicroVM data events
AWS::Lambda::MicrovmImage
| Screenshot | What it proves | Links for Screenshots |
|---|---|---|
aws sts get-caller-identity |
Correct AWS account is active. | AWS Verifications |
aws s3api head-bucket |
Terraform backend bucket exists. | S3 Bucket Verification |
terraform init -upgrade |
Backend and providers initialized. | Terraform Init |
terraform plan |
Terraform syntax is valid. | Terraform Plan |
terraform apply complete |
Infrastructure was deployed. | Terraform Apply |
terraform output |
Current ARNs, URLs, and log groups. | Terraform Outputs |
API Gateway 401 curl |
Webhook security check works. | Webhook Smoke Test |
| Manual MicroVM launch | Runtime and handler are correct. | Manual MicroVM Launch |
MicroVM state RUNNING |
Runtime launch succeeded. | MicroVM State Running |
MicroVM /health 200 |
Worker is reachable. | MicroVM Health |
| Launcher Lambda logs | Observability is working. | Launcher Lambda Logs |
| CloudWatch Alarms (Part I) | Monitoring exists. | CloudWatch Alarms (Part I) |
| CloudWatch Alarms (Part II) | Monitoring exists. | CloudWatch Alarms (Part II) |
| CloudTrail selectors | Audit logging is configured. | CloudTrail Selectors |
Terminate active MicroVMs:
aws lambda-microvms list-microvms \
--image-identifier "$MICROVM_IMAGE_ARN" \
--region "$AWS_REGION" \
--output tableaws lambda-microvms terminate-microvm \
--microvm-identifier REPLACE_WITH_MICROVM_ID \
--region "$AWS_REGION"Destroy Terraform resources:
terraform destroyCause: AWS_REGION is empty.
Fix:
export AWS_REGION="us-east-1"Use:
MSYS_NO_PATHCONV=1 aws logs tail "/aws/lambda/lambda-microvm-lab-dev-microvm-launcher" \
--since 30m \
--region "$AWS_REGION" \
--format shortCause: Python dependencies were built for Windows instead of Lambda Linux.
Fix:
rm -rf ../build
terraform apply \
-replace=terraform_data.launcher_packageThis is expected for unsigned curl tests and means the route is secure.
Fix:
cat microvm-run.json
MICROVM_ID="$(cat microvm-run.json | jq -r '.microvmId')"
MICROVM_ENDPOINT="$(cat microvm-run.json | jq -r '.endpoint')"Check state:
aws lambda-microvms get-microvm \
--microvm-identifier "$MICROVM_ID" \
--region "$AWS_REGION" \
--output tableIf state is TERMINATED, launch a fresh MicroVM and generate a fresh token. If state is RUNNING, check the MicroVM logs.
Fix:
curl --ssl-no-revoke ...- AWS Lambda MicroVMs
- Launching Lambda MicroVMs
- Monitoring Lambda MicroVMs
- CloudFormation
AWS::Lambda::MicrovmImage - Terraform S3 backend
- Terraform AWS provider
- Claude Self-Hosted Sandboxes on AWS Lambda MicroVMs (GitHub)
| Role | Name / Group |
|---|---|
| Project Author | T.I.Q.S. |
| Project Team | The Brotherhood of jerMutants β Wolfpack |
| Team Lead | John Sweeney |
| Course Instructor | Theo WAF |
| Project Version | v2.1 |
| Completion Date | July 2026 |
| Project Type | Student lab / proof-of-concept |
