Instance metadata and user data
Objective
Section titled “Objective”Read this before writing cloud-init for this platform. One deliberate difference from AWS changes how configuration reaches your machine, and it is not visible from the API side.
Configuration arrives on a config drive, not over the network
Section titled “Configuration arrives on a config drive, not over the network”force_config_drive = trueEvery guest on this platform is handed its configuration on a config drive —
a small read-only volume attached to the machine, labelled config-2 — and
never over the metadata network.
the compute service normally attaches a config drive only when an instance asks for one, and the EC2 API has no parameter for asking. So no consumer of this cloud could ask; forcing it makes it the platform’s behaviour rather than a per-launch accident.
The reason is a dataplane one. A guest reaches 169.254.169.254 through the
router of its own network — and a machine that has not been configured yet is
exactly the machine least able to fix a fault on that path. The config drive is
the only delivery that does not depend on the network coming up first.
For Talos this matters twice over: it looks for the config-2 volume first and
falls back to the metadata address, so with this set it never touches the
network to install itself.
What you should take from it: if your machine did not get its keys or its user data, the network is not the first thing to check. Mount the drive and look.
blkid -t LABEL=config-2mkdir -p /mnt/cfg && mount /dev/disk/by-label/config-2 /mnt/cfgcat /mnt/cfg/openstack/latest/user_datacat /mnt/cfg/openstack/latest/meta_data.jsonThe metadata service
Section titled “The metadata service”There is one — ec2-api-metadata runs alongside the EC2 API — and it answers on
the usual link-local address from inside an instance:
http://169.254.169.254/latest/meta-data/http://169.254.169.254/latest/user-dataIt is the EC2-shaped metadata service, so the familiar paths work:
instance-id, instance-type, local-ipv4, public-ipv4, hostname,
placement/availability-zone, public-keys/0/openssh-key.
It is a fallback and a convenience here, not the delivery mechanism. Everything it serves is also on the config drive.
What it does not do
Section titled “What it does not do”| AWS | Here |
|---|---|
IMDSv2 session tokens (PUT /latest/api/token, X-aws-ec2-metadata-token) | Not supported. the compute service’s metadata service has no session-token mode |
HttpTokens=required | Refused, not silently downgraded — UnsupportedOperation |
Instance tags in metadata (InstanceMetadataTags) | disabled |
| IPv6 metadata endpoint | disabled |
IAM role credentials at iam/security-credentials/ | Nothing to serve. There are no instance roles — see Identity, as deployed |
The layer’s defaults, which are the only values MetadataOptions will accept:
HttpTokens=optional HttpEndpoint=enabled HttpPutResponseHopLimit=1HttpProtocolIpv6=disabled InstanceMetadataTags=disabledRunInstances sends MetadataOptions only when Terraform has a
metadata_options block; any member that differs from the above is rejected
rather than quietly ignored.
[!warning]
The metadata endpoint is unauthenticated from inside the guest, and
HttpTokens=requiredcannot be set. IMDSv2 exists on AWS specifically to blunt SSRF — an application tricked into fetching a URL cannot reach IMDS because it will not send the token header. That defence is not available here.There are no role credentials to steal, which is the worst of what SSRF gets on AWS. But your SSH public key, hostname and network layout are readable by anything that can make an HTTP request from inside the machine.
User data
Section titled “User data”| Parameter | UserData on RunInstances |
| Encoding | Base64 |
| Limit | 16384 bytes decoded — AWS’s limit, enforced, even though the compute service would allow 65535 |
| Logging | Never logged. The model marks the shape sensitive |
| Delivery | Config drive, and the metadata service |
aws --endpoint-url https://ec2.shelfcs.com --region hel1 \ ec2 run-instances --image-id ami-… --instance-type cd-standard-2-4 \ --key-name mykey --user-data file://cloud-init.yamlresource "aws_instance" "app" { ami = data.aws_ami.debian.id instance_type = "cd-standard-2-4" key_name = aws_key_pair.mine.key_name user_data = file("cloud-init.yaml")}Over 16384 bytes decoded is InvalidParameterValue. If your configuration is
bigger than that, put a fetch in the user data and the payload somewhere your
machine can reach — noting that there is no object storage on this platform to
put it in.
The guest environment cloud-init lands in
Section titled “The guest environment cloud-init lands in”| Login user | Set by the image, never by us — debian, ubuntu, rocky, almalinux, fedora, opensuse, arch. See Machine images |
| Root SSH | Disabled by the vendor image. Your key goes to the login user |
| Address | On 10.100.0.0/24, gateway and NAT at 10.100.0.1 |
| DNS | Quad9 — 9.9.9.9, 149.112.112.112 |
| Root disk | 20–160 GB by shape, deleted with the instance |
Talos takes no cloud-init: it reads Talos machine configuration from the same user-data channel, and has no SSH or login user at all.
A green launch is not a working machine
Section titled “A green launch is not a working machine”[!warning]
cloud-init’s
runcmdswallows failures. Every command in aruncmdblock can fail and cloud-init still finishes; the API still reports the instancerunning, Terraform still reports success, and your machine is up and unconfigured. A pipeline going green tells you the VM booted, not that it works.
Two habits that pay for themselves here:
- Make setup scripts re-runnable. A half-applied configuration is the normal failure, and the fix should be “run it again”, not “rebuild the box”.
- Fail loudly on purpose. Put
set -euo pipefailat the top of abootcmd/runcmdscript and write a sentinel at the end — a file, a systemd unit reachingactive, anything you can check from outside — so “did this work” has an answer that is not “SSH in and read the logs”.
Check what actually happened:
cloud-init status --longsudo cloud-init analyze showsudo journalctl -u cloud-final -bsudo cat /var/log/cloud-init-output.logIf you cannot get in to run those, the VNC console is the way in — it works before the network does.
Go further
Section titled “Go further”- RunInstances — the
UserDataandMetadataOptionsparameters in full - Machine images — login users
- Key pair actions
- Networking — the guest network
- Web console and VNC