How to prevent Man-in-the-Middle (MITM) attacks by adding EC2 instance’s SSH Host Key to GitHub Workflow
To enhance the security of your GitHub Actions workflow, you can add the EC2 instance’s SSH host key to the known_hosts
file. This process will help in verifying the identity of the EC2 instance when connecting via SSH, thereby preventing Man-in-the-Middle (MITM) attacks.
Step 1: Obtain Your EC2 SSH Host Key:
- SSH into your EC2 instance.
- Run
ssh-keyscan -t rsa [your-ec2-ip-or-domain]
to get the SSH host key.
ops, it appears that ssh-keyscan
is not returning the full SSH key, but only the SSH server version. To correctly capture the SSH host key, you might need to run ssh-keyscan
without specifying the key type, or try a different approach.
Copy the output, which is your EC2 instance’s SSH host key.
35.164.114.135 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAdqwffsdfas
Step 2: Add EC2 Host Key to GitHub Secrets:
In your GitHub repository, go to “Settings” -> “Secrets”. Click “New repository secret”. Name it EC2_HOST_KEY
. Paste the SSH host key you copied into the value field.
STEP 3: Update Your GitHub Actions Workflow
Modify your .github/workflows/deploy.yml
file to include the host key in the known_hosts
file. Here's how you can do it:
name: Deploy to AWS EC2
on:
push:
branches:
- main # Set the branch to trigger the deployment
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Deploy to AWS EC2
run: |
# Setting up SSH Key
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# Add EC2 host key to known_hosts
echo "${{ secrets.EC2_HOST_KEY }}" >> ~/.ssh/known_hosts
# Rsync to transfer the project to EC2
rsync -avz --exclude='.git/' --exclude='.DS_Store' --exclude='venv_winjob' --exclude='__pycache__' --exclude='.gitattributes' --exclude='.gitignore' --exclude='history templates' --exclude='history version' --exclude='.env' -e "ssh -i ~/.ssh/id_rsa" $GITHUB_WORKSPACE/ ec2-user@${{ secrets.EC2_HOST }}:/home/ec2-user/winjob/
# SSH into EC2 and set up the virtual environment and install dependencies
ssh -i ~/.ssh/id_rsa ec2-user@${{ secrets.EC2_HOST }} "
# Remove the existing virtual environment (if necessary)
# rm -rf /home/ec2-user/winjob/venv_winjob
# Create a new virtual environment
# python3 -m venv /home/ec2-user/winjob/venv_winjob
# Activate the virtual environment
source /home/ec2-user/winjob/venv_winjob/bin/activate
# Install the required packages
pip3 install -r /home/ec2-user/winjob/requirements.txt
# Additional commands to restart your application (if necessary)
sudo systemctl restart gunicorn
"
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
EC2_HOST: ${{ secrets.EC2_HOST }}
EC2_HOST_KEY: ${{ secrets.EC2_HOST_KEY }}
ops, error:
After getting advises from ChatGPT and testing a lot of time, I found that we can use
ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts
to replce
echo "${{ secrets.EC2_HOST_KEY }}" >> ~/.ssh/known_hosts
in other words, no need to use EC2_HOST_KEY
:(
The updated file is:
name: Deploy to AWS EC2
on:
push:
branches:
- main # Set the branch to trigger the deployment
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Deploy to AWS EC2
run: |
# Setting up SSH Key
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# Add EC2 host key to known_hosts
# echo "${{ secrets.EC2_HOST_KEY }}" >> ~/.ssh/known_hosts
# Dynamically add EC2 host key to known_hosts
ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts
# Rsync to transfer the project to EC2
rsync -avz --exclude='.git/' --exclude='.DS_Store' --exclude='venv_winjob' --exclude='__pycache__' --exclude='.gitattributes' --exclude='.gitignore' --exclude='history templates' --exclude='history version' --exclude='.env' -e "ssh -i ~/.ssh/id_rsa" $GITHUB_WORKSPACE/ ec2-user@${{ secrets.EC2_HOST }}:/home/ec2-user/winjob/
# SSH into EC2 and set up the virtual environment and install dependencies
ssh -i ~/.ssh/id_rsa ec2-user@${{ secrets.EC2_HOST }} "
# Remove the existing virtual environment (if necessary)
# rm -rf /home/ec2-user/winjob/venv_winjob
# Create a new virtual environment
# python3 -m venv /home/ec2-user/winjob/venv_winjob
# Activate the virtual environment
source /home/ec2-user/winjob/venv_winjob/bin/activate
# Install the required packages
pip3 install -r /home/ec2-user/winjob/requirements.txt
# Additional commands to restart your application (if necessary)
sudo systemctl restart gunicorn
"
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
EC2_HOST: ${{ secrets.EC2_HOST }}
EC2_HOST_KEY: ${{ secrets.EC2_HOST_KEY }}
It works! At least on my computer. So for now, every time I update my GitHub repo, the EC2 instance will update too.