When creating custom AMIs on AWS, many administrators encounter an annoying behavior where cloud-init automatically disables root SSH login during instance initialization - even when you've explicitly enabled it in your base image. This happens because Ubuntu's cloud-init package includes a configuration module (cc_ssh.py) that manages SSH server settings.
The culprit is in /usr/share/pyshared/cloudinit/CloudConfig/cc_ssh.py. This module performs several SSH-related tasks during boot:
1. Regenerates host keys (useful for security)
2. Disables root login via SSH (problematic for automation)
3. Manages authorized_keys files
The proper way to prevent this is by creating a cloud-init configuration file that overrides the default behavior. Create /etc/cloud/cloud.cfg.d/99_keep_root.cfg with:
#cloud-config
ssh_pwauth: true
disable_root: false
ssh_deletekeys: false # if you want to keep existing host keys
If you need to ensure root access regardless of cloud-init's behavior, you can add a script to run after cloud-init completes:
#!/bin/bash
# Place in /var/lib/cloud/scripts/per-instance/
sed -i 's/PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshd
After implementing either solution, verify that root login remains enabled:
# Check SSH config
grep "PermitRootLogin" /etc/ssh/sshd_config
# Test connection (from another terminal)
ssh -i your_key.pem root@your-instance-ip
While enabling root SSH access can be necessary for automation, consider these security best practices:
1. Use SSH keys only (disable password authentication)
2. Restrict source IPs in security groups
3. Change default SSH port
4. Implement fail2ban or similar protection
5. Regularly rotate SSH keys
If you want to maintain consistent host keys across instances (not recommended for security), add this to your cloud-init config:
ssh_deletekeys: false
ssh_genkeytypes: []
When creating custom AMIs on AWS, many administrators encounter an annoying behavior where cloud-init re-disables root SSH login during instance launch, even after explicitly enabling it in the base image. This occurs because cloud-init's cc_ssh module automatically applies security hardening by default.
The crucial configuration lives in /usr/share/pyshared/cloudinit/CloudConfig/cc_ssh.py. The module performs three key operations:
1. Regenerates host SSH keys (desired behavior)
2. Disables root login via SSH (problematic for automation)
3. Manages SSH authorized_keys (can interfere with custom setups)
The proper way to prevent this is through cloud-init's configuration system. Create or modify /etc/cloud/cloud.cfg.d/99-disable-ssh-root-lockdown.cfg:
# cloud-init configuration to preserve root login
ssh_pwauth: true
disable_root: false
ssh_deletekeys: false # if you want to preserve host keys
If you prefer a more surgical approach, create a systemd service that runs after cloud-init:
# /etc/systemd/system/enable-root-ssh.service
[Unit]
Description=Re-enable root SSH access
After=cloud-init.target
[Service]
Type=oneshot
ExecStart=/bin/sed -i 's/^PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
ExecStart=/bin/systemctl restart sshd
[Install]
WantedBy=multi-user.target
After implementing either method, validate the configuration:
# Check cloud-init logs
sudo cat /var/log/cloud-init.log | grep -i "root"
# Verify SSH config
sudo grep "PermitRootLogin" /etc/ssh/sshd_config
# Test connection (from another terminal)
ssh -p YOUR_CUSTOM_PORT root@instance-ip
While enabling root login facilitates automation, consider these security measures:
- Restrict root access to specific IPs in
/etc/ssh/sshd_config:Match Address YOUR_IP_RANGE PermitRootLogin yes - Use SSH certificates instead of passwords
- Implement two-factor authentication for root