How Cloud-Init Provisions Metadata and SSH Keys on Debian
When a Debian cloud instance boots for the first time,
cloud-init automatically discovers the host environment,
fetches instance metadata from cloud-specific providers, and securely
injects configuration details, user accounts, and public SSH keys into
the operating system. This automated provisioning process eliminates
manual setup, allowing instances to be immediately reachable and
configured for remote management.
The Boot Process and Datasource Discovery
The provisioning workflow is managed through standard Debian
systemd services grouped under
cloud-init.target. The initial stage,
cloud-init-local.service, runs before local networking is
fully initialized. During this phase, cloud-init searches
for an available datasource.
A datasource can be a link-local network service (such as the
standard 169.254.169.254 metadata service used by AWS,
Google Cloud, and OpenStack) or an attached disk image containing a
configuration drive (such as NoCloud or
ConfigDrive). Once the platform is identified,
cloud-init waits for networking to initialize so it can
request the metadata payload.
Fetching Metadata and User-Data
Once the network is available via cloud-init.service,
the daemon retrieves the instance's metadata and user-data:
- Metadata: Contains cloud-provided properties, including the assigned hostname, local and public IP addresses, network routes, and default public SSH keys registered in the cloud console.
- User-Data: Contains custom configurations provided by the user, such as cloud-config YAML directives, shell scripts, or additional user accounts.
The retrieved files are cached locally in
/var/lib/cloud/instance/ to ensure that future boots do not
unnecessarily query the metadata service for static initialization
data.
SSH Key and User Provisioning
After fetching the metadata, the cloud-config.service
stage executes specific modules responsible for identity and access
management:
- User Creation: The
cc_users_groupsmodule creates the default system user (typicallydebianon official Debian cloud images) if it does not already exist, assigning standard groups likesudoand disabling password authentication. - SSH Key Injection: The
cc_sshmodule reads the public keys present in both the metadata and the user-data configuration. It writes these keys into the user's~/.ssh/authorized_keysfile. If configured, it can also inject administrative keys into/root/.ssh/authorized_keys. - Permission Enforcement:
cloud-initstrictly applies POSIX permissions to the generated files, setting the.sshdirectory to0700andauthorized_keysto0600, owned by the target user. This prevents OpenSSH from rejecting the keys due to insecure file permissions. - Host Key Generation: If the instance does not have
SSH host keys,
cloud-initgenerates unique RSA, ECDSA, and Ed25519 host keys for the SSH daemon, ensuring unique cryptographic identity for the new server.
Finalization
In the final stage, cloud-final.service,
cloud-init applies any optional configuration routines
specified in the user-data, such as package installations, command
execution via runcmd, or arbitrary shell scripts. A
sentinel file is then written to
/var/lib/cloud/instance/boot-finished to signify that
provisioning is complete, leaving the Debian instance fully accessible
over SSH using the provisioned credentials.