Skip to content

Instantly share code, notes, and snippets.

@dduvnjak
Last active March 7, 2024 15:18
Show Gist options
  • Star 77 You must be signed in to star a gist
  • Fork 19 You must be signed in to fork a gist
  • Save dduvnjak/a0bf8032222fe2b4b30cbcc599c241f0 to your computer and use it in GitHub Desktop.
Save dduvnjak/a0bf8032222fe2b4b30cbcc599c241f0 to your computer and use it in GitHub Desktop.
Add CloudFlare IP addresses to an EC2 Security Group using awscli
# first we download the list of IP ranges from CloudFlare
wget https://www.cloudflare.com/ips-v4
# set the security group ID
SG_ID="sg-00000000000000"
# iterate over the IP ranges in the downloaded file
# and allow access to ports 80 and 443
while read p
do
aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare'}]"
aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges="[{CidrIp=$p,Description='Cloudflare'}]"
done< ips-v4
rm ips-v4
@vaisov
Copy link

vaisov commented May 23, 2017

Cool, thanks for solution.

In my case I wanted EC2 instance to update this list itself, so I created this policy:

{

    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "WhitelistCloudflareIPs1",
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeNetworkAcls",
                "ec2:DescribeSecurityGroups"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "WhitelistCloudflareIPs2",
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupEgress",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:RevokeSecurityGroupEgress",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Resource": [
                "arn:aws:ec2:eu-central-1:<account id>:security-group/<security group id>"
            ]
        }
    ]
}

This policy limits user to edit only defined security group. Just update <account id> and <security group id> in the policy and attach it to this user. Also update the region if your security group isn't in "eu-central-1".

@sqlheisenberg
Copy link

well done. Thanks

@csev
Copy link

csev commented Apr 25, 2018

Nicely done. Thanks.

@roeniss
Copy link

roeniss commented Feb 5, 2020

Really help me a lot. Thank you.

@alinoudev
Copy link

Thanks for this!

@jamsinclair
Copy link

Thanks! I slightly tweaked the script to also add a description:

while read p; do aws ec2 authorize-security-group-ingress --group-id sg-e0000000 --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare'}]"; done< ips-v4

@amaitu
Copy link

amaitu commented Dec 6, 2021

My own version that includes port 443 for those who want their Cloudflare encryption on strict mode:

SG_ID="sg-00000000000000"

wget https://www.cloudflare.com/ips-v4
while read p;
    do
        aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare'}]";
        aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges="[{CidrIp=$p,Description='Cloudflare'}]";
done< ips-v4
rm ips-v4

@dduvnjak
Copy link
Author

@amaitu thanks, updated.

@Kcrong
Copy link

Kcrong commented Jul 5, 2023

My two cents here.

  • Use curl response directly, without tmp file removal.
  • Remove all existing rules. (For handling expired subnets from Cloudflare)
  • Add ipv6
SG_ID="GROUP_ID"

# Delete all existing rules
aws ec2 revoke-security-group-ingress --group-id $SG_ID \
  --ip-permissions \
  "`aws ec2 describe-security-groups --output json --group-ids $SG_ID --query "SecurityGroups[0].IpPermissions"`"

# Adding ipv4
while read -r p
do
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare - updated by instance'}]"
	echo "$p has been added"
done < <(curl --fail --silent https://www.cloudflare.com/ips-v4)
echo "IPv4 completed"

# Adding ipv6
while read -r p
do
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,Ipv6Ranges="[{CidrIpv6=$p,Description='Cloudflare - updated by instance'}]"
	echo "$p has been added"
done < <(curl --fail --silent https://www.cloudflare.com/ips-v6)
echo "IPv6 completed"

@Its-Ankush
Copy link

Thank you for the above script @Kcrong however it seems that the while loop is not reading the last ip address in that list so following this stackoverflow suggestion = https://stackoverflow.com/a/12916758 , ive used the for loop and added both port 80,443[for the cloudflare IPs] and also 22 but only for my IP

#! /bin/bash
SG_ID="";
# Delete all existing rules
aws ec2 revoke-security-group-ingress --group-id $SG_ID \
		  --ip-permissions \
		    "`aws ec2 describe-security-groups --output json --group-ids $SG_ID --query "SecurityGroups[0].IpPermissions"`"

# Adding ipv4
for p in $(< <(curl --fail --silent https://www.cloudflare.com/ips-v4));
do
			aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare - updated by instance'}]"
			aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges="[{CidrIp=$p,Description='Cloudflare - updated by instance'}]"
				echo "$p has been added"
		done;
		echo "IPv4 completed"

# Get my IP
my_ip=$(curl --fail --silent ifconfig.me);
echo "starting to add your IP for SSH";
aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges="[{CidrIp=$my_ip/32,Description='Cloudflare - updated by instance'}]";
echo "your IP added for SSH";

@masonjmiller
Copy link

Not sure if this is still being watched by anyone, but I found it extremely helpful and figured I'd update the chain with what I consider the final script for both ipv4 and ipv6:

#!/bin/bash
SG_ID="sg-00000000000000000"
aws ec2 revoke-security-group-ingress --group-id $SG_ID --ip-permissions "`aws ec2 describe-security-groups --output json --group-ids $SG_ID --query "SecurityGroups[0].IpPermissions"`"

# Adding ipv4
for p in $(curl --fail --silent https://www.cloudflare.com/ips-v4);
do
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$p,Description='Cloudflare IPv4 - updated by instance'}]"
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges="[{CidrIp=$p,Description='Cloudflare IPv4 - updated by instance'}]"
	echo "$p has been added"
done
echo "IPv4 completed"

# Adding ipv6
for p in $(curl --fail --silent https://www.cloudflare.com/ips-v6);
do
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,Ipv6Ranges="[{CidrIpv6=$p,Description='Cloudflare IPv6 - updated by instance'}]"
	aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions IpProtocol=tcp,FromPort=443,ToPort=443,Ipv6Ranges="[{CidrIpv6=$p,Description='Cloudflare IPv6 - updated by instance'}]"
	echo "$p has been added"
done
echo "IPv6 completed"

The only thing I'm having trouble with is capturing "my IP", since I'm running this via cloudshell. Oh well, doesn't hurt to still manually do that once in awhile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment