8

Let's say that users' avatars are uploaded and stored on the Amazon S3 and we have a domain called mywebsite.com and I want to use CloudFlare in order to cache the files from the S3 bucket. How would I do that?

NoDisplayName
  • 15,246
  • 12
  • 62
  • 98

2 Answers2

13

The docs that we can find on the cloudflare site are rather implicit and I had to google quite a lot to make it work. So here's my solution that may not be comprehensive but it may be good enough to get started.

1) Create a bucket called avatars.mywebsite.com

2) Add the following policy to it. Policy, not CORS.

{
    "Version": "2012-10-17",
    "Id": "http referer policy",
    "Statement": [
        {
            "Sid": "CloudFlare Requests",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::avatars.mywebsite.com/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "103.21.244.0/22",
                        "103.22.200.0/22",
                        "103.31.4.0/22",
                        "104.16.0.0/12",
                        "108.162.192.0/18",
                        "131.0.72.0/22",
                        "141.101.64.0/18",
                        "162.158.0.0/15",
                        "172.64.0.0/13",
                        "173.245.48.0/20",
                        "188.114.96.0/20",
                        "190.93.240.0/20",
                        "197.234.240.0/22",
                        "198.41.128.0/17"
                    ]
                }
            }
        }
    ]
}

What I believe it does is that it restricts the access to the bucket so that it could only be accessed with those IPs, which belong to CloudFlare and may be found somewhere on their website. Also I believe Id and Sid can contain any information that makes sense in your case.

3) Add a CNAME record in the CloudFlare DNS manager. Name should be avatars and value avatars.mywebsite.com.s3.amazonaws.com

4) Now, if you want to access a file in the bucket with a path like user/1/avatar.jpg from your website, use the following src:

https://avatars.mywebsite.com/user/1/avatar.jpg

5) It's worth pointing out that it may be required to change the SSL level from Full(Strict) to Full in the CloudFlare dashboard if HTTPS is used.

NoDisplayName
  • 15,246
  • 12
  • 62
  • 98
  • 1
    Not bad. *"What I believe it does is that it restricts the access to the bucket so that it could only be accessed with those IPs"* Technically, what this does is not restrict the bucket but rather allow unauthenticated access to private objects when the source IP is one of the listed addresses. The net effect is similar if the object ACLs, bucket policy, and bucket ACLs don't make things in the bucket public for everyone. `Sid` (Statement ID) is indeed an opaque label for convenience, the service does not interpret it. – Michael - sqlbot Dec 25 '17 at 08:43
  • Hi, I have a couple of questions. Does Cloudflare let you know when these IPs change? They are different now than 2 years ago when this post was made. I'm wondering if it'll cause a problem if certain CF IPs are blocked from this bucket when they change. Also, this enables Cloudflare to cache your avatar images, is that correct? – user2619824 Aug 03 '20 at 23:09
  • You can also use the origin rule to map any domain to your S3 bucket, without keeping the bucket name the same as your domain name. Step by step guide can be found here: https://dev.to/ashish_r/how-to-access-a-private-s3-bucket-via-cloudflare-2nc5 – Ashish Aug 01 '23 at 20:29
0

This solution fits better if you use the s3 bucket for private and public objects. It restricts public access unless IP belongs to Cloudflare. So it transparently replaces s3.amazonaws.com with the custom domain.

{
    "Version": "2012-10-17",
    "Id": "http referer policy",
    "Statement": [
        {
            "Sid": "CloudFlare Requests",
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::avatars.mywebsite.com/*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "173.245.48.0/20",
                        "103.21.244.0/22",
                        "103.22.200.0/22",
                        "103.31.4.0/22",
                        "141.101.64.0/18",
                        "108.162.192.0/18",
                        "190.93.240.0/20",
                        "188.114.96.0/20",
                        "197.234.240.0/22",
                        "198.41.128.0/17",
                        "162.158.0.0/15",
                        "104.16.0.0/12",
                        "172.64.0.0/13",
                        "131.0.72.0/22",
                        "2400:cb00::/32",
                        "2606:4700::/32",
                        "2803:f800::/32",
                        "2405:b500::/32",
                        "2405:8100::/32",
                        "2a06:98c0::/29",
                        "2c0f:f248::/32"
                    ]
                }
            }
        }
    ]
}

P.S: Don't forget to update the list of CloudFlare servers https://www.cloudflare.com/ips/

karser
  • 1,625
  • 2
  • 20
  • 24
  • I have tried the above solution, and also updated the CNAME in cloudflare DNS. But when I try to access the object in the bucket I am getting access denied even after changing my bucket to Public. Is there anything else to be checked ? – Sreejith Jul 23 '20 at 05:52