If you use EC2 to host your application, and a tool like CircleCI to automate the deployment of new versions of your application, chances are, you've run into the problem of Circle not being able to SSH into your servers.
The problem is Circle could change the public IP of your runner for every new Build which prevents it from being able to access (SSH) the EC2 Instance. Unfortunately, Circle is not able to provide a list of public IP addresses to whitelist on a Security Group attached to the EC2 Instance. More on this here: https://discuss.circleci.com/t/circleci-source-ip/1202
Assuming that, of course, you haven't allowed public access to port 22 on a production server, right?
The solution is to, temporarily, allow the current Circle runner access to the server in the config.yml of Circle. The steps for doing so can be summarised by the following:
1- Install the AWS CLI
2- Get the public IP of the current CircleCI runner
3- Get the AWS region in which the EC2 Instance is running
4- Get the ID of a Security Group attached to the EC2 Instance This can be specified as an Environment Variable in Circle Project Settings if you wish to avoid committing it to the source code.
5- Add an ingress rule to the security group
6- Give the ingress rule some time to propagate This step can certainly be improved, but waiting for 5 seconds seems to be working fine for now.
7- SSH to the server to deploy
8- Remove the ingress rule
Below is a snippet to implement the above steps:
# 1- Install AWS CLI
curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip"
unzip awscli-bundle.zip
./awscli-bundle/install -b ~/bin/aws
# 2- Get the public IP of the current CircleCI runner
PUBLIC_IP=$(curl ipinfo.io/ip)
# 3- Get AWS Region
# TODO Don't forget to replcae with your own Region
AWS_REGION=us-east-2
# 4- Get SG ID
# TODO Don't forget to replace with your own SG ID
SG_ID=sg-XXXXXXXX
# 5- Add an ingress rule to the security group
~/bin/aws ec2 authorize-security-group-ingress --region $AWS_REGION --group-id $SG_ID \
--protocol tcp --port 22 --cidr $PUBLIC_IP/24
# 6- Give the ingress rule some time to propogate
sleep 5
# 7- SSH to the server to deploy
ssh -o StrictHostKeyChecking=no ubuntu@EC2_public_IP \
# other commands
# TODO Perform steps to deploy
# .
# .
# .
# 8- Remove the ingress rule
~/bin/aws ec2 revoke-security-group-ingress --region $AWS_REGION --group-id $SG_ID \
--protocol tcp --port 22 --cidr $PUBLIC_IP/24
IMPORTANT Do not forget to add the SSH key file (.pem) in the Project Settings in Circle.
The file below is a complete config.yml that you can use as a starting point.