When working with AWS EC2 instances, there are scenarios where you need to transfer your SSH public key without relying on AWS-specific CLI tools like ec2-instance-connect
or aws ec2-instance
commands. This typically happens when:
- Your IAM permissions don't include EC2 API access
- You're working in an environment with strict security policies
- You need to script the process in a vendor-agnostic way
Method 1: Using SSH Directly
The most reliable way is to use standard SSH authentication to first connect with an existing key, then append your new public key:
# First connect using existing credentials
ssh -i ~/.ssh/existing_key.pem ec2-user@your-instance-public-dns
# Once connected, append your new public key
echo "ssh-rsa AAAAB3NzaC1yc2EAAA... your-comment" >> ~/.ssh/authorized_keys
Method 2: Temporary Password Authentication
If you can temporarily enable password authentication:
# On the EC2 instance (via AWS console or existing access):
sudo sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Then use ssh-copy-id with password:
ssh-copy-id -i ~/.ssh/new_key.pub ec2-user@your-instance-public-dns
# Remember to disable password auth afterward
Method 3: EC2 User Data Injection
For new instances, inject the public key through user data:
#!/bin/bash
mkdir -p /home/ec2-user/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAA..." >> /home/ec2-user/.ssh/authorized_keys
chown -R ec2-user:ec2-user /home/ec2-user/.ssh
chmod 700 /home/ec2-user/.ssh
chmod 600 /home/ec2-user/.ssh/authorized_keys
Common pitfalls include incorrect permissions on the .ssh
directory or authorized_keys
file. The directory should be 700 and the file 600:
ssh -i ~/.ssh/existing_key.pem ec2-user@instance \
"chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys"
For scripting purposes, here's a complete workflow:
#!/bin/bash
INSTANCE_DNS="ec2-1-2-3-4.compute-1.amazonaws.com"
TEMP_KEY="~/.ssh/temp_access.pem"
NEW_PUB_KEY="~/.ssh/new_key.pub"
# Copy via existing credentials
scp -i $TEMP_KEY $NEW_PUB_KEY ec2-user@$INSTANCE_DNS:/tmp/new_key.pub
# SSH in and append the key
ssh -i $TEMP_KEY ec2-user@$INSTANCE_DNS \
"cat /tmp/new_key.pub >> ~/.ssh/authorized_keys && rm /tmp/new_key.pub"
When provisioning EC2 instances, we often need to transfer SSH public keys manually when:
- AWS CLI/API tools aren't available
- Existing key pairs need rotation
- Automation scripts require alternative methods
Traditional approaches like ssh-copy-id
or scp
fail because:
# This doesn't work as expected:
ssh-copy-id -i ~/.ssh/new_key.pub ec2-user@ec2-instance
# Neither does this:
scp -i ~/.ssh/existing_key.pem ~/.ssh/new_key.pub ec2-user@ec2-instance:~/.ssh/
The -i
parameter behaves differently across tools - for ssh-copy-id
it specifies which key to install, not which key to authenticate with.
Method 1: SSH Pipe Technique
cat ~/.ssh/new_key.pub | ssh -i ~/.ssh/existing_key.pem ec2-user@ec2-instance \
"mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
Method 2: Temporary SCP Transfer
# First copy the public key to a temporary location
scp -i ~/.ssh/existing_key.pem ~/.ssh/new_key.pub ec2-user@ec2-instance:/tmp/new_key.pub
# Then SSH in to move it properly
ssh -i ~/.ssh/existing_key.pem ec2-user@ec2-instance \
"cat /tmp/new_key.pub >> ~/.ssh/authorized_keys && rm /tmp/new_key.pub"
For automation scenarios, consider this Python script using Paramiko:
import paramiko
def add_public_key(hostname, username, key_path, public_key_path):
private_key = paramiko.RSAKey.from_private_key_file(key_path)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, username=username, pkey=private_key)
sftp = ssh.open_sftp()
try:
with sftp.file('.ssh/authorized_keys', 'a') as f:
with open(public_key_path) as pk:
f.write(pk.read() + '\n')
finally:
sftp.close()
ssh.close()
Always verify the key was properly installed:
ssh -i ~/.ssh/new_key ec2-user@ec2-instance "echo 'Key test successful'"
Check the remote authorized_keys file:
ssh -i ~/.ssh/existing_key.pem ec2-user@ec2-instance \
"cat ~/.ssh/authorized_keys | grep 'your_key_comment'"