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:

  1. 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.
  2. 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_groups module creates the default system user (typically debian on official Debian cloud images) if it does not already exist, assigning standard groups like sudo and disabling password authentication.
  • SSH Key Injection: The cc_ssh module reads the public keys present in both the metadata and the user-data configuration. It writes these keys into the user's ~/.ssh/authorized_keys file. If configured, it can also inject administrative keys into /root/.ssh/authorized_keys.
  • Permission Enforcement: cloud-init strictly applies POSIX permissions to the generated files, setting the .ssh directory to 0700 and authorized_keys to 0600, 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-init generates 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.