Harden Cloud-Init User Data
Keep user data minimal, never embed secrets, disable password SSH, and use cloud-init only for bootstrap before configuration management takes over.
Task
Make cloud-init user data safe and minimal instead of a long script with baked-in credentials.
When to use this
User data contains secrets and a sprawling script, so it is visible in instance metadata and becomes an unmaintainable second configuration system.
Prerequisites
- A cloud that supports cloud-init
- A configuration management or image pipeline for ongoing config
Steps
1. Restrict user data to bootstrap: users, SSH keys, and a one-time fetch of real config.
Expected output: User data stays small and auditable.
2. Fetch secrets at runtime from a secret manager, never embed them.
Expected output: Instance metadata never exposes credentials.
3. Disable password authentication and root SSH login.
Expected output: Access is key-based only.
4. Hand ongoing configuration to configuration management or a baked image.
curl -s http://169.254.169.254/latest/user-data | headExpected output: There is one source of truth for config.
Troubleshooting
Problem
Secrets visible in metadata
Solution
Anyone with access to the instance can read user data; rotate any secret that was embedded and move it to a secret manager.
Problem
Long user-data script fails partway
Solution
Keep bootstrap idempotent and log errors; use a proper image pipeline for complex setup.
Limitations
- User data is visible to anyone who can query instance metadata, so it must be treated as non-secret.
- Bootstrap via cloud-init adds boot-time dependency on external services for secrets and config.
Context
Make cloud-init user data safe and minimal instead of a long script with baked-in credentials. User data contains secrets and a sprawling script, so it is visible in instance metadata and becomes an unmaintainable second configuration system.
Steps
- Restrict user data to bootstrap: users, SSH keys, and a one-time fetch of real config. Expected: User data stays small and auditable.
- Fetch secrets at runtime from a secret manager, never embed them. Expected: Instance metadata never exposes credentials.
- Disable password authentication and root SSH login. Expected: Access is key-based only.
- Hand ongoing configuration to configuration management or a baked image. Expected: There is one source of truth for config.
#cloud-config
users:
- name: deploy
ssh_authorized_keys: [ssh-ed25519 AAAA...]
ssh_pwauth: false
disable_root: true
runcmd:
- [ sh, -c, "curl -fsSL https://config.example.com for real config" ]
Verify
- User data stays small and auditable.
- Instance metadata never exposes credentials.
- Access is key-based only.
- There is one source of truth for config.
Limits
- User data is visible to anyone who can query instance metadata, so it must be treated as non-secret.
- Bootstrap via cloud-init adds boot-time dependency on external services for secrets and config.