Images and IAM¶
Every sandbox starts from a Lambda MicroVMs image published in your
account from image/Dockerfile. The SDK needs an image with a rayd of
its same series (MAJOR.MINOR, see
Compatibility) and, for two
families of features, a specific variant. rayito doctor checks the version
of the image's agent (CLI).
Which image each feature needs¶
The three variants come from the same Dockerfile: rayito-base-caps is the
same zip as rayito-base published with additionalOsCapabilities ALL, and
rayito-base-poly adds a layer with bash_kernel and Deno 2.9.7. There are
also two optional images that you only publish if you use their feature:
rayito-base-caps-efs (rayito-base-caps plus amazon-efs-utils, for
volumes=) and the agent image built by AgentTemplate (rayito-agent, on
top of rayito-base-caps).
| Feature | rayito-base |
rayito-base-caps |
rayito-base-poly |
|---|---|---|---|
commands, files, pty, run_code in Python, metadata, pool, persist= |
yes | yes | yes |
Server-side deadline: max_lifetime, on_timeout, set_timeout, connect(timeout=) (Deadline) |
yes (0.3.0) | yes (0.3.0) | yes (0.3.0) |
upload_url/download_url, large files over S3, gzip, metadata (Files) |
yes (0.3.0) | yes (0.3.0) | yes (0.3.0) |
get_metrics_history(), guest facts (Observability) |
yes (0.3.0) | yes (0.3.0) | yes (0.3.0) |
sbx.git (git-core in the image, Git) |
yes (0.3.0) | yes (0.3.0) | yes (0.3.0) |
rayito.e2b / rayito/e2b shim (Compatibility) |
yes (0.3.0) | yes (0.3.0) | yes (0.3.0) |
run_code(language="bash") |
no: UNIMPLEMENTED |
no | yes |
run_code(language="javascript") or "typescript" (Kernels) |
no: UNIMPLEMENTED |
no | yes (0.3.0) |
Egress policy: network=, allow_internet_access=False, update_network() (Outbound network) |
no: the SDK terminates the VM and raises UnimplementedError |
yes (0.3.0) | no: same as rayito-base |
IMDS blocked for uid 1000–65535 (get_health().imds_blocked) |
no | yes | no |
mounts= (S3 mounts) |
no: UnimplementedError |
yes (0.6.0), with the bucket in RAYITO_ALLOWED_MOUNT_BUCKETS |
no: same as rayito-base |
events= (Events and webhooks), gateways= (Secret gateway) |
yes (0.6.0) | yes (0.6.0) | yes (0.6.0) |
telemetry= (OTLP export) |
yes (0.6.0) with OtlpAuth.bearer(...) |
yes (0.6.0), also with OtlpAuth.execution_role() |
yes (0.6.0) with OtlpAuth.bearer(...) |
Template.set_start_cmd() (Templates) as a base image |
yes (0.6.0) | yes (0.6.0) | yes (0.6.0) |
| Reaping orphan zombies (What's new in 0.6.1) | yes (0.6.1) | yes (0.6.1) | yes (0.6.1) |
volumes= (EFS volumes, experimental) |
no: UnimplementedError |
no: only the optional rayito-base-caps-efs variant (0.7.0, rayito image publish --with-efs) |
no: UnimplementedError |
Agent hardening: isolated hooks, persistence bound to /run (What's new in 0.7.0) |
yes (0.7.0) | yes (0.7.0) | yes (0.7.0) |
sbx.agent (Agent in the sandbox) |
no: fails with reason="runtime_missing" |
no: same, unless you install the runtime yourself | no: same |
size= (Sizes) is not an image feature
but one more image per size: rayito image publish --sizes publishes
rayito-base-4gb (or rayito-base-caps-4gb) from the same artifact as the
variant.
"yes (0.3.0)" means you need an image with rayd 0.3.0 or later
(agent_version); against an earlier one, each feature fails closed with
UnimplementedError (LifecycleUnsupportedException for the server-side
deadline, a subclass of it since 0.4.0; the rest already were).
There is no variant that combines -caps and -poly: no make target
publishes it and the combination has not been measured.
How the SDK recognizes the variant¶
Before launching, the SDK tries to deduce the variant from the image's
name, only to reject early (and without paying for the launch) what that
image cannot do. It only recognizes rayito-<variant> or
rayito-<variant>-<size>, with the variant in the closed catalog base,
base-caps, base-caps-efs, base-poly and base-slim, and the size among
those in Sizes (512mb, 1gb, 2gb,
4gb, 8gb). With a known variant:
mounts=andtelemetry=with the execution role requirebase-capsorbase-caps-efs;volumes=requiresbase-caps-efs:base-capswithoutamazon-efs-utilscannot mount EFS.
Any other name (an image of your own, even if it starts with rayito-, such
as rayito-my-app) or an ARN is not interpreted: the SDK launches the
sandbox and decides from what the agent announces in Health.features, which
remains the authority. If the image does not have the feature, the sandbox is
terminated (unless keep_on_failure) and UnimplementedError is raised. So,
an image of your own with caps and EFS layers published with --image-name
works without changing anything.
Publish all three¶
Without compiling anything, rayito-base and rayito-base-caps are
published from each release's signed rayito-image.zip
(Set up AWS).
From source (Linux or WSL2, to compile rayd):
export AWS_PROFILE=<your-profile> AWS_REGION=us-east-1
make image-publish BUCKET=amzn-s3-demo-bucket # rayito-base
make image-publish-caps BUCKET=amzn-s3-demo-bucket # rayito-base-caps (additionalOsCapabilities ALL)
make image-publish-poly BUCKET=amzn-s3-demo-bucket # rayito-base-poly (bash, JavaScript, TypeScript)
make image-publish-caps-efs BUCKET=amzn-s3-demo-bucket # optional: rayito-base-caps-efs, for volumes=
BUCKET= can also be exported as RAYITO_BUCKET; with neither, make stops
before compiling. MOUNT_BUCKETS=b1,b2 on the -caps targets bakes in the
allowlist for S3 mounts, and
PUBLISH_ARGS= passes extra options to rayito image publish (for example
--force or --sizes 4gb). The agent image does not come from make: it is
built with rayito agent template build on top of an already published
rayito-base-caps (Agent templates).
Or with the CLI (rayito image publish, CLI); the
bucket is the one for image artifacts (prefix rayito/), not the transfer
one. Each new version costs ≈ $0.04/week of storage (Costs).
Size (CPU/RAM) is also a property of the image, with --memory-mib
(resources[0].minimumMemoryInMiB, default 2048): to have sandboxes of
several sizes, publish one image per size with a name that says so
(--image-name myimg-4gb --memory-mib 4096) and choose the image when
creating the sandbox. Details, the size table (from AWS's documentation, not
measured except where stated) and the $/h per size are in
Limits.
import { Sandbox } from "rayito";
const base = await Sandbox.create({ template: "rayito-base" }); // or RAYITO_TEMPLATE
const caps = await Sandbox.create({ template: "rayito-base-caps", allowInternetAccess: false });
const poly = await Sandbox.create({ template: "rayito-base-poly" });
console.log((await poly.runCode("1 + 1", { language: "typescript" })).text);
for (const sbx of [base, caps, poly]) {
await sbx.kill();
}
With AWS CDK
The RayitoMicrovmImage construct publishes an image with rayd (and its
sizes) from your CDK app, with the same configuration as
rayito image publish; sandboxes are still created with the SDK by name.
The rayito-base* names stay with rayito setup and
rayito image publish: Deploy with CDK.
Caller IAM¶
The SDK runs with your credentials (the boto3 / AWS SDK v3 chain).
infra/iam.yaml ships SandboxLauncherPolicy (launch and manage sandboxes),
ImagePublisherPolicy (publish images) and CallerPolicy, the union of the
two. The full table, feature by feature and with the optional secrets and
index policies, is in IAM. What each feature on this page
adds:
| Feature | New permissions |
|---|---|
Server-side deadline (kill and pause) |
none: with kill, rayd exits and the VM ends on its own; with pause, the SDK uses suspend-microvm, which was already there |
Class forms (Sandbox.set_timeout(id), get_metrics_history(id), update_network(id)) |
none: get-microvm and create-microvm-auth-token, which were already there, plus the sandbox's access token |
| Egress policy | none on the caller; the rayito-base-caps image is published with --os-capabilities ALL |
| Metrics history, listing, git, JS/TS kernels | none |
Transfers (upload_url, download_url, large files) |
s3:PutObject, s3:GetObject, s3:DeleteObject, s3:AbortMultipartUpload on <bucket>/<prefix>/* and s3:ListBucket scoped to the prefix |
With the template, two parameters add them (empty = no transfer permissions):
aws cloudformation deploy --stack-name rayito-m0-iam \
--template-file infra/iam.yaml --capabilities CAPABILITY_NAMED_IAM \
--profile <your-profile> \
--parameter-overrides ArtifactBucket=amzn-s3-demo-bucket LogGroupPrefix=/rayito \
TransferBucket=amzn-s3-demo-bucket TransferPrefix=rayito-transfer
Without the template, the equivalent to add to your policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "TransferObjects",
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:AbortMultipartUpload"],
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/rayito-transfer/*"
},
{
"Sid": "TransferMissingKeyIs404",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket",
"Condition": { "StringLike": { "s3:prefix": "rayito-transfer/*" } }
}
]
}
s3:PutObjectalso coversCreateMultipartUpload,UploadPartandCompleteMultipartUpload(exports from 5 GiB).- Without
s3:ListBucket, a missing key gives 403 instead of 404 and the import treats it as pending until it expires. - With SSE-KMS, add
kms:GenerateDataKey(uploads) andkms:Decrypt(downloads) on the key; the template does not include it. - The sandbox's execution role needs nothing:
raydnever signs or stores credentials for transfers (see Security).
The transfer bucket¶
Full recipe in infra/README.md, "File transfers". The essentials:
- Same region as the sandboxes (or
S3Staging(region=)), name without dots: the SDK signs with the regional virtual host (amzn-s3-demo-bucket.s3.us-east-1.amazonaws.com) andraydrejects any other form. - A prefix of its own (
rayito-transferby default): neverrayito(the image artifacts) nor the persistence one. - 1-day lifecycle on the prefix, with
AbortIncompleteMultipartUpload: the objects are single-use. - Bucket policy that rejects anything that is not SigV4
(
s3:signatureversion) and anything that does not go over TLS (aws:SecureTransport). - CORS only if a browser uploads or downloads directly, with explicit origins.
- Network: with
INTERNET_EGRESSthere is nothing to do; with your own VPC connector (infra/egress-connector.yaml) the VM needs to reach S3 (gateway endpoint or NAT). The guest's egress policy does not affectrayd(root), which is the one moving the bytes.
Configure it in the SDK with transfer=S3Staging("amzn-s3-demo-bucket") (TS
transfer: { bucket: "amzn-s3-demo-bucket" }) or with the variables
RAYITO_TRANSFER_BUCKET, RAYITO_TRANSFER_PREFIX and RAYITO_TRANSFER_REGION
(the only route in the E2B shim).