
AWS LambdaMicroVm
CertifiedEnterprise EditionTask runner that executes a task in an AWS Lambda MicroVM
AWS LambdaMicroVm
Task runner that executes a task in an AWS Lambda MicroVM
Enterprise Edition only.
This task runner starts an AWS Lambda MicroVM, runs your task's
commands in it, then terminates it. The microVM is isolated and starts fast, so it suits short and bursty jobs that should not
share a machine. The containerImage property is ignored: a microVM runs a Lambda microVM image, not a container image.
Minimal setup. Set region, bucket, buildRoleArn and executionRoleArn. The first run builds a microVM image holding the Kestra agent in your
account (a few minutes, once). Later runs reuse it. The image is built from a Dockerfile on
public.ecr.aws/lambda/microvms: al2023-minimal, so commands get the Amazon Linux 2023 minimal userland (arm64). The image is named kestra-task-runner-<hash> and never changes, so a plugin
upgrade or a different memory builds a new image next to the old one. If the build fails, the error carries AWS's reason and
the build log location: fix the cause, delete the failed image and run again.
How a run works. The runner uploads your input files and the commands to bucket (under kestra-lambda-microvm/), starts
the microVM with short-lived links to those objects, and waits for the agent to write the result back. The microVM needs no IAM
role for this. The staged objects, which include the task's environment variables, are deleted when the run ends, so use a bucket
you trust and, ideally, with default encryption. Command output appears in the Kestra logs, and the exit code is the real exit code of
your commands. Access the working directory with {{ workingDir }} or the WORKING_DIR environment variable. To pass
inputFiles, outputFiles, or namespaceFiles, nothing more is needed: bucket is always used.
Differences from Batch and Ec2.
- There is no
containerImage, no vCPU and no disk setting: the Lambda MicroVMs API only exposes memory, set withmemory, which applies to the image. - microVMs run on
arm64only: binaries and native Python wheels your commands use must bearm64. - A run lasts at most 8 hours (
waitUntilCompletion). - The first run in a region builds the image.
- File permissions are not kept when files go through the staging bucket, as with
Ec2. - On a failed run, Kestra core drops the
taskRunneroutputs, so the runtime details (microvmId,state,stateReason,startedAt,stoppedAt,imageArn,imageVersion,logGroup,logStream,region) are available in{{ outputs.<taskId>.vars.kestraTaskRunner }}instead.
Runner credentials. The credentials need (action names follow the API operation names):
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": ["lambda: RunMicrovm", "lambda: GetMicrovm", "lambda: TerminateMicrovm"], "Resource": "*"},
{"Effect": "Allow", "Action": ["lambda: CreateMicrovmImage", "lambda: GetMicrovmImage", "lambda: ListMicrovmImages",
"lambda: GetMicrovmImageVersion", "lambda: ListManagedMicrovmImages", "lambda: ListManagedMicrovmImageVersions", "lambda: TagResource"], "Resource": "*"},
{"Effect": "Allow", "Action": "iam: PassRole", "Resource": ["<buildRoleArn>", "<executionRoleArn>"],
"Condition": {"StringEquals": {"iam: PassedToService": "lambda.amazonaws.com"}}},
{"Effect": "Allow", "Action": "lambda: PassNetworkConnector", "Resource": "arn: aws: lambda: *: aws: network-connector: *"},
{"Effect": "Allow", "Action": ["s3: PutObject", "s3: GetObject", "s3: DeleteObject", "s3: AbortMultipartUpload"], "Resource": "arn: aws: s3: : : <bucket>/kestra-lambda-microvm/*"},
{"Effect": "Allow", "Action": ["s3: ListBucket", "s3: GetBucketLocation"], "Resource": "arn: aws: s3: : : <bucket>"},
{"Effect": "Allow", "Action": "logs: DescribeLogGroups", "Resource": "*"},
{"Effect": "Allow", "Action": ["logs: CreateLogGroup", "logs: FilterLogEvents"], "Resource": "arn: aws: logs: <region>: <account>: log-group: <logGroup>: *"}
]
}
lambda: PassNetworkConnector is needed because, with no network connector set, AWS applies its managed INTERNET_EGRESS and
HTTP_INGRESS connectors to the microVM, and passing them requires this permission.
Custom connectors set in ingressNetworkConnectors or egressNetworkConnectors need their own ARNs added to that statement.
The runner credentials must also be valid for the whole run, since the links are signed with them: with temporary credentials, make sure they outlive waitUntilCompletion.
Encryption with KMS. With serverSideEncryption: aws: kms (or an SSE-KMS bucket default), add a statement for the key to the runner credentials:
kms: GenerateDataKey to upload the bundle, the input archive and the agent's code artifact, and kms: Decrypt because the microVM reads the bundle and
the input archive through presigned links, which act with these credentials, and the runner reads the result back. The build role needs kms: Decrypt
on the same key to read the agent's code artifact. Objects the microVM writes through presigned links (output.zip, status.json) use the bucket's default encryption:
an SSE-KMS bucket default covers them, and the runner credentials then need kms: GenerateDataKey on that key too, as they sign those links.
{"Effect": "Allow", "Action": ["kms: GenerateDataKey", "kms: Decrypt"], "Resource": "arn: aws: kms: <region>: <account>: key/<key id>"}
Build role (buildRoleArn). Lambda assumes this role to build the image. Its trust policy:
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts: AssumeRole"}
]
}
Its permissions policy:
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "s3: GetObject", "Resource": "arn: aws: s3: : : <bucket>/kestra-lambda-microvm/bootstrap/*"},
{"Effect": "Allow", "Action": ["logs: CreateLogStream", "logs: PutLogEvents"], "Resource": "arn: aws: logs: <region>: <account>: log-group: <logGroup>: *"}
]
}
Execution role (executionRoleArn). Required. The runner has the microVM write its logs to CloudWatch, which it reads back to get the
command output, and AWS writes those logs as this role. It uses the same trust policy (lambda.amazonaws.com). Its permissions policy
needs the log permissions below, plus whatever your own commands need (for example s3: GetObject for aws s3 cp):
{
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": ["logs: CreateLogStream", "logs: PutLogEvents"], "Resource": "arn: aws: logs: <region>: <account>: log-group: <logGroup>: *"}
]
}
For a quick setup, one role can serve as both the build and the execution role (same trust policy, merged permissions); separate roles are cleaner, as the build role then carries no permission your commands could use.
In the IAM console, create the roles with the trusted entity "AWS service" and the use case "Lambda".
To use your own image instead, set imageIdentifier (and imageVersion). It must embed the Kestra agent, which is the bootstrap
executable listening on 0.0.0.0: 8080 and serving POST /aws/lambda-microvms/runtime/v1/{run,terminate,validate,ready}.
Security note. The agent's hooks are not authenticated. With no ingressNetworkConnectors set, AWS attaches its managed
HTTP_INGRESS connector to the microVM. According to the AWS samples, reaching a microVM through that ingress requires a MicroVM
auth token (lambda: CreateMicrovmAuthToken), so keep that permission restricted to trusted principals. Do not add other ingress
connectors that would expose port 8080: any peer that can reach it could start a job or stop the running one.
type: io.kestra.plugin.ee.aws.runner.LambdaMicroVmExamples
Run a Shell command in a Lambda MicroVM. The image is built on the first run.
id: lambda_microvm_shell
namespace: company.team
tasks:
- id: shell
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.ee.aws.runner.LambdaMicroVm
accessKeyId: "{{ secret('AWS_ACCESS_KEY_ID') }}"
secretKeyId: "{{ secret('AWS_SECRET_KEY_ID') }}"
region: us-east-1
bucket: my-kestra-staging-bucket
buildRoleArn: arn:aws:iam::123456789012:role/kestra-microvm-build
executionRoleArn: arn:aws:iam::123456789012:role/kestra-microvm-execution
commands:
- echo "Hello World"Pass input files to the task, run it with 2 GiB of memory, then retrieve the output files.
id: lambda_microvm_with_input_files
namespace: company.team
inputs:
- id: file
type: FILE
tasks:
- id: shell
type: io.kestra.plugin.scripts.shell.Commands
inputFiles:
data.txt: "{{ inputs.file }}"
outputFiles:
- out.txt
taskRunner:
type: io.kestra.plugin.ee.aws.runner.LambdaMicroVm
accessKeyId: "{{ secret('AWS_ACCESS_KEY_ID') }}"
secretKeyId: "{{ secret('AWS_SECRET_KEY_ID') }}"
region: us-east-1
bucket: my-kestra-staging-bucket
buildRoleArn: arn:aws:iam::123456789012:role/kestra-microvm-build
executionRoleArn: arn:aws:iam::123456789012:role/kestra-microvm-execution
memory: 2048
waitUntilCompletion: PT30M
commands:
- cp {{ workingDir }}/data.txt {{ workingDir }}/out.txtProperties
bucket *string
S3 bucket used to stage the task's files and result
Always required: the runner uploads inputFiles, namespaceFiles and the commands here, and the microVM writes outputFiles and its result back. Everything is kept under the kestra-lambda-microvm/ prefix and removed when the run ends, except the agent's code artifact (kestra-lambda-microvm/bootstrap/), which is reused by later runs.
As a safety net in case a run is killed before it can clean up, add an S3 lifecycle rule that expires the objects under kestra-lambda-microvm/run/ after one day.
executionRoleArn *string
IAM role the microVM assumes while running
Always required, with a custom imageIdentifier too: the runner has the microVM log to CloudWatch to read the command output, and AWS writes those logs as this role. The role must trust lambda.amazonaws.com and allow logs: CreateLogStream and logs: PutLogEvents on the CloudWatch log group logGroup (arn: aws: logs: <region>: <account>: log-group: <logGroup>: *), plus whatever your commands need when they call AWS themselves (for example aws s3 cp). Staging the task's files never needs more. The credentials of the runner need iam: PassRole on it. It can be the same role as buildRoleArn for a quick setup, but separate roles are cleaner.
region *string
AWS region
The region the microVMs, the staging bucket and the log group live in, for example us-east-1. Lambda MicroVMs are not available in every region.
accessKeyId string
AWS access key ID
With secretKeyId, static credentials. If none are set, the AWS default credentials provider chain is used.
baseImageArn string
Lambda-managed base image the runner builds its image on
Defaults to the only managed base image AWS lists for the region. If AWS lists several (or none), the run fails and asks for this property. The base image is part of the image name, so changing it builds a separate image. The newest available version of the base image is used.
buildRoleArn string
IAM role Lambda assumes to build the microVM image
Required unless imageIdentifier is set. The role must trust the lambda.amazonaws.com service principal and allow s3: GetObject on s3://<bucket>/kestra-lambda-microvm/bootstrap/*, plus logs: CreateLogStream and logs: PutLogEvents on the CloudWatch log group logGroup. The credentials of the runner need iam: PassRole on it. It can be the same role as executionRoleArn for a quick setup (same trust policy, merged permissions), but separate roles are cleaner.
completionCheckInterval string
PT5SHow often Kestra polls for the task's completion
Defaults to PT5S. Set a lower value (e.g. PT0.1S) for quick tasks and a higher one (e.g. PT1M) for long-running tasks. A lower value makes more API calls to the remote service, so raise it if you see API rate limit errors.
egressNetworkConnectors array
Egress network connectors of the microVM
ARNs or IDs of the network connectors that allow outbound traffic from the microVM. With none set, AWS attaches its managed INTERNET_EGRESS connector, which is why lambda: PassNetworkConnector is needed on arn: aws: lambda: *: aws: network-connector: *.
endpointOverride string
Endpoint override
Replaces the AWS endpoint of every service the runner calls. Only for emulators or private endpoints.
idlePolicy
Idle policy of the microVM
Sets what AWS does with a microVM that receives no activity. Unset by default: no policy is sent, so the service default applies. Every field is optional and only the ones you set are sent. Beware that a suspended microVM stops running your commands.
io.kestra.plugin.ee.aws.runner.LambdaMicroVm-IdlePolicyConfiguration
Resume a suspended microVM automatically
Maps to autoResumeEnabled.
Idle time before the microVM is suspended
Whole seconds, at least PT1S. Maps to maxIdleDurationSeconds.
How long a suspended microVM is kept
Whole seconds, at least PT1S. Maps to suspendedDurationSeconds.
imageIdentifier string
Custom microVM image to run instead of the one the runner builds
The ARN or ID of an image that embeds the Kestra agent (serving POST /aws/lambda-microvms/runtime/v1/{run,terminate,validate,ready} on port 8080). When set, nothing is built and buildRoleArn is not needed.
imageVersion string
Version of the custom image to run
Only used with imageIdentifier. Defaults to the latest active version, which is then pinned for the run.
ingressNetworkConnectors array
Ingress network connectors of the microVM
ARNs or IDs of the network connectors that allow inbound traffic to the microVM. With none set, AWS attaches its managed HTTP_INGRESS connector, which is why lambda: PassNetworkConnector is needed on arn: aws: lambda: *: aws: network-connector: *. Do not add a connector that exposes port 8080: the agent's hooks are not authenticated.
kmsKeyId string
KMS key used when serverSideEncryption is aws: kms or aws: kms: dsse
Key ID, key ARN or alias ARN; S3 uses the AWS managed key aws/s3 when unset. Rejected when serverSideEncryption is AES256. See "Encryption with KMS".
logGroup string
/aws/lambda-microvm/kestraCloudWatch log group for the microVM output and the image build logs
Created if it does not exist. Defaults to /aws/lambda-microvm/kestra. Each run writes to its own log stream.
memory integerstring
Memory of the microVM, in MiB
Sets the minimum memory of the image the runner builds, for example 2048; it must be positive. Leave it unset to use the service default. The memory belongs to the image, so each value gets its own image, built on its first use.
monitoring
{
"enabled": "false",
"metricsInterval": "PT1S"
}Report the command's resource usage and traces as task metrics
Runs the command under kotlp.
io.kestra.plugin.ee.aws.runner.LambdaMicroVm-MonitoringConfiguration
falseRun the command under kotlp
Reports CPU, memory and disk I/O, plus any OpenTelemetry traces the command exports, as task metrics, and logs stderr at ERROR.
The kotlp binary is staged through bucket, and the Kestra agent unpacks it, so the image only needs /bin/sh (no gzip, which the Lambda-managed base image lacks).
PT1SHow often kotlp samples the process's resource usage
Passed to kotlp as --interval. Between PT0.001S and PT1H.
secretKeyId string
AWS secret access key
serverSideEncryption string
AES256AES256AWS_FSXAWS_BACKUPAWS_KMSAWS_KMS_DSSEUNKNOWN_TO_SDK_VERSIONServer-side encryption of the objects the runner uploads to the staging bucket
One of AES256 (SSE-S3), aws: kms or aws: kms: dsse; defaults to AES256. Applies to the bundle, the input archive and the agent's code artifact, not to output.zip and status.json. See "Encryption with KMS" for the permissions and the bucket default.
sessionToken string
AWS session token
For temporary credentials. They must stay valid for the whole run, see waitUntilCompletion.
stsEndpointOverride string
STS endpoint override
stsRoleArn string
IAM role to assume through STS
The session lasts as long as stsRoleSessionDuration, which must cover waitUntilCompletion: it defaults to the wait of the run (waitUntilCompletion, or the task timeout when it is set) plus 15 minutes, capped at 1 hour (the default maximum session of a role). A longer wait needs an explicit stsRoleSessionDuration.
stsRoleExternalId string
External ID for the assumed role
stsRoleSessionDuration string
Duration of the assumed role session
Unset by default, which sizes it on the wait of the run, waitUntilCompletion or the task timeout when that is set (see stsRoleArn). A role cannot be assumed for longer than its own maximum session duration.
stsRoleSessionName string
Session name for the assumed role
syncWorkingDirectory booleanstring
falseSync the whole working directory back from the microVM
When true, the whole working directory of the microVM is uploaded back to Kestra after the commands finish, not only the outputFiles and the output directory. Defaults to false.
version string
Plugin Version
Defines the version of the plugin to use.
The version must follow the Semantic Versioning (SemVer) specification:
- A single-digit MAJOR version (e.g.,
1). - A MAJOR.MINOR version (e.g.,
1.1). - A MAJOR.MINOR.PATCH version, optionally with any qualifier
(e.g.,
1.1.2,1.1.0-SNAPSHOT).
waitForLogInterval string
PT5SPost-completion CloudWatch log drain period
Once the task reports its result, the task runner keeps polling CloudWatch Logs until no new output has arrived for this long, so a short command's entire output burst, which can land in CloudWatch a second or two after the task ended, isn't lost. Defaults to PT5S.
waitUntilCompletion string
PT1HThe maximum duration to wait for the task to complete unless the task timeout property is set which will take precedence over this property
The task is failed if the commands have not finished by then, and the microVM is also capped to this duration. Defaults to PT1H, and cannot exceed PT8H, the longest a microVM can run. A longer value is rejected instead of being shortened.