When working with cloud providers like AWS EC2, DigitalOcean droplets, or other ephemeral infrastructure, the standard SSH security model becomes problematic. Each time your instance gets a new IP (which happens during reboots, scaling events, or provider maintenance), you'll face the dreaded:
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
The known_hosts
file maintains cryptographic fingerprints of servers you've previously connected to. While crucial for security in static environments, this becomes a nuisance with:
- Cloud auto-scaling groups
- Spot instances
- Containers with short lifespans
- Kubernetes pods
For development environments (not recommended for production):
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@hostname
For more controlled environments:
#!/bin/bash
# Safe automated connection script
HOST="your-dynamic-host"
TMP_FILE="/tmp/known_hosts.tmp"
ssh-keygen -R "$HOST" -f ~/.ssh/known_hosts
ssh-keyscan -H "$HOST" > "$TMP_FILE"
if [ -s "$TMP_FILE" ]; then
cat "$TMP_FILE" >> ~/.ssh/known_hosts
ssh user@"$HOST"
else
echo "Failed to fetch host keys"
exit 1
fi
Add this to your ~/.ssh/config
:
Host *.dynamic-cloud
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
GlobalKnownHostsFile /dev/null
LogLevel ERROR
While convenient, these approaches weaken SSH's man-in-the-middle protection. For better security:
- Use cloud provider metadata services to verify host keys
- Implement certificate-based authentication
- Use SSHFP DNS records when possible
- Consider tools like HashiCorp Vault for dynamic credentials
For large-scale operations:
# Ansible playbook snippet
- name: Update known hosts
known_hosts:
path: /etc/ssh/ssh_known_hosts
name: "{{ inventory_hostname }}"
key: "{{ lookup('pipe', 'ssh-keyscan {{ inventory_hostname }}') }}"
When working with cloud providers like AWS EC2, DigitalOcean droplets, or auto-scaling groups, instances frequently get new IP addresses upon reboot or recreation. This triggers SSH's host key verification:
Warning: Permanently added 'hostname' (ECDSA) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Before implementing solutions, understand that SSH host key verification exists to prevent man-in-the-middle attacks. These workarounds should only be used in:
- Controlled development environments
- Temporary testing instances
- When you control both endpoints
Add this to your ~/.ssh/config:
Host dynamic-host
HostName your.hostname.com
User username
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
This completely disables host key checking for this specific host.
For one-time connections:
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@hostname
For more control, use this bash function in your .bashrc:
function ssh_dynamic() {
local host=$1
ssh-keygen -R $host
ssh-keyscan -H $host >> ~/.ssh/known_hosts
ssh $host
}
Usage: ssh_dynamic your.hostname.com
For multiple hosts, create a playbook:
- name: Update SSH known hosts
hosts: all
tasks:
- name: Scan and add host keys
ansible.builtin.known_hosts:
path: /tmp/known_hosts
name: "{{ inventory_hostname }}"
key: "{{ lookup('pipe', 'ssh-keyscan {{ inventory_hostname }}') }}"
Consider using:
- DNS CNAME records that update automatically
- Cloud provider metadata services (AWS IMDS)
- Service discovery tools like Consul