I'm a big fan of Cloudflare. Even the basic free service offers numerous caching and security features which would be pretty time consuming to implement yourself. At the very least it offers a free and very easy ssl certificate service.
Security should always be thought of as a layered process and Cloudflare plays an important role as a first line of defence. The ability to block out malicious or suspicious requests before it even reaches your server is a great asset. Obviously this only works if Cloudflare is positioned in front of your server and requests are forced to go through Cloudflare's proxy.
For any bad guy worth his salt, its relatively simple to figure out the real IP address of the server and bypass Cloudflare. Your server is now more vulnerable and security is now down to your server skills, up to date software and coding best practices.
Therefore its pretty important to stop direct access to your sites by only allowing web access from Cloudflare IP addresses. This blob post will cover doing this in the Amazon Web Services environment:
- Creating a Security Group
- Assign Security Group to relevant EC2 instances.
- Create A Lambda function to regularly retrieve Cloudflare's IP address list and update the security group.
If you don't use AWS, the theory is still sound and wouldn't take much tweaking to achieve the same though a cron service and iptables.
The Lambda code uses Python 2.7 and uses the Boto3 library to communicate with AWS.
The Lambda Python code is available from the github code repository. I'm relatively new to Python, so feel free to contribute and improve.
Create EC2 Security Group
Firstly create a Security Group and take note of the Group ID. This can be done through the AWS web interface:
Or from the command line:
aws ec2 create-security-group --group-name cloudflare-access --description "http(s) access from Cloudflare IPs only" --vpc-id VPC-ID-GOES-HERE
Keep a note of the Group ID as will use this as an environmental variable with our Lambda code.
Create a Lambda Function
As these IP addresses may change, we need some code to update them. As were in the AWS environment, we can easily do this from a Lambda function which we can run on a regular basis for next to nothing.
If your not familiar with AWS Lambda, its software as a service facility where you can place some code (C#, Java Python or Node) and you only pay for the time that the code runs. No need to maintain a server, just code, pure glorious code!
So heres the code repository for one I did earlier.
The required code is in the file cf-security-group-update.py. For those not familiar def lambda_handler(event, context):
is the main function thats called when the Lambda is triggered. What happens from here should be self explanatory from the descriptive function names.
Select blueprint
From the AWS user interface, select new function and select Blank Function from the blueprint list.
Configure triggers
Next, set a Trigger by clicking on the blank square and selecting CloudWatch Events - Schedule.
You can set up your required CRON or defined rate from here. For now select Rate(1 day) to run this daily.
Configure function
Now give the Lambda a name, choose Python from the runtime list and then paste the contents of cf-security-group-update.py from the github code repository in the text area.
In the Environment variables section, add the following:
key: SECURITY_GROUP_ID
value: add your security group id here
key: PORTS_LIST
value: 80,443
add 80 or 80,443 dependant on if you want http and https added to the security group.
You may need to add a role in the Lambda function handler and role section. If so the only rule needed is:
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:DescribeSecurityGroups"
],
"Resource": [
"*"
]
}
]
Set the Timeout to maybe 5-8 seconds.
Keep the rest of the default values, continue and review, once happy finish by clicking Create Function.
Test
Click the Test button and accept the defaults and the Lambda should hopefully work. The output should list the IP addresses added.
To check it actually did add them, go back into the EC2 section and check your cloudflare-access security group and hopefully it contains IP addresses. Try deleting some and running the Lambda again, it should replace them.
There you go, you now have a Lambda function that will run routinely and will update the specified Security Group with any new CloudFlare IP addresses, Done!
Issues
If it didn't work or you got error messages:
- Cloudflare response error - for some reason the cloudflare API wasn't available.
- Failed to retrieve Security Group - The Group ID used was incorrect.
- If the Lambda times out, click in the Configuration tab and set the Timeout to a higher value, 10 seconds should be adequate.
- Any other errors are probably due to the Security Role being incorrectly setup. Its Stack Overflow time!
Todo
- Add IPv6 addresses
- Remove old IP addresses
Automate AWS security group with CloudFlare IPs first appeared on my blog site on 04/04/2017.
Top comments (3)
Hi John,
I know this is quite an old post and I may not get a reply but going to try anyway.
I can get this working, but it only writes one ip address for each port. Do you have any idea why that may be?
The JSON has multiple IP's but only one writes to the security group. Struggling to figure this one out.
Any help will be much appreciated
Thanks
Dean
Dean
There is an error in the code at github.com/johnmccuk/cloudflare-ip...
Code
needs changing to
That is, swap line 188 with 189.
Exactly what I was searching for, Thank you!