Description
cloud-init configures a new instance from its datasource: the metadata service of the cloud
provider (IMDS), or a configuration disk such as a NoCloud cidata volume or an OpenStack
config drive. It is installed on every Ubuntu cloud image and on servers installed with
Subiquity, and it starts at every boot: it detects the datasource again, runs its per-boot
modules (bootcmd, scripts-per-boot, hostname and /etc/hosts updates), and when the
instance ID changes it runs every first-boot module again (users, SSH keys, packages, user-data
scripts).
Once the server is provisioned and managed by the organization's own tools, the file
/etc/cloud/cloud-init.disabled (or cloud-init=disabled on the kernel command line) stops
cloud-init from running at boot. cloud-init status then prints disabled.
The fix only writes the file when cloud-init status reports done, so that it never stops a
provisioning that is still running or failed. The fix is disabled by default (lockout_risk):
a server whose network depends on cloud-init can become unreachable after a hardware change.
Removing the cloud-init package also meets the goal, but it is harder to undo and some
platforms (Azure, Proxmox templates) expect it to be present. The QEMU guest agent and the SSH
server keep working: they do not depend on cloud-init once the system is provisioned.
Rationale
The datasource is a root-level configuration channel that is not covered by the server's own
change management. A person who can edit the user-data in the cloud console, answer as the
metadata service on a network without IMDS protection, or attach a disk labelled cidata to the
machine can add an SSH key, create an account or run a script as root at the next boot. Stopping
cloud-init after provisioning closes that channel and keeps the network, users and keys under
configuration management only.
Impact
From the next boot, cloud-init no longer applies changes coming from the platform:
- network:
/etc/netplan/50-cloud-init.yamlstays as written at provisioning and is no longer regenerated. When it matches the interface by MAC address, a new or replaced network card (another MAC address, a VM moved to a new network) comes up without network; - disk: the root partition and file system are no longer grown after the disk is enlarged
(
growpart,resizefs): rungrowpartandresize2fsby hand; - identity: hostname, SSH keys and users from the metadata are no longer updated, and a cloned VM keeps the SSH host keys of its source.
Re-enable cloud-init (remove the file and reboot) before resizing, moving or cloning the server through the cloud platform. Do not apply this control to images or templates, and keep it off for autoscaled instances that the platform must be able to rebuild.
Applies when
Detected: when: cloud-init is installed A scanner reports the control not applicable when one is false.
Setting
| Location | /etc/cloud/cloud-init.disabled |
| Default | Absent (cloud-init runs at every boot) |
| Recommended | Present |
Audit
- Check that
/etc/cloud/cloud-init.disabledexists, or that/proc/cmdlinecontainscloud-init=disabled. - After a reboot,
cloud-init statusmust printstatus: disabled.
Automated: every check must pass. Scanners report each check by its id.
disabled
cloud-init is disabled by /etc/cloud/cloud-init.disabled or the kernel command line.
script: |
if [ -e /etc/cloud/cloud-init.disabled ]; then
echo "/etc/cloud/cloud-init.disabled present"
exit 0
fi
if grep -qw 'cloud-init=disabled' /proc/cmdline; then
echo "cloud-init=disabled on the kernel command line"
exit 0
fi
s=$(cloud-init status 2>/dev/null | sed -n 's/^status: //p')
echo "cloud-init enabled (status: ${s:-unknown})"
exit 1
Remediation
- Check that provisioning is over:
cloud-init statusmust printstatus: done. - Check that
/etc/netplan/holds the network configuration the server needs without cloud-init (and adapt anymatch: macaddressif the hardware may change). - Run
touch /etc/cloud/cloud-init.disabled, reboot, and check thatcloud-init statusprintsstatus: disabledand that the network and SSH access still work.
| Restart | system reboot |
| Disruption | low |
| Lockout risk | yes: can cut off administrative access. Off by default in generated scripts and playbooks, opt in through a tailoring file. |
Rollback
Delete /etc/cloud/cloud-init.disabled and reboot. If the instance ID has not changed,
cloud-init only runs its per-boot modules again.
disable
f=/etc/cloud/cloud-init.disabled
[ -e "$f" ] && exit 0
s=$(cloud-init status 2>/dev/null | sed -n 's/^status: //p')
if [ "$s" != done ]; then
echo "cloud-init provisioning is not done (status: ${s:-unknown}), not disabling it" >&2
exit 1
fi
printf '# Written by CIRSEC Baselines CB-UBU-SVC-028: cloud-init does not run at boot.\n' >"$f"
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- cloud-init documentation - How to disable cloud-init Canonical, vendor-doc, accessed 2026-10-19
- cloud-init documentation - Boot stages Canonical, vendor-doc, accessed 2026-10-19
- cloud-init documentation - NoCloud datasource Canonical, vendor-doc, accessed 2026-10-19
- cloud-init(1), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R62) ANSSI, guide, accessed 2026-10-19
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R62 | partial | R62 asks to disable every unneeded service; this control covers cloud-init after provisioning. |
| NIST SP 800-53 Rev. 55.1.1 | CM-7 | partial | |
| NIST SP 800-53 Rev. 55.1.1 | CM-5 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. Stock image fails (status: done); fix only with CB_ENABLE_CB_UBU_SVC_028=1 (lockout_risk), writes cloud-init.disabled; after reboot status: disabled, network (DHCP from the cloud-init netplan file), SSH and guest agent work, also after installing and removing about 30 packages. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Stock image fails (status: done); fix only with CB_ENABLE_CB_UBU_SVC_028=1 (lockout_risk), writes cloud-init.disabled; after reboot status: disabled, network (DHCP from the cloud-init netplan file), SSH and guest agent work, also after installing and removing about 30 packages. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Stock image fails (status: done); fix only with CB_ENABLE_CB_UBU_SVC_028=1 (lockout_risk), writes cloud-init.disabled; after reboot status: disabled, network (DHCP from the cloud-init netplan file), SSH and guest agent work, also after installing and removing about 30 packages. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Stock image fails (status: done); fix only with CB_ENABLE_CB_UBU_SVC_028=1 (lockout_risk), writes cloud-init.disabled; after reboot status: disabled, network (DHCP from the cloud-init netplan file), SSH and guest agent work, also after installing and removing about 30 packages. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |