DEV Community

John McCracken
John McCracken

Posted on

Automate AWS security group with CloudFlare IPs

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.

Cloudlfare protection

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.

Bad guys, doing their thing!

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
Enter fullscreen mode Exit fullscreen mode
key: PORTS_LIST
value: 80,443
Enter fullscreen mode Exit fullscreen mode

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": [
                "*"
            ]
        }
    ]
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
deanhtid99 profile image
Dean Whittaker  🦈

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

Collapse
 
yebowhatsay profile image
yebowhatsay • Edited

Dean

There is an error in the code at github.com/johnmccuk/cloudflare-ip...

Code

  ## IPv4
    # add new addresses
    for ipv4_cidr in ip_addresses['ipv4_cidrs']:
        for port in ports:
            if not check_ipv4_rule_exists(current_rules, ipv4_cidr, port):
                add_ipv4_rule(security_group, ipv4_cidr, port)

needs changing to

     ## IPv4
    # add new addresses
    for port in ports:
        for ipv4_cidr in ip_addresses['ipv4_cidrs']:
            if not check_ipv4_rule_exists(current_rules, ipv4_cidr, port):
                add_ipv4_rule(security_group, ipv4_cidr, port)

That is, swap line 188 with 189.

Collapse
 
roshan8 profile image
Roshan shetty

Exactly what I was searching for, Thank you!