Supported environments
How the targets compare
Each row compares a capability of EC2 with its adaptation on each target. A dash means this profile does not state the capability for that target.Cloud Adapter
On Akamai and Private Kubernetes
KubeVirt VM
How it works
On AWS your workload runs on an EC2 instance. Tensor9 compiles the AWS Terraform into a KubeVirt VirtualMachine using a compatible target image containing the application software, running under KVM on the Kubernetes cluster you operate. Your process runs directly inside the VM. A Tensor9 metadata service runs inside the VM. It answers requests to169.254.169.254 for the instance ID, region, and IAM credentials your workload expects from EC2.
The workload runs on a KubeVirt VirtualMachine under KVM on the target cluster, with an in-guest metadata responder.
Machine Images
Tensor9 translates the VM size and image. Theinstance_type becomes the VM’s guest resources (its domain CPU and memory) read straight from the instance’s vCPU and RAM rather than mapped through a fixed shape table. The VM boots the resolved image directly as its disk, sized by that image, so an origin that sets its own root-volume size is caught at build rather than booted smaller than it asked for.
The image. A stock image is looked up: a data aws_ami lookup for a current Ubuntu LTS resolves to the equivalent Canonical Ubuntu containerDisk (a bootable cloud image with cloud-init) that the VM boots directly. A custom image is compiled into a bootable volume: your own built AMI is compiled into a bootable persistent volume by the Containerized Data Importer, so the VM boots a native disk built from your software. That path, like the VM primitive itself, needs the KubeVirt operator and the Data Importer installed on the cluster, so a compile that references a custom image is caught at build with a clear message when they are absent, rather than booting the wrong image.
- Stock image → Canonical containerDisk: a
data aws_amiUbuntu-LTS lookup resolves to a Canonical Ubuntu containerDisk (a bootable cloud image with cloud-init) booted directly. - instance_type → domain CPU and memory: the guest’s vCPU and RAM are read straight from the instance shape, not mapped through a fixed size table.
- The boot disk: it is created from the resolved image and sized by it; additional capacity and data disks require appropriately sized persistent volumes and guest mounts.
- Custom image → compiled by the Data Importer: a non-Canonical AMI is compiled into a bootable persistent volume containing your software; the KubeVirt operator and Data Importer must be installed, and a compile that needs them when absent is caught at build rather than booted wrong.
- Self-managed: the VM runs under KVM on the nodes you operate: you run the hypervisor and the cluster, not a cloud provider; your workload runs unchanged in the guest.
IMDSv2
The in-guest responder implements Instance Metadata Service v2 (IMDSv2), the token-protected mode AWS defaults to:PUT /latest/api/token returns a short-lived session token, which the client sends back in the X-aws-ec2-metadata-token header on each GET /latest/meta-data/…. Token-less IMDSv1 reads work too, unless the origin instance set http_tokens=required.
The AWS SDK and most bootstrap scripts read this metadata from the fixed link-local address 169.254.169.254. A KubeVirt guest boots a real cloud image with cloud-init and, unlike a cloud VM, has no native metadata service sitting on that address to coexist with. So the in-guest responder owns 169.254.169.254 outright: it answers there directly, read-only, never leaving the VM, with nothing to pass through. A field it can’t resolve truthfully returns an error, so a wrong value never reaches the workload.
the IMDSv2 handshake, unchanged, on the migrated KubeVirt VM
The metadata address is owned outright in the guest (there is no native metadata service to share it with), and an in-guest responder speaks IMDSv2 and returns an EC2-shaped identity.
Launch templates and Auto Scaling fleets
A launch template defines instance settings. An Auto Scaling group adds the member count, placement and scaling policy. The fleet mapping combines them into the target’s instance template and managed group. Review the Auto Scaling page for scaling-policy and orchestration limits. Launch templates. A launch template is a blueprint for an instance: the same fields anaws_instance sets (image, size, key, user-data, disks, IAM role), declared once for reuse. An instance that references one is read as a single effective configuration: the template supplies the base and the instance’s own inline arguments override it, field by field, exactly as AWS resolves them. That one effective machine is then translated the same way a standalone instance is, so a launch-template-defined VM gets the same image, guest resources, disks, network, identity, and in-guest metadata as any other.
Auto Scaling groups. An ASG is a fleet of identical instances behind one size-and-scaling policy, and KubeVirt’s native equivalent is a VirtualMachinePool. The launch template’s effective configuration becomes the pool’s embedded virtualMachineTemplate, and desired_capacity becomes the pool’s replicas, every replica a full VM with the same disks, network, identity, and read-only metadata API as a standalone instance, scheduled onto your nodes. The pool exposes a standard scale subresource, so min_size/max_size become the bounds of a horizontal autoscaler you point at it; without one, the pool holds a fixed replica count.
- Launch template → one effective machine: template base + the instance’s inline overrides resolve to a single configuration, translated like any standalone VM.
- ASG → VirtualMachinePool.
desired_capacity→ the pool’sreplicas; the blueprint becomes the pool’s embeddedvirtualMachineTemplate. - Scaling → a horizontal autoscaler on the scale subresource.
min_size/max_sizebecome the bounds of a HorizontalPodAutoscaler you point at the pool; without one it holds a fixed count. - Every replica is a full VM: each replica has the same identity and metadata as a single instance, scheduled onto your own nodes.
When the instance ID changes
An EC2 instance-id (i-…) is stable for the life of the instance and changes only when the instance is replaced. The responder reproduces that by deriving the instance-id from the VM’s own firmware UUID, the SMBIOS identifier the VM presents to its guest, set when the VM is created. While the VM exists the id is stable, including across reboots and across Tensor9 redeploys of the surrounding stack, and it is served consistently from first boot, not regenerated on a restart.
It changes when the VM is replaced. Tensor9 ties the VM’s firmware UUID to the AWS attributes it models as requiring replacement (image, subnet, key pair, availability zone, CPU options, placement), so replacing any of them replaces the VM and rotates the id. Target replacement rules can differ from EC2; review image, shape and network changes before applying them. In a pool, each replica gets its own firmware UUID, so every replica gets a distinct EC2-shaped id.
- Stable across reboots and redeploys: the id is derived from the VM’s persistent firmware UUID, and served consistently across a responder restart.
- Rotates on a modeled force-new change: a change to a modeled attribute (image, subnet, key pair, zone, CPU options, placement) replaces the VM and rotates the id.
- Distinct per replica: each VM in a pool has its own firmware UUID, so each is served its own EC2-shaped id.
- Never the raw UUID: the firmware UUID is hashed into an EC2-shaped
i-…; it is not served or logged verbatim.
Limitations
The compute path is native and the metadata handshake matches EC2. Review these metadata, storage and network differences: Known limits- This is self-managed, not a cloud service: you operate the Kubernetes cluster and the KVM nodes the VM runs on, so availability, live-migration, and rescheduling on node drain are the target cluster’s (not a cloud provider’s single-instance SLA), and performance tracks the node the VM lands on.
- The metadata API is read-only: it serves identity and metadata, not a control plane: there is no EC2 create or terminate against it; the VM is managed as a Kubernetes resource on the target cluster.
- The VM runs as the origin instance’s IAM role, mapped to a Kubernetes ServiceAccount: the origin’s declared IAM role becomes the ServiceAccount the VM runs as (its
serviceAccountName), so the origin’s declared identity is what the VM can actually do; a named role with no projected ServiceAccount on the cluster is caught at compile rather than the VM silently running as the namespace default. - The signed instance-identity document isn’t served: its signature can’t be reproduced, so it is withheld; the plaintext identity document is served, with a reconciled account id and region. Workloads that verify the IMDS signature won’t run.
- Local discovery. The configured EC2 adapter endpoint describes only the calling VM and its attached resources. It does not enumerate a managed account or fleet. The in-guest metadata endpoint remains a separate read-only service.
- No per-VM public IP: a KubeVirt VM is single-homed on the target cluster network with no cloud-assigned public address; a request for a per-instance public IP is caught at compile, and an Elastic IP is reproduced as a LoadBalancer Service that fronts the VM rather than an address on the VM itself.
- Security groups map to target network controls. Use a default-deny Kubernetes NetworkPolicy with explicit allows for the VM’s translated rules. Preserve default-deny ingress and the declared egress permissions; do not rely on the cluster’s default pod-to-pod reachability. Review target rule scope, protocol support and address ranges when validating connectivity.
- Persistent storage needs explicit sizing. An image-backed boot disk and a persistent boot volume have different capacity and recovery behavior. Provision the required PersistentVolumes and guest mounts for root expansion or attached data disks; importing an image does not copy unrelated EBS volume contents.
- Launch templates and Auto Scaling groups use the fleet mapping. A launch template or launch configuration defines each member, and the group maps to a VirtualMachinePool. Review the Auto Scaling page for the target’s scaling, health-check and rolling-update limits; support for individual instances does not establish every fleet policy.
- Disk performance belongs to the target cluster, not the VM: a volume’s independent
iops/throughputsettings have no equivalent knob here (your StorageClass and CSI driver own disk performance), so an instance that sets either is caught at build rather than having the values silently ignored. - The KubeVirt operator and the Data Importer must be installed on the cluster: the VM primitive and the custom-image rebuild path depend on them; a compile that needs either is caught at build when they are absent, rather than emitting a manifest the cluster can’t run.
Other considerations
Plan for the following operating requirements.- Native execution: the workload runs directly in the KubeVirt VM’s guest; Tensor9 operates the separate in-guest metadata service.
- You operate the machine: unlike the cloud arms, the VM runs under KVM on the Kubernetes cluster and nodes you run, so availability, live-migration, and rescheduling on node drain are the target cluster’s, not a cloud provider’s.
- Tensor9 operates the read-only metadata API: the in-guest responder owns 169.254.169.254 outright and serves EC2 identity and IAM credentials, but accepts no create or terminate against the VM.
- Guest size is read directly, and performance tracks the node: the instance’s vCPU and RAM become the VM’s domain resources rather than a mapped shape, so performance tracks the node the VM is scheduled onto, not the specific EC2 instance.
- The instance-id follows the VM’s lifecycle: it is derived from the VM’s firmware UUID, remains stable while the VM exists, and changes when the VM is replaced. Review target replacement rules before changing size or image.
Infrastructure and local discovery
KubeVirt maps VM infrastructure and local metadata on the existing cluster, not managed lifecycle through the EC2 runtime API. Local DescribeInstances, VPC, subnet and security-group responses describe the calling VM and agree with its metadata. They do not provide managed fleet enumeration. Use the native cluster and infrastructure configuration to manage the VM.On Azure
Virtual Machines
How it works
On AWS your workload runs on an EC2 instance. Tensor9 compiles the AWS Terraform into an Azure Linux Virtual Machine using a compatible target image containing the application software. Your process runs directly on the VM. A Tensor9 metadata service runs inside the VM. It answers requests to169.254.169.254 for the instance ID, region, and IAM credentials your workload expects from EC2.
The workload runs on a native Azure Linux VM, with an in-guest metadata responder.
Machine Images
Tensor9 translates the VM size and image. Theinstance_type maps to the nearest Azure VM size in the same hardware family (general purpose → D-series, compute → F, memory → E, burstable → B), and the root EBS volume becomes an Azure managed disk.
The image. A stock image is looked up: a data aws_ami lookup for a current Ubuntu LTS resolves to the equivalent Canonical image in the Azure Marketplace (the Canonical publisher’s source_image_reference), kept at the resolved version so a change to “latest” does not trigger a rebuild. A custom image is compiled into the target image format: your own built AMI becomes a native Azure managed image containing your software, so both paths boot a native Azure image. An input with no faithful target (an Arm origin with no matching image, or an image that can’t be built) is caught at build rather than booted as the wrong machine.
- Stock image → Azure Marketplace: a
data aws_amiUbuntu-LTS lookup resolves to the matching Canonical Marketplace image, kept at the resolved version. - instance_type → VM size: general →
D, compute →F, memory →E, burstable →B, GPU →N-series, Arm →Dpds/Epsv. - The OS disk: it boots the resolved image, keeping its size and type; attached data volumes require target disks, guest mounts and a separate data transfer.
- Custom image → compiled Azure image: a non-Canonical AMI is compiled into a native Azure managed image built from your software; both stock and custom images use the target cloud’s format.
- Cloud-managed. Azure operates the hypervisor, host, and availability; your workload runs unchanged in the guest.
IMDSv2
The in-guest responder implements Instance Metadata Service v2 (IMDSv2), the token-protected mode AWS defaults to:PUT /latest/api/token returns a short-lived session token, which the client sends back in the X-aws-ec2-metadata-token header on each GET /latest/meta-data/…. Token-less IMDSv1 reads work too, unless the origin instance set http_tokens=required.
An Azure VM already answers on 169.254.169.254: that is Azure’s own Instance Metadata Service. Tensor9 does not take it over: the EC2 metadata paths (/latest/…) are answered in the guest by the EC2-shaped responder, while Azure’s own metadata paths (/metadata/…) are passed straight through to Azure untouched, so managed-identity and platform tooling that read Azure’s metadata keep working. A field the responder can’t resolve truthfully returns an error, so unresolved fields fail rather than returning a fabricated identity.
the IMDSv2 handshake, unchanged, on the migrated Azure VM
The link-local metadata address is shared by path: the EC2 metadata path gets an EC2-shaped answer in the guest; Azure’s own metadata path is passed straight through, untouched.
Launch templates and Auto Scaling fleets
A launch template defines instance settings. An Auto Scaling group adds the member count, placement and scaling policy. The fleet mapping combines them into the target’s instance template and managed group. Review the Auto Scaling page for scaling-policy and orchestration limits. Launch templates. A launch template is a blueprint for an instance: the same fields anaws_instance sets (image, size, key, user-data, disks, IAM role), declared once for reuse. An instance that references one is read as a single effective configuration: the template supplies the base and the instance’s own inline arguments override it, field by field, exactly as AWS resolves them. That one effective machine is then translated the same way a standalone instance is, so a launch-template-defined VM gets the same image, size, disks, network, identity, and in-guest metadata as any other.
Auto Scaling groups. An ASG is a fleet of identical instances behind one size-and-scaling policy, and Azure’s native equivalent is a Virtual Machine Scale Set. desired_capacity becomes the scale set’s desired size; running and ready capacity depend on allocation, startup and health checks. min_size/max_size become desired-capacity autoscale bounds. On Azure the scale set declares its machine blueprint inline (there is no separate template resource), so the launch template’s effective configuration becomes the scale set’s VM profile, and every replica is a full VM with the same disks, network, identity, and read-only metadata API as a standalone instance.
- Launch template → one effective machine: template base + the instance’s inline overrides resolve to a single configuration, translated like any standalone VM.
- ASG → Virtual Machine Scale Set.
desired_capacity→ desired size, with readiness following allocation and health;min_size/max_size→ autoscale bounds. - Every replica is a full VM: the blueprint becomes the scale set’s inline VM profile, so each replica gets the same identity and metadata as a single instance.
When the instance ID changes
An EC2 instance-id (i-…) is stable for the life of the instance and changes only when the instance is replaced. The responder reproduces that by deriving the instance-id from the Azure VM’s own vmId. While the VM exists the id is stable, including across reboots and across Tensor9 redeploys of the surrounding stack, and it is served consistently from first boot, not regenerated on a restart.
It changes when the VM is replaced. Tensor9 ties the VM’s replacement to the AWS attributes it models as requiring replacement (image, subnet, key pair, availability zone, CPU options, placement), so replacing any of them replaces the VM and rotates the id. Target replacement rules can differ from EC2; review image, shape and network changes before applying them.
- Stable across reboots and redeploys: the id is derived from the persistent Azure
vmId, and served consistently across a responder restart. - Rotates on a modeled force-new change: a change to a modeled attribute (image, subnet, key pair, zone, CPU options, placement) replaces the VM and rotates the id.
- Never the raw VM id: the Azure
vmIdis hashed into an EC2-shapedi-…; it is not served or logged verbatim.
Limitations
The compute path is native and the metadata handshake matches EC2. Review these metadata, storage and network differences: Known limits- The metadata API is read-only: it serves identity and metadata, not a control plane: there is no EC2 create or terminate against it; the VM is managed as an Azure resource.
- The signed instance-identity document isn’t served: its signature can’t be reproduced, so it is withheld; the plaintext identity document is served, with a reconciled account id and region. Workloads that verify the IMDS signature won’t run.
- Discovery uses the configured EC2 adapter endpoint. Describe operations return supported instances and related resources in the managed account, including the VM. Filters and pagination follow the supported API scope. The metadata endpoint inside the guest remains a separate service; unrelated real cloud accounts are outside this discovery scope.
- Security groups map to target network controls. Use the Azure network security group for the VM’s translated rules. Preserve default-deny ingress and the declared egress permissions; do not rely on Azure’s default intra-network allow. Review target rule scope, protocol support and address ranges when validating connectivity.
- A per-instance public IP is caught at build: an instance that requests one (
associate_public_ip_address) is refused because this target does not create a per-instance public IP. - Explicit disk-performance settings fail during the build: an instance that sets
iopsorthroughputindependently (AWSgp3/io1/io2) asks for something an Azure managed OS disk cannot honor (independent IOPS needs a different disk type entirely), so the build stops rather than quietly giving the disk a different performance profile than the one you declared. - Disks use the target storage service. The root volume uses an Azure managed disk; attached data volumes need corresponding target disks and guest mounts. Match size, performance class, encryption and attachment limits to the workload. Provisioning a disk does not copy the data from an existing EBS volume.
- Launch templates and Auto Scaling groups use the fleet mapping. A launch template or launch configuration defines each member, and the group maps to a Virtual Machine Scale Set. Review the Auto Scaling page for the target’s scaling, health-check and rolling-update limits; support for individual instances does not establish every fleet policy.
- The VM runs as the origin instance’s IAM role, mapped to an Azure managed identity: the origin’s declared IAM intent is what the VM can actually do; a role with no literal name (a
name_prefixor a pre-existing external profile that can’t be resolved) is caught at compile rather than binding a wrong or default identity. - The VM size is the nearest Azure analog, not identical hardware: performance tracks the Azure size rather than the specific EC2 instance. The performance tab has the published comparison.
- Burstable and Spot instances have limitations on Azure: a burstable T-instance maps to a B-series size; the AWS unlimited-burst mode has no B-series equivalent and is caught rather than silently throttled. Spot maps to an Azure Spot VM (stop → deallocate, terminate → delete); a hibernate-on-interruption policy is caught at compile.
Other considerations
Plan for the following operating requirements.- Native execution: the workload runs directly on the Azure Linux VM; Tensor9 operates the separate in-guest metadata service.
- Azure operates the machine: the hypervisor, host, and hardware availability are Azure’s to run, as AWS does for EC2.
- Tensor9 operates the read-only metadata API: the in-guest responder serves EC2 identity and IAM credentials but accepts no create or terminate against the VM, and Azure’s own instance metadata on the same address is passed through untouched.
- The VM size is the nearest analog, not identical hardware: the workload lands on the closest Azure size in its family (D/F/E/B), so plan for performance that tracks that size rather than the specific EC2 instance.
- The instance-id follows the VM’s lifecycle: it is stable across reboots and redeploys while the VM exists, and changes when the VM is replaced. Review target replacement rules before changing size or image.
Runtime management on Azure
The EC2 lifecycle and metadata model also applies to Azure VMs. Supported runtime requests reconcile onto Azure resources; acceptance precedes readiness. The Azure metadata endpoint remains separate from managed-account discovery. The operation rows above bound supported launch and attribute changes.On DigitalOcean
Droplet
How it works
On AWS your workload runs on an EC2 instance. Tensor9 compiles the AWS Terraform into a DigitalOcean Droplet using a compatible target image containing the application software. Your process runs directly on the Droplet. A Tensor9 metadata service runs inside the VM. It answers requests to169.254.169.254 for the instance ID, region, and IAM credentials your workload expects from EC2.
The workload runs on a native DigitalOcean Droplet, with an in-guest metadata responder.
Machine Images
Tensor9 translates the VM size and image. Theinstance_type maps to the nearest DigitalOcean Droplet size slug in the same hardware family (general purpose → g, compute → c, memory → m, basic/burstable → s), and the Droplet’s disk comes bundled with that size, so an origin that sets its own root-volume size is caught at build rather than silently under-provisioned.
The disk comes with the slug. A Droplet’s disk is not an independent resource; its size and type are fixed by the size slug you land on, so root_block_device sizing, iops, and throughput aren’t set separately. A disk larger than the slug provides is caught at build rather than silently under-provisioned; Choose storage capacity through the Droplet size.
The image. A stock image is looked up: a data aws_ami lookup for a current Ubuntu LTS resolves to the equivalent Canonical Ubuntu image on DigitalOcean (a DigitalOcean image slug such as ubuntu-22-04-x64), set directly on the Droplet and kept at the resolved version so a change to “latest” does not trigger a rebuild. A custom image is compiled into the target image format: your own built AMI becomes a native DigitalOcean image containing your software, so both paths boot a native image. An input with no faithful target (a shape without a matching DigitalOcean size and compatible image, or an image that can’t be built) is caught at build rather than booted as the wrong machine.
- Stock image → Canonical Ubuntu on DigitalOcean: a
data aws_amiUbuntu-LTS lookup resolves to the matching DigitalOcean image slug (e.g.ubuntu-22-04-x64), kept at the resolved version. - instance_type → Droplet size slug: general →
g, compute →c, memory →m, basic/burstable →s; choose a size and image with the required architecture; GPU capacity depends on the selected GPU offering and region. - The Droplet size sets the disk capacity: a Droplet’s root disk size and type are set by the size slug, not independently; attached data volumes use separately provisioned volumes and guest mounts.
- Custom image → compiled DigitalOcean image: a non-Canonical AMI is compiled into a native DigitalOcean image with your bits; both stock and custom images use the target cloud’s format.
- Cloud-managed. DigitalOcean operates the hypervisor, host, and availability; your workload runs unchanged in the guest.
IMDSv2
The in-guest responder implements Instance Metadata Service v2 (IMDSv2), the token-protected mode AWS defaults to:PUT /latest/api/token returns a short-lived session token, which the client sends back in the X-aws-ec2-metadata-token header on each GET /latest/meta-data/…. Token-less IMDSv1 reads work too, unless the origin instance set http_tokens=required.
The DigitalOcean wrinkle. A Droplet already answers on 169.254.169.254, and unlike other clouds, DigitalOcean’s own metadata also answers the EC2-style /latest path, so the two surfaces overlap. Tensor9 does not let that ambiguity reach the workload: the in-guest EC2 responder owns the /latest surface on 169.254.169.254, so a read always gets the EC2-shaped answer, never DigitalOcean’s overlapping one.
The id is anchored to the right source. To keep the identity truthful, the responder reads the Droplet’s real id from DigitalOcean’s own canonical path, /metadata/v1/id, never the overlapping /latest path (which on DigitalOcean is DigitalOcean’s own answer). The surface then self-checks: it compares the answer coming back on 169.254.169.254 against its own ground truth, so if the in-guest redirect is ever disrupted, the mismatch is caught and the in-guest responder is restored periodically. Test recovery after guest network changes; a repair interval does not guarantee uninterrupted metadata routing.
the IMDSv2 handshake, unchanged, on the migrated DigitalOcean Droplet
The link-local address is owned in-guest by the EC2 responder; the instance-id is derived from the Droplet’s ID, read from DigitalOcean’s own canonical path, never the overlapping /latest.
Launch templates and Auto Scaling fleets
Two EC2 shapes define how a machine is built rather than a single machine: a launch template and an Auto Scaling group. They are handled differently. Launch templates translate. A launch template is a blueprint for an instance: the same fields anaws_instance sets (image, size, key, user-data, disks, IAM role), declared once for reuse. An instance that references one is read as a single effective configuration: the template supplies the base and the instance’s own inline arguments override it, field by field, exactly as AWS resolves them. That one effective machine is then translated the same way a standalone instance is, so a launch-template-defined Droplet gets the same image, size, disks, network, identity, and in-guest metadata as any other.
Auto Scaling groups map to a Droplet autoscale pool. The digitalocean_droplet_autoscale resource supplies the fleet. Each member needs the image, network rules and metadata configuration described for a standalone Droplet. DigitalOcean’s public addressing makes firewall attachment part of the fleet configuration; adding replicas must retain those rules. Review the Auto Scaling page for supported scaling policies and fleet orchestration limits.
- Launch template → one effective machine: template base + the instance’s inline overrides resolve to a single configuration, translated like any standalone Droplet.
- Auto Scaling group → Droplet autoscale pool. The group defines the member count and scaling bounds; each member uses the translated launch configuration.
- Scaling must preserve network and identity settings: a fleet mapping has to give every replica the same default-deny firewall, identity, and metadata surface as a single Droplet, so scaling never widens exposure.
When the instance ID changes
An EC2 instance-id (i-…) is stable for the life of the instance and changes only when the instance is replaced. The responder reproduces that by deriving the instance-id from the Droplet’s own id, the same id it reads from DigitalOcean’s canonical /metadata/v1/id. While the Droplet exists the id is stable, including across reboots and across Tensor9 redeploys of the surrounding stack, and the first-served id is remembered, so a responder restart keeps serving the same one rather than regenerating it.
It changes when the Droplet is replaced. Tensor9 ties the Droplet’s replacement to the AWS attributes it models as requiring replacement (image, size, key pair, region, VPC), so replacing any of them replaces the Droplet and rotates the id. Target replacement rules can differ from EC2, including size changes that replace the Droplet.
- Stable across reboots and redeploys: the id is derived from the persistent DigitalOcean Droplet id, and the first-served id is remembered across a responder restart.
- Rotates on a modeled force-new change: a change to a modeled attribute (image, size, key pair, region, VPC) replaces the Droplet and rotates the id.
- Never the raw Droplet id: the DigitalOcean Droplet id is hashed into an EC2-shaped
i-…; it is not served or logged verbatim.
Limitations
The compute path is native and the metadata handshake matches EC2. Review these metadata, storage and network differences: Known limits- The metadata API is read-only: it serves identity and metadata, not a control plane: there is no EC2 create or terminate against it; the Droplet is managed as a DigitalOcean resource.
- The signed instance-identity document isn’t served: its signature can’t be reproduced, so it is withheld; the plaintext identity document is served, with a reconciled account id and region. Workloads that verify the IMDS signature won’t run.
- Discovery uses the configured EC2 adapter endpoint. Describe operations return supported instances and related resources in the managed account, including the Droplet. Filters and pagination follow the supported API scope. The metadata endpoint inside the guest remains a separate service; unrelated real cloud accounts are outside this discovery scope.
- A Droplet is always publicly addressed, so its confidentiality comes from a default-deny firewall: an AWS security group denies inbound by default and permits egress, and a Droplet has no way to suppress its public IPv4, so a private instance compiles to a Droplet behind a DigitalOcean firewall that denies all inbound, permits egress, and is created before the Droplet exists. Creating the firewall first prevents the machine from starting with unrestricted inbound access. A private instance that cannot be paired with its firewall is caught at build rather than compiled, because widening a VPC-internal machine to the internet is never done silently.
- There is no DigitalOcean-native identity binding: the origin instance’s IAM role credentials are served in-guest by the metadata API, so the workload’s AWS SDK keeps working, but DigitalOcean has no per-instance workload identity to bind, and none is needed, since the workload believes it is on EC2. A role with no literal name (a
name_prefixor an unresolvable external profile) is caught at compile rather than serving credentials with no role. - The root disk is bundled with the size slug. Select a Droplet size with enough root capacity; EBS root type, IOPS and throughput settings do not have independent equivalents. Use separate target volumes for additional data storage and transfer existing volume contents before cutover.
- The Droplet size is the nearest DigitalOcean analog, not identical hardware: performance tracks the DigitalOcean size rather than the specific EC2 instance; choose a supported size, architecture and image combination; GPU availability depends on the selected offering and region. The performance tab has the published comparison.
- Security-group rules use DigitalOcean firewalls. Preserve default-deny ingress and the intended egress rules. Review protocol and address-range restrictions before allowing traffic to a Droplet’s public interface.
- Public addressing differs from EC2. The selected Droplet has a native public address protected by its firewall. That does not reproduce every EC2 associate_public_ip_address choice or Elastic IP attachment behavior.
- Launch templates and Auto Scaling groups use the fleet mapping. A launch template or launch configuration defines each member, and the group maps to a DigitalOcean autoscale pool. Review the Auto Scaling page for the target’s scaling, health-check and rolling-update limits; support for individual instances does not establish every fleet policy.
Other considerations
Plan for the following operating requirements.- Nothing sits in the compute path: the workload runs directly on the Droplet, so there is no proxy or adapter to operate, size, or keep alive alongside the process.
- DigitalOcean operates the machine: the hypervisor, host, and hardware availability are DigitalOcean’s to run, as AWS does for EC2.
- Tensor9 operates the read-only metadata API: the in-guest responder owns the
/latestsurface on 169.254.169.254 and serves EC2 identity and IAM credentials, but accepts no create or terminate against the Droplet. - The Droplet size is the nearest analog, not identical hardware: the workload lands on the closest DigitalOcean size slug (x86 only), so plan for performance that tracks that slug rather than the specific EC2 instance.
- The instance-id follows the Droplet’s lifecycle: it is stable across reboots and redeploys and rotates only when a modeled force-new attribute replaces the Droplet, so replacement changes the reported identity. Review target replacement rules before changing size or image.
Runtime lifecycle and instance metadata
Maximum adaptation separates the EC2 management API from the metadata endpoint inside each VM. Supported lifecycle requests record the requested instance state; a reconciler creates or changes the target VM and its associated resources. A successful request can return a pending state while the target is still creating the machine. Use the describe operations to check readiness. RunInstances, termination and tagging operate on resources managed by this adapter-managed account. Attribute updates and launch shapes remain bounded by the supported request and target settings. Describe requests can list managed instances; they do not grant access to unrelated cloud accounts. The in-guest metadata service supplies the workload’s identity and credentials independently of those lifecycle operations. Metadata and management responses must refer to the same managed instance.On Google Cloud
Compute Engine
How it works
On AWS your workload runs on an EC2 instance. Tensor9 compiles the AWS Terraform into a Compute Engine VM using a compatible target image containing the application software. Your process runs directly on the VM. A Tensor9 metadata service runs inside the VM. It answers requests to169.254.169.254 for the instance ID, region, and IAM credentials your workload expects from EC2.
The workload runs on a native Compute Engine VM, with an in-guest metadata responder.
Machine Images
Tensor9 translates the image and VM size. A stock image is looked up: adata aws_ami lookup for a current Ubuntu LTS resolves to the equivalent Compute Engine image family (Ubuntu 22.04 on x86 → ubuntu-os-cloud/ubuntu-2204-lts), kept at the resolved version so a change to “latest” does not trigger a rebuild. A custom image is compiled into the target image format: your own built AMI becomes a native Compute Engine image containing your software, so both paths land a native image. The instance_type maps to the nearest Compute Engine machine type in the same hardware class, and the root EBS volume becomes a persistent disk. An input with no faithful target (an Arm origin where no matching image family exists, or an image that can’t be built) is caught at build rather than booted as the wrong machine.
- AMI → Compute Engine image: a
data aws_amistock lookup resolves to the equivalent image family at a fixed version; a custom AMI is compiled into a native Compute Engine image built from your software. Both produce an image for the target cloud. - instance_type → machine_type: general →
n2 / n4, compute →c2 / c3, memory →m3, storage →z3, GPU →a3 / a2 / g2. The Arm class has its analog inc4a(Axion), gated today on Arm image-family coverage, so an Arm origin is caught at build rather than landed on an x86 host. - The root disk: it boots the translated image, keeping its size and type; attached data volumes require target disks, guest mounts and a separate data transfer.
- Cloud-managed. Google operates the hypervisor, host, and availability; your workload runs unchanged in the guest.
IMDSv2
The responder implements Instance Metadata Service v2 (IMDSv2), the token-protected mode AWS defaults to:PUT /latest/api/token returns a short-lived session token, which the client sends back in the X-aws-ec2-metadata-token header on each GET /latest/meta-data/…. Token-less IMDSv1 reads work too, unless the origin instance set http_tokens=required.
The AWS SDK and most bootstrap scripts read this metadata from the fixed link-local address 169.254.169.254. Compute Engine uses that address for its own metadata API. The adapter serves the AWS metadata paths in the guest: the address is redirected to a loopback responder that returns an EC2-shaped identity, read-only, and never leaving the VM. A field it can’t resolve truthfully returns an error, so unresolved fields fail rather than returning a fabricated identity.
Native Google metadata uses /computeMetadata/v1/ paths and the required Metadata-Flavor: Google request header. The responder forwards those native requests to Compute Engine metadata, preserving the path, query and header; it returns the provider’s response. Only the AWS /latest/ paths use the EC2 responder and its IMDSv2 token handshake. The shared link-local address therefore does not turn a native Google metadata request into an AWS request.
the IMDSv2 handshake, unchanged, on the migrated GCE VM
The link-local metadata address is redirected to an in-guest responder that speaks IMDSv2 and returns an EC2-shaped identity.
Launch templates and Auto Scaling fleets
A launch template defines instance settings. An Auto Scaling group adds the member count, placement and scaling policy. The fleet mapping combines them into the target’s instance template and managed group. Review the Auto Scaling page for scaling-policy and orchestration limits. Launch templates. A launch template is a blueprint for an instance: the same fields anaws_instance sets (image, machine type, key, user-data, disks, IAM role), declared once for reuse. An instance that references one is read as a single effective configuration: the template supplies the base and the instance’s own inline arguments override it, field by field, exactly as AWS resolves them. That one effective machine is translated the same way a standalone instance is, so a launch-template-defined VM gets the same image, machine type, disks, network, identity, and in-guest metadata as any other.
Auto Scaling groups. An ASG is a fleet of identical instances behind one size-and-scaling policy, and Google’s native equivalent is a regional managed instance group driven by a google_compute_instance_template. desired_capacity becomes the group’s target size and min_size/max_size become the regional autoscaler’s bounds. The launch template’s effective configuration becomes the instance template every member boots from, so each replica is a full VM with the same disks, network, identity, and read-only metadata API as a standalone instance, spread across the region’s zones.
- Launch template → one effective machine: template base + the instance’s inline overrides resolve to a single configuration, translated like any standalone VM.
- ASG → regional managed instance group.
desired_capacity→ target size;min_size/max_size→ the regional autoscaler’s bounds. - Every replica is a full VM: the blueprint becomes the
google_compute_instance_templateeach member boots from, giving each member the same identity and metadata as a single instance.
When the instance ID changes
An EC2 instance-id (i-…) is stable for the life of the instance and changes only when the instance is replaced. The responder reproduces that by deriving the instance-id from the GCE VM’s own Google-assigned id (hashed together with the install id). While the VM exists the id is stable, including across reboots and across Tensor9 redeploys of the surrounding stack.
It changes when the VM is replaced. Tensor9 ties the VM’s replacement to the AWS attributes it models as requiring replacement (AMI, subnet, key pair, availability zone, CPU options, placement), so replacing any of them replaces the VM and rotates the id. Target replacement rules can differ from EC2; review image, shape and network changes before applying them.
- Stable across reboots and redeploys: the id is derived from the persistent GCE VM id, not from boot state.
- Rotates on a modeled force-new change: a change to a modeled attribute (AMI, subnet, key pair, AZ, CPU options, placement) replaces the VM and rotates the id.
- Never the raw VM id: the Google id is hashed into an EC2-shaped
i-…; it is not served or logged verbatim.
Limitations
The compute path is native and the metadata handshake matches EC2. Review these metadata, storage and network differences: Known limits- The metadata API is read-only: it serves identity and metadata, not a control plane: there is no EC2 create or terminate against it; the VM is managed as a Compute Engine resource.
- The signed instance-identity document isn’t served: its signature can’t be reproduced, so it is withheld; the plaintext identity document is served, with a reconciled account id and region. Workloads that verify the IMDS signature won’t run.
- Discovery uses the configured EC2 adapter endpoint. Describe operations return supported instances and related resources in the managed account, including the instance. Filters and pagination follow the supported API scope. The metadata endpoint inside the guest remains a separate service; unrelated real cloud accounts are outside this discovery scope.
- The IAM credentials from the metadata service are Tensor9-scoped placeholders. AWS calls still succeed (they travel the Tensor9 egress path, which substitutes the real caller credential), but the placeholder credentials don’t work against an AWS endpoint reached directly.
- The VM runs as the origin instance’s IAM role: that role is mapped to a Google service account and the VM runs as it (not GCP’s default Compute Engine service account), so the origin’s declared IAM intent is what the VM can actually do. A role with no literal name (a
name_prefixor computed name) can’t be resolved, so it is caught at compile. - The machine type is the nearest Compute Engine analog, not identical hardware: performance tracks Compute Engine rather than the specific EC2 instance, close on most shapes, with older Intel generations trailing on single-core. The performance tab has the published comparison.
- Security groups map to target network controls. Use the Compute Engine firewall rules for the VM’s translated rules. Preserve default-deny ingress and the declared egress permissions; do not rely on the network’s default reachability. Review target rule scope, protocol support and address ranges when validating connectivity.
- A per-instance public IP is caught at build: an instance that requests one (
associate_public_ip_address) is refused because this target does not create a per-instance public IP. - Explicit disk-performance settings fail during the build: an instance that sets
iopsorthroughputindependently (AWSgp3/io1/io2) asks for something a Compute Enginepd-*boot disk cannot honor independently, so the build stops rather than quietly giving the disk a different performance profile than the one you declared. - Disks use the target storage service. The root volume uses a Compute Engine persistent disk; attached data volumes need corresponding target disks and guest mounts. Match size, performance class, encryption and attachment limits to the workload. Provisioning a disk does not copy the data from an existing EBS volume.
- Launch templates and Auto Scaling groups use the fleet mapping. A launch template or launch configuration defines each member, and the group maps to a regional managed instance group. Review the Auto Scaling page for the target’s scaling, health-check and rolling-update limits; support for individual instances does not establish every fleet policy.
Other considerations
Plan for the following operating requirements.- Native execution: the workload runs directly on the Compute Engine VM; Tensor9 operates the separate in-guest metadata service.
- Google operates the machine: the hypervisor, host, and hardware availability are Google’s to run, as AWS does for EC2.
- Tensor9 operates the read-only metadata API: the in-guest responder answers EC2 identity and IAM credentials on 169.254.169.254, read-only, and accepts no create or terminate against the VM.
- The machine type is the nearest analog, not identical hardware: the workload lands on the closest Compute Engine machine type in its class, so plan for performance that tracks that type rather than the specific EC2 instance.
- The instance-id follows the VM’s lifecycle: it is stable across reboots and redeploys while the VM exists, and changes when the VM is replaced. Review target replacement rules before changing size or image.
Runtime lifecycle and instance metadata
Maximum adaptation separates the EC2 management API from the metadata endpoint inside each VM. Supported lifecycle requests record the requested instance state; a reconciler creates or changes the target VM and its associated resources. A successful request can return a pending state while the target is still creating the machine. Use the describe operations to check readiness. RunInstances, termination and tagging operate on resources managed by this adapter-managed account. Attribute updates and launch shapes remain bounded by the supported request and target settings. Describe requests can list managed instances; they do not grant access to unrelated cloud accounts. The in-guest metadata service supplies the workload’s identity and credentials independently of those lifecycle operations. Metadata and management responses must refer to the same managed instance.On OCI
Compute Instance
How it works
On AWS your workload runs on an EC2 instance. Tensor9 compiles the AWS Terraform into an OCI Compute instance (oci_core_instance) using a compatible target image containing the application software. Your process runs directly on the instance.
A Tensor9 metadata service runs inside the VM. It answers requests to 169.254.169.254 for the instance ID, region, and IAM credentials your workload expects from EC2.
The workload runs on a native OCI Compute instance, with an in-guest metadata responder.
Machine Images
Tensor9 translates the VM size and image. Theinstance_type maps to the nearest OCI shape, a VM.Standard flexible shape, where the origin’s vCPU count sets the shape’s OCPUs and its memory sizing; the root EBS volume becomes an OCI boot volume.
The image. A stock image is looked up: a data aws_ami lookup for a current Ubuntu LTS resolves to the equivalent Canonical Ubuntu image through a data oci_core_images find-latest lookup, kept at the resolved version so a change to “latest” does not trigger a rebuild. A custom image is compiled into the target image format: your own built AMI becomes a native OCI custom image containing your software, so both paths boot a native OCI image. An input with no faithful target (an Arm origin with no matching image, or an image that can’t be built) is caught at build rather than booted as the wrong machine.
- Stock image → Canonical Ubuntu: a
data aws_amiUbuntu-LTS lookup resolves throughdata oci_core_imagesto the matching Canonical image (x86 today; an Arm origin is caught at build rather than booted on the wrong architecture). - instance_type → OCI shape: mapped to the nearest
VM.Standardflexible shape; the vCPU count sets the shape’s OCPUs, andcpu_options.core_countmaps onto the shape’s OCPU config. - The boot volume: it runs the resolved image, keeping its size and type; attached data volumes use separately provisioned volumes and guest mounts.
- Custom image → compiled OCI image: a non-Canonical AMI is compiled into a native OCI custom image that contains your software; both stock and custom images use the target cloud’s format.
- Cloud-managed. OCI operates the hypervisor, host, and availability domain; your workload runs unchanged in the guest.
IMDSv2
The in-guest responder implements Instance Metadata Service v2 (IMDSv2), the token-protected mode AWS defaults to:PUT /latest/api/token returns a short-lived session token, which the client sends back in the X-aws-ec2-metadata-token header on each GET /latest/meta-data/…. Token-less IMDSv1 reads work too, unless the origin instance set http_tokens=required.
An OCI Compute instance already answers on 169.254.169.254: that is OCI’s own Instance Metadata Service, which serves under /opc/… paths. Tensor9 does not take it over: the EC2 metadata paths (/latest/…) are answered in the guest by the EC2-shaped responder, while OCI’s own metadata paths (/opc/…) are passed straight through to OCI untouched, so OCI instance-principal and platform tooling that read /opc keep working. A field the responder can’t resolve truthfully returns an error, so unresolved fields fail rather than returning a fabricated identity.
the IMDSv2 handshake, unchanged, on the migrated OCI Compute instance
The link-local metadata address is shared by path: the EC2 metadata path gets an EC2-shaped answer in the guest; OCI’s own /opc metadata path is passed straight through, untouched.
Launch templates and Auto Scaling fleets
A launch template defines instance settings. An Auto Scaling group adds the member count, placement and scaling policy. The fleet mapping combines them into the target’s instance template and managed group. Review the Auto Scaling page for scaling-policy and orchestration limits. Launch templates. A launch template is a blueprint for an instance: the same fields anaws_instance sets (image, size, key, user-data, disks, IAM role), declared once for reuse. An instance that references one is read as a single effective configuration: the template supplies the base and the instance’s own inline arguments override it, field by field, exactly as AWS resolves them. That one effective machine is then translated the same way a standalone instance is, so a launch-template-defined instance gets the same image, shape, disks, network, identity, and in-guest metadata as any other.
Auto Scaling groups. An ASG is a fleet of identical instances behind one size-and-scaling policy, and OCI’s native equivalent is an instance pool. Unlike Azure’s inline scale set, OCI keeps the machine blueprint in a separate oci_core_instance_configuration resource, which the pool references; desired_capacity becomes the pool’s desired size. Running and ready capacity depend on allocation, startup and health checks. min_size/max_size become its desired-capacity autoscale bounds. The launch template’s effective configuration becomes that configuration’s launch details, so every replica is a full instance with the same disks, network, scoped identity, and read-only metadata API as a standalone instance.
- Launch template → one effective machine: template base + the instance’s inline overrides resolve to a single configuration, translated like any standalone instance.
- ASG → instance pool + instance configuration.
desired_capacity→ desired size, with readiness following allocation and health;min_size/max_size→ autoscale bounds; the blueprint lives in a separateoci_core_instance_configuration, not inline. - Every replica is a full instance: the blueprint becomes the configuration’s launch details, so each pool member has the same scoped identity and metadata as a single instance.
When the instance ID changes
An EC2 instance-id (i-…) is stable for the life of the instance and changes only when the instance is replaced. The responder reproduces that by deriving the instance-id from the OCI instance’s own OCID. While the instance exists the id is stable, including across reboots and across Tensor9 redeploys of the surrounding stack, and it is served consistently from first boot, not regenerated on a restart.
It changes when the instance is replaced. Tensor9 ties the instance’s replacement to the AWS attributes it models as requiring replacement (image, subnet, SSH key pair, availability domain, CPU options, placement), so replacing any of them replaces the instance and rotates the id. Target replacement rules can differ from EC2.
- Stable across reboots and redeploys: the id is derived from the persistent OCI instance
OCID, and served consistently across a responder restart. - Rotates on a modeled force-new change: a change to a modeled attribute (image, subnet, SSH key, availability domain, CPU options, placement) replaces the instance and rotates the id.
- Never the raw OCID: the OCI
OCIDis hashed into an EC2-shapedi-…; it is not served or logged verbatim.
Limitations
The compute path is native and the metadata handshake matches EC2. Review these metadata, storage and network differences: Known limits- The metadata API is read-only: it serves identity and metadata, not a control plane: there is no EC2 create or terminate against it; the instance is managed as an OCI resource.
- The signed instance-identity document isn’t served: its signature can’t be reproduced, so it is withheld; the plaintext identity document is served, with a reconciled account id and region. Workloads that verify the IMDS signature won’t run.
- Discovery uses the configured EC2 adapter endpoint. Describe operations return supported instances and related resources in the managed account, including the instance. Filters and pagination follow the supported API scope. The metadata endpoint inside the guest remains a separate service; unrelated real cloud accounts are outside this discovery scope.
- Security groups map to target network controls. Use the OCI network security list for the instance’s translated rules. Preserve default-deny ingress and the declared egress permissions; do not rely on OCI’s more permissive default. Review target rule scope, protocol support and address ranges when validating connectivity.
- A per-instance public IP is caught at build: an instance that requests one (
associate_public_ip_address) is refused because this target does not create a per-instance public IP. - Launch templates and Auto Scaling groups use the fleet mapping. A launch template or launch configuration defines each member, and the group maps to an OCI instance pool. Review the Auto Scaling page for the target’s scaling, health-check and rolling-update limits; support for individual instances does not establish every fleet policy.
- The instance runs as the origin’s IAM role, mapped to an OCI dynamic group and instance principal, scoped to this one instance: every OCI instance is automatically an instance principal; the origin’s declared IAM intent becomes a dynamic group whose membership rule and policy use a per-install tag to match only this instance, so a grant never reaches sibling VMs. A role that can’t be resolved to a literal identity (a
name_prefix, or an external profile that can’t be resolved) is caught at compile, and an identity that can’t be scoped to the installed instance fails rather than granting access to other instances. - The OCI shape is the nearest analog, not identical hardware: performance tracks the OCI shape rather than the specific EC2 instance type. The performance tab has the published comparison.
- Disks use the target storage service. The root volume uses an OCI boot volume; attached data volumes need corresponding target disks and guest mounts. Match size, performance class, encryption and attachment limits to the workload. Provisioning a disk does not copy the data from an existing EBS volume.
- Boot-volume performance is one coupled knob, not two. AWS
gp3setsiopsandthroughputindependently; an OCI boot volume sets both together from a single per-GB performance setting. The volume class comes across (a general-purpose origin lands on the balanced setting), but explicitiopsorthroughputnumbers do not, so an instance that sets either is caught at build rather than having the two values silently coerced into one. - Availability-zone placement isn’t reproduced one-to-one: an AWS availability zone has no faithful OCI availability domain, so the instance is placed in the compartment’s availability domain rather than a mapped zone, which changes its placement.
- Burstable and Spot instances have limitations on OCI: a burstable T-instance maps to an OCI shape with a reduced baseline OCPU utilization; the AWS unlimited-burst mode has no OCI equivalent and is caught rather than silently throttled. Spot maps to an OCI preemptible instance (stop → the preemption action); a hibernate-on-interruption policy is caught at compile.
Other considerations
Plan for the following operating requirements.- Native execution: the workload runs directly on the OCI Compute instance; Tensor9 operates the separate in-guest metadata service.
- OCI operates the machine: the hypervisor, host, and availability domain are OCI’s to run, as AWS does for EC2.
- Tensor9 operates the read-only metadata API: the in-guest responder answers the EC2
/latestpaths on 169.254.169.254 while OCI’s own/opcmetadata is passed through, and it accepts no create or terminate against the instance. - The OCI shape is the nearest analog, not identical hardware: the workload lands on the closest
VM.Standardflexible shape, so plan for performance that tracks that shape rather than the specific EC2 instance type. - The instance-id follows the instance’s lifecycle: it is derived from the instance’s OCID, remains stable while the instance exists, and changes when the instance is replaced. Review target replacement rules before changing size or image.