When automating SSH key deployment using ssh-copy-id
, the first connection attempt triggers host key verification:
# ssh-copy-id -i .ssh/id_dsa.pub backup@example.com
The authenticity of host 'example.com (xxx.xxx.xxx.xxx)' can't be established.
RSA key fingerprint is 39:fb:5e:70:30:33:2b:18:17:e9:4f:2f:91:b5:d2:21.
Are you sure you want to continue connecting (yes/no)?
Option 1: Using SSH StrictHostKeyChecking
The simplest method is to modify SSH's behavior:
ssh-keyscan -H example.com >> ~/.ssh/known_hosts
ssh-copy-id -i .ssh/id_dsa.pub backup@example.com
Or in a single command:
ssh -o StrictHostKeyChecking=no -i .ssh/id_dsa.pub backup@example.com "true"
ssh-copy-id -i .ssh/id_dsa.pub backup@example.com
Option 2: Expect Script
For more complex scenarios requiring interactive handling:
#!/usr/bin/expect -f
set timeout 20
spawn ssh-copy-id -i .ssh/id_dsa.pub backup@example.com
expect {
"continue connecting" {send "yes\r"; exp_continue}
"password:" {send "your_password\r"}
}
expect eof
Option 3: Using sshpass (for password-based auth)
sshpass -p 'your_password' ssh-copy-id -i .ssh/id_dsa.pub -o StrictHostKeyChecking=no backup@example.com
While automating the "yes" response is convenient, be aware that:
- This bypasses host verification security
- Only use in trusted environments
- Consider pre-populating known_hosts through secure channels
For enterprise environments, combine multiple approaches:
#!/bin/bash
TARGET_HOST="example.com"
TARGET_USER="backup"
KEY_FILE=".ssh/id_dsa.pub"
# Pre-populate known_hosts
mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keyscan -H $TARGET_HOST >> ~/.ssh/known_hosts 2>/dev/null
# Deploy key
if ! ssh-copy-id -i $KEY_FILE $TARGET_USER@$TARGET_HOST; then
echo "Key deployment failed" >&2
exit 1
fi
When running ssh-copy-id
for the first time against a new host, you'll encounter the host verification prompt:
# ssh-copy-id -i .ssh/id_dsa.pub backup@example.com
The authenticity of host 'example.com (xxx.xxx.xxx.xxx)' can't be established.
RSA key fingerprint is 39:fb:5e:70:30:33:2b:18:17:e9:4f:2f:91:b5:d2:21.
Are you sure you want to continue connecting (yes/no)?
The most secure way to automate this is to pre-populate the known_hosts file:
ssh-keyscan example.com >> ~/.ssh/known_hosts
ssh-copy-id -i ~/.ssh/id_dsa.pub backup@example.com
For temporary scripts or trusted environments, you can bypass the check:
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-i ~/.ssh/id_dsa.pub backup@example.com "echo 'Key copied!'"
Here's a robust script that handles both approaches:
#!/bin/bash
HOST="example.com"
USER="backup"
KEY_FILE="$HOME/.ssh/id_dsa.pub"
# Method 1: Pre-scan host key
ssh-keyscan $HOST >> ~/.ssh/known_hosts 2>/dev/null
# Method 2: Direct copy with forced acceptance
ssh-copy-id -i $KEY_FILE $USER@$HOST || \
ssh -o StrictHostKeyChecking=no -i $KEY_FILE $USER@$HOST "true"
# Verify successful key copy
ssh -i $KEY_FILE $USER@$HOST "echo 'SSH key authentication working!'"
While automation is convenient, consider these security best practices:
- Always verify host fingerprints manually for production environments
- Use ssh-keyscan rather than disabling StrictHostKeyChecking when possible
- Implement proper error handling in your scripts
For complex interactive scenarios, you might use expect:
#!/usr/bin/expect -f
set timeout 20
set host "example.com"
set user "backup"
set keyfile "$env(HOME)/.ssh/id_dsa.pub"
spawn ssh-copy-id -i $keyfile $user@$host
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "your_password\r" }
}
expect eof