pub struct CreateImageRequest {Show 17 fields
pub name: String,
pub base_image: BaseImage,
pub base_image_version: Option<String>,
pub dockerfile: Option<String>,
pub binary: Vec<u8>,
pub project_files: Option<ProjectFiles>,
pub code_artifact_uri: String,
pub build_role_arn: String,
pub size: SizeClass,
pub repair_guest_identity: bool,
pub inherit_workdir: bool,
pub run_hook_timeout: RunHookTimeout,
pub build_hook_timeout: BuildHookTimeout,
pub tags: BTreeMap<String, String>,
pub log_group: Option<String>,
pub log_stream: Option<String>,
pub token_scope: Option<String>,
}Expand description
Everything CreateMicrovmImage needs, with the traps closed in the type.
§What is deliberately not here
A client_token field. See token for the fifteen-hour wedge that absence prevents;
CreateImageRequest::token_scope is a label folded in beside a fresh nonce and
cannot become the token.
A capabilities list. See repair_guest_identity.
An architecture field. The model’s enum has exactly one value, so the only thing a
field could express is a rejected request — and the rejection arrives after the
artifact upload, reported as a constraint on a field the caller thought was a choice.
ARM_64 is injected. A caller who built an x86 binary finds out from doctor’s ELF
check, not from a build cycle.
Fields§
§name: StringThe image name. Validated against ImageName (1..=64, [a-zA-Z0-9-_]+) before the
artifact is uploaded, because AWS’s rejection arrives after the upload.
base_image: BaseImageThe base image, pairing the baseImageArn with the Dockerfile FROM.
base_image_version: Option<String>baseImageVersion, or None to take whatever the service currently defaults to.
§Why pinning is worth a field
Without it a build floats. The managed base’s version list is not static — al2023-1
carried one version in June and two by July ("0" and "1", measured 2026-08-16) — so
two builds of identical inputs weeks apart can sit on different bases, and neither
recorded which. That is a reproducibility hole with no local symptom: the build
succeeds either way, and the difference appears in the guest.
None is the default and stays the default, because pinning without knowing the legal
values is how a caller pins to a version that has been withdrawn.
ControlPlane::managed_base_versions is what answers that, and the version strings
are bare integers for a managed base where a custom image’s are "1.0" — the two
are not comparable, so a value from anywhere else does not belong here.
Checked against the Version shape before the call, because the create happens after
the artifact upload.
dockerfile: Option<String>The Dockerfile, or None for the derived default.
A caller-supplied one is checked against base_image’s docker_ref: the two
disagreeing builds against a base none of the measured platform behaviour applies
to.
binary: Vec<u8>The daemon binary’s bytes, zipped into the artifact.
project_files: Option<ProjectFiles>The project’s dependency files — the lockfile plus its manifest — zipped into the
artifact beside the Dockerfile, or None for an image with no environment layer.
This is what lets the derived Dockerfile’s install step (uv sync --locked,
npm ci, cargo fetch per Ecosystem) see the files it installs from (#74).
The entry names are fixed by the ecosystem; there is no way to put an arbitrary
file into the shared snapshot through this field, which is the TRAP-5 property
restated as a type.
code_artifact_uri: StringWhere the artifact is uploaded to. create_image does not upload: the caller puts
the bytes there and passes the URI. crate::sandbox::Sandbox::ensure_image is the
path that uploads for itself (services).
build_role_arn: StringThe build role, which must grant logs on /aws/lambda-microvms/*.
size: SizeClassThe size class. Selects a documented baseline; it does not size the VM (TRAP-10).
repair_guest_identity: boolWhether to repair guest identity (TRAP-3).
§Why a bool and not a capability list
Measured 2026-08-06: without the capability, a guest running as root still gets
EPERM from sethostname and from a bind mount over
/proc/sys/kernel/random/boot_id, because the MicroVM drops CAP_SYS_ADMIN by
default. Writing /etc/machine-id needs no capability and succeeds either way,
which is what makes the gap easy to miss — identity repair looks like it works
until you check the two steps that need the kernel’s permission rather than the
filesystem’s.
Capability’s enum is exactly ["ALL"], so there is no way to ask for
CAP_SYS_ADMIN alone. A list parameter would let a caller write
["CAP_SYS_ADMIN"] — the request AWS rejects after the artifact upload — so the
intent is a boolean and the request injects ["ALL"] itself.
inherit_workdir: boolWhether the daemon should inherit the image’s WORKDIR.
Rejected when nothing declares one: most public ARM64 bases leave it empty, so the
inheritance silently resolves to / and the symptom appears in the guest a build
cycle later.
run_hook_timeout: RunHookTimeoutThe run-family hook timeout: run, resume, suspend, terminate. Caps at 60s,
and the type is what keeps a build-sized value out of it.
build_hook_timeout: BuildHookTimeoutThe build-family hook timeout: ready, validate. Caps at 3600s.
Tags, or none.
log_group: Option<String>logging.cloudWatch.logGroup, or None for the service default — a
service-created group under /aws/lambda-microvms/<image-name> with random stream
names.
Checked against CloudWatchLoggingLogGroupString (1..=512, [a-zA-Z0-9_\-/.#]+)
before the artifact upload. The build role must be able to write to whatever this
names: the conformance account’s role grants logs only on
/aws/lambda-microvms/*, so a group outside that prefix builds with no logs at
all — the same failure mode as the wrong-prefix policy (docs/PLATFORM.md).
log_stream: Option<String>logging.cloudWatch.logStream — a stream-name prefix, never the exact name.
§The client always appends a per-build discriminator
The wire member is an EXACT stream name (prefixes unsupported — measured 2026-08,
docs/PLATFORM.md ‘An image build is three VMs and three log streams’), and one
build emits three streams. A fixed configured name collapses all three of every
build into one stream, so ControlPlane::create_image sends
<this>/<16 hex> with fresh CSPRNG per create attempt — the same mechanism as
the clientToken nonce (TRAP-1) — and the resolved name comes back on
image::Image::log_stream so the caller can find their logs.
Capped at crate::constants::MAX_USER_LOG_STREAM_LEN (495) so the resolved name
fits the shape’s 512, and refused when it carries : or * (the pattern is
[^:*]*). Requires Self::log_group: a stream inside a group the service
chose randomly is a stream nobody can predict the location of.
token_scope: Option<String>A label folded into the create token for CloudTrail readability, defaulting to the image name. Not the token, and cannot become it (TRAP-1).
Implementations§
Source§impl CreateImageRequest
impl CreateImageRequest
Sourcepub fn new(
name: impl Into<String>,
binary: Vec<u8>,
code_artifact_uri: impl Into<String>,
build_role_arn: impl Into<String>,
) -> Self
pub fn new( name: impl Into<String>, binary: Vec<u8>, code_artifact_uri: impl Into<String>, build_role_arn: impl Into<String>, ) -> Self
A request with the measured defaults: the al2023 base, the default size class, the derived Dockerfile, identity repair off, and 30-second hook timeouts.
The hook timeouts are expected rather than propagated because 30 is legal for both
families by construction — it is below the run family’s 60s ceiling, which is the
lower of the two — and a Result here would put a ? on every call site for a
value this function chose itself.