This document describes the design and operation of Code Runner, a minimal, on-demand code execution sandbox built on Amazon Web Services (AWS). The system accepts arbitrary Python programs submitted as compressed archives, executes them within resource-constrained, network-isolated virtual machines, and returns captured output to the caller via a REST API. Critically, compute instances are provisioned at the moment of execution and autonomously terminated upon completion, eliminating idle resource consumption entirely. Infrastructure is expressed as code using Terraform, and all sandbox constraints — including CPU, memory, process count, execution time, and network egress — are governed by a single declarative configuration file.
Remote code execution services typically fall into one of two categories: always-on runtimes that maintain warm instances to reduce latency (e.g., AWS Lambda, containerised runners), or batch-oriented pipelines that schedule work against a pre-existing fleet. Both models incur costs during periods of inactivity and introduce non-trivial operational surface area.
For workloads where execution frequency is low and unpredictable, neither approach is economical. Moreover, executing untrusted third-party code carries inherent security risks: without strong isolation boundaries, a malicious or poorly-written program may exhaust host resources, exfiltrate data, or interfere with co-located workloads.
Code Runner addresses these concerns through three design principles:
- Ephemeral compute. Each execution is assigned a dedicated EC2 instance that is launched on demand and terminates itself upon completion. No instance persists between runs.
- Defense in depth. Resource limits are enforced at the operating-system level via
systemdcgroup controls (CPU quota, memory ceiling, process cap), supplemented by a hard execution timeout and a watchdog timer that destroys the instance unconditionally after a configurable lifetime. - Minimal attack surface. Instances operate with no inbound network access. Outbound egress is restricted by default to HTTPS (required for S3 communication), with all traffic to AWS services routed through a VPC Gateway Endpoint that never traverses the public internet.
┌──────────┐ POST /run (zip) ┌─────────────┐ launch ┌──────────────┐
│ │ ───────────────────▶ │ API Server │ ─────────▶ │ EC2 Runner │
│ Client │ │ (FastAPI) │ │ (ephemeral) │
│ │ GET /run/{id} └─────────────┘ └──────┬───────┘
│ │ ◀──────────────────────────────────────────────── S3 ◀──┘
└──────────┘ output.txt + status.json
The API server is the sole persistent component. Execution state is mediated entirely through S3: the server writes the user's code archive and an initial status document to S3 before launching the instance, and the instance writes its output and final status to S3 before terminating. The client polls the API, which proxies S3 reads, until a terminal status is observed.
| Requirement | Version |
|---|---|
| AWS CLI, configured with appropriate IAM credentials | ≥ 2.x |
| Terraform | ≥ 1.6 |
| Python (API server) | ≥ 3.10 |
Install via pip install -r api/requirements.txt:
| Package | Purpose |
|---|---|
fastapi |
HTTP API framework |
uvicorn[standard] |
ASGI server |
boto3 |
AWS SDK (S3 reads/writes, EC2 launch) |
pyyaml |
Parses sandbox.yaml configuration |
python-multipart |
Enables multipart file upload in FastAPI |
- The submission must be a valid
.ziparchive. main.pymust be present at the archive root and serves as the sole entry point.- An optional
requirements.txtat the archive root will be passed topip installbefore execution. - The total archive size must not exceed the configured
storage.max_upload_mblimit (default: 50 MB).
All sandbox parameters are centralised in sandbox.yaml at the repository root. Changes to EC2 or network settings require re-running ./scripts/deploy.sh; changes to execution limits take effect on the next API server restart.
| Key | Default | Description |
|---|---|---|
ec2.instance_type |
t3.micro |
AWS EC2 instance size |
ec2.region |
us-east-1 |
Deployment region |
execution.timeout_seconds |
60 |
Hard process kill timeout |
execution.python_version |
3.11 |
Python interpreter version |
resources.max_memory_mb |
256 |
Memory ceiling (systemd MemoryMax) |
resources.max_cpu_percent |
80 |
CPU quota (systemd CPUQuota) |
resources.max_processes |
64 |
Process cap (systemd TasksMax) |
storage.max_upload_mb |
50 |
Maximum accepted archive size |
network.allow_outbound_internet |
false |
Permit unrestricted egress |
shutdown.shutdown_after_run |
true |
Auto-terminate instance after run |
shutdown.max_lifetime_minutes |
10 |
Watchdog lifetime ceiling |
chmod +x scripts/deploy.sh
./scripts/deploy.shcd api
pip install -r requirements.txt
uvicorn main:app --port 8000zip code.zip main.py
curl -X POST http://localhost:8000/run \
-F "file=@code.zip"EC2 instance boot and code installation typically takes 30–90 seconds.
curl http://localhost:8000/run/abc-123Possible terminal status values: success, error, timeout.
cd terraform && terraform destroy