| Service Name: | Lambda MicroVMs |
| ARN Format: | arn:aws:lambda:{region}:{account}:microvm-image:{image name} or
arn:aws:lambda:{region}:{account}:microvm-image:{image name}:{version} |
| Style: | Request/Response |
| Actions (required Permissions): |
lambda:RunMicrovm,lambda:CreateMicrovmAuthToken,lambda:GetMicrovmImage,lambda:GetMicrovmImageVersion,lambda:GetMicrovm,lambda:ResumeMicrovm,lambda:TerminateMicrovm,iam:PassRole (when ExecutionRoleArn is set)
|
| Payload Format: | JSON object with array of request packet objects, sent over HTTPS |
| Arguments: |
ExecutionRoleArn (string, optional),RunHookExtraData (string, optional),EgressNetworkConnectorArns (list of strings, optional),IdleDurationSeconds (string containing an integer, optional),TenantId (string, optional),TenantIdExpression (binary range expression, optional),TenantIdFormatter (string "ascii", "hex", "base64" or "utf8", optional)
|
A Lambda MicroVM is a full Linux environment, built from a container image you provide, that keeps running (and keeps its memory) across requests until it is suspended or terminated. Using a MicroVM image as a destination suits UDP workloads that need long-lived, in-memory state per client or tenant, software that does not fit the Lambda function model, or an HTTP application you would rather not rewrite as a function. For stateless packet handling, Lambda functions are simpler.
The destination is a MicroVM image, not a running MicroVM. Proxylity starts MicroVMs from the image when packets arrive, delivers batches to them, and sends their replies back to the remote UDP client.
RunMicrovm to start one
from the image, using the execution role from Arguments.ExecutionRoleArn if one is given./run hook, Lambda calls it with the MicroVM ID and a
run hook payload from Proxylity. Traffic is routed once the hook returns.CreateMicrovmAuthToken for a token scoped to port 8080, and
POSTs batches of packets to the MicroVM's HTTPS endpoint as JSON.Note: The first packet for a tenant starts the MicroVM, so it may be dropped or answered late
while the MicroVM reaches the RUNNING state. Send a few packets when testing.
With an ARN that has no version suffix, new MicroVMs run the latest active version of the image, so publishing
a new version takes effect for MicroVMs started after that (running MicroVMs are not replaced). To pin the
destination to a specific version, add the version to the ARN
(...:microvm-image:my-image:3). Proxylity re-reads the image version at most once a minute.
If Proxylity cannot read the image (for example, the destination role is missing
lambda:GetMicrovmImage or lambda:GetMicrovmImageVersion), it logs a warning and starts
MicroVMs without choosing a version and without the run hook payload, so the version is left to Lambda.
The application must listen for HTTP requests on port 8080. This port is fixed. Each request
body is a JSON object with a Messages property containing an array of
request packet objects, the same format used by
Lambda destinations:
{
"Messages": [{
"Tag": "opaque-correlation-tag",
"Remote": { "IpAddress": "203.0.113.10", "Port": 45678 },
"Local": { "Domain": "ingress-1", "Port": 15678 },
"Formatter": "base64",
"Data": "aGVsbG8="
}]
}
The application responds with a Replies array. Replies are matched to messages using
Tag. If no replies are needed, return an empty array:
{ "Replies": [{ "Tag": "opaque-correlation-tag", "Data": "SGVsbG8gZnJvbSBNaWNyb1ZNLi4u" }] }
The Data format follows the destination's Formatter property, for both requests and
replies (base64 by default).
All arguments are optional.
| Argument | Default | Description |
|---|---|---|
ExecutionRoleArn |
none | IAM role the MicroVM runs with. Required for the application to use AWS services, and for its
stdout/stderr to be forwarded to CloudWatch Logs. The role must be assumable by
lambda.amazonaws.com, and the destination role needs iam:PassRole on it,
conditioned on iam:PassedToService equal to lambda.amazonaws.com. |
RunHookExtraData |
none | String of up to 2048 characters, delivered to the /run hook as ExtraData.
Use it for application settings; do not put secrets in it. |
IdleDurationSeconds |
900 |
Seconds without packets before the MicroVM is suspended to save compute cost. Values are clamped to 60 to 28800 (1 minute to 8 hours); 28800 keeps the MicroVM running for its whole lifetime. A suspended MicroVM resumes automatically when packets arrive, which adds latency to the first packet. |
EgressNetworkConnectorArns |
none | List of 1 to 10 customer-managed Lambda network connector
ARNs (optionally version-qualified, ...:network-connector:{id}:{version}) that
MicroVMs use for outbound traffic. Without it Lambda's default applies, which gives MicroVMs
public internet access. See Network Access. |
TenantId, TenantIdExpression, TenantIdFormatter |
none | Start one MicroVM per tenant, using a fixed tenant ID or one extracted from each packet. See Tenants. |
By default Lambda gives a MicroVM public internet access for outbound traffic, and Proxylity starts MicroVMs
with that default. To restrict it, create a Lambda network connector that routes the MicroVM's outbound
traffic through your VPC (for example one with no route to the internet) and list its ARN in
EgressNetworkConnectorArns. Proxylity passes the connectors to RunMicrovm when it
starts a MicroVM, so the VPC's routing, security groups and network ACLs control what the application can
reach. Connectors cannot change while a MicroVM is running: MicroVMs that are already running keep the
connectors they started with, and a change applies to MicroVMs started afterward. The inbound path used for
packet delivery is not affected.
The destination role must be allowed to pass the connectors that RunMicrovm attaches. Without
EgressNetworkConnectorArns these are the AWS-managed HTTP_INGRESS and
INTERNET_EGRESS connectors, as in the example below. With it, grant
lambda:PassNetworkConnector on HTTP_INGRESS and on your connectors (and on their
unversioned ARNs if you pin versions), and leave out INTERNET_EGRESS so the role cannot start
MicroVMs with internet access. The execution role is separate: with no internet or VPC endpoints the
application cannot reach AWS APIs regardless of its policy, so omit ExecutionRoleArn or grant
only what the endpoints in your VPC provide.
Without a tenant setting, all packets go to a single MicroVM. Set Arguments.TenantId to a fixed
string, or Arguments.TenantIdExpression to a
binary range expression (for example "u8[0] >> 6 ?? 0") and
optionally Arguments.TenantIdFormatter to start a separate MicroVM for each tenant. Batches are
split by tenant, and tenants are delivered concurrently. This is the natural way to give each client, device or
customer its own isolated, stateful environment.
IdleDurationSeconds is
suspended and resumes automatically when packets arrive./run hook failed) is not replaced for 5 minutes, and packets for that tenant are
dropped in the meantime. The reason is written to the destination's log group./run hooks free of side effects that assume they run once per tenant.The /run hook is optional. Proxylity sends a run hook payload only if the image version it starts
enables the hook. Lambda posts { "microvmId": "...", "runHookPayload": "..." } to the hook, where
runHookPayload is a JSON string:
{
"Version": 1,
"DestinationName": "the destination's name",
"ImageArn": "arn:aws:lambda:us-west-2:123456789012:microvm-image:my-image",
"TenantId": "tenant ID, or null",
"Region": "the region delivering packets to this MicroVM",
"Formatter": "base64",
"Port": 8080,
"StartedAt": "2026-11-07T18:00:00.0000000Z",
"ExtraData": "the RunHookExtraData argument, or null"
}
The payload never contains credentials or tokens. Serve the hooks on a port other than 8080 (the example uses
9000) so they cannot be reached with the port 8080 token Proxylity holds. Lambda limits the whole payload to
4096 characters; if a long tenant ID and RunHookExtraData exceed it, the MicroVM is not started and
an error is logged.
The destination role below is assumed by Proxylity. MicroVM actions are authorized against the image the MicroVM
runs from, so scoping them to the image's ARN limits the destination to MicroVMs started from that image.
RunMicrovm also requires lambda:PassNetworkConnector for each network connector attached
to the MicroVM.
DestinationRole:
Type: AWS::IAM::Role
Properties:
# AssumeRolePolicyDocument for Proxylity omitted; see the Access and Permissions docs
Policies:
- PolicyName: microvm
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- lambda:RunMicrovm
- lambda:GetMicrovm
- lambda:ResumeMicrovm
- lambda:TerminateMicrovm
- lambda:GetMicrovmImage
- lambda:GetMicrovmImageVersion
- lambda:CreateMicrovmAuthToken
Resource: !GetAtt EchoMicrovmImage.ImageArn
- Effect: Allow
Action: lambda:PassNetworkConnector
Resource:
- !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:aws:network-connector:aws-network-connector:HTTP_INGRESS"
- !Sub "arn:${AWS::Partition}:lambda:${AWS::Region}:aws:network-connector:aws-network-connector:INTERNET_EGRESS"
- Effect: Allow
Action: iam:PassRole
Resource: !GetAtt MicrovmExecutionRole.Arn
Condition:
StringEquals:
iam:PassedToService: lambda.amazonaws.com
UdpListener:
Type: Custom::ProxylityUdpGatewayListener
Properties:
# ...
Destinations:
- Description: Deliver UDP packets to a Lambda MicroVM
Role:
Arn: !GetAtt DestinationRole.Arn
DestinationArn: !GetAtt EchoMicrovmImage.ImageArn
Arguments:
IdleDurationSeconds: "900"
TenantIdExpression: "u8[0] >> 6 ?? 0"
TenantIdFormatter: hex
ExecutionRoleArn: !GetAtt MicrovmExecutionRole.Arn
RunHookExtraData: '{"Example":"lambda-microvm"}'
The image itself is declared with the AWS::Serverless::MicrovmImage SAM resource. See the complete
Lambda MicroVM example, including
a small Node.js application, step-by-step deployment and test commands.