Whitelist IP addresses to access the static site hosted on S3
Published: 2023-01-23 05:19:45

Have a static web application hosted on S3 for a specific group and wanted to restrict the traffic to certain IP addresses? Let’s see how this can be achieved. To restrict access to whitelisted IP addresses we will use a bucket policy. As a part of this article, we will set up the S3 bucket for static website hosting from scratch and enable it to serve the traffic to only whitelisted IP addresses.

### Setup S3 bucket for static site host

Navigate to S3 Management Console and create the new bucket with Public Access enabled.

![S3 config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vsih0r855hvnw00ortt4.png)

Upload the necessary files in the bucket for a web application.

![Static site](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44stpvwrmbginp9ptric.png)

Next step: To enable the Static website hosting, click on Properties and scroll down to Static website hosting and click on Edit. Select Enable under Static website hosting. Under Hosting type select Host a static website. Within the Index document type in the name of the document that you want to load when the client hit the URL. Additionally, you can also modify the Error document.

![Static site config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2dkmpoyzp1f7t0kq9tmv.png)

After the above configuration, you will be able to locate the URL under the **Bucket website endpoint**. As a next step, we will try to load the web application and as a result, we received _403 Forbidden_. The reason for not being able to load the site successfully is the objects in the S3 bucket are not publically readable. And to make the objects in the bucket publically readable, we have to write the bucket policy to grant s3:GetObject permission. To add a bucket policy, click on Permissions → scroll down to Bucket policy → click on Edit and copy/paste the below policy and update the resource accordingly.

```
{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "AllowGetObj",
   "Effect": "Allow",
   "Principal": "*",
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::your-bucket-name/*"
  }
 ]
}
```
The above policy will allow everyone on the internet to read objects and anyone on the internet can access the web application using the URL.

Now, if you load the site using the URL then it should be accessible. But, we want to limit the access to the number of IP addresses that we whitelist and for that, you have to add a condition to the allow statement above to define when should the allow statement should come into effect. The overall policy will look like the below.

```
{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "AllowGetObj",
   "Effect": "Allow",
   "Principal": "*",
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::static-website-host-demo-video/*",
   "Condition": {
    "IpAddress": {
     "aws:SourceIp": ["0.0.0.0"]
    }
   }
  }
 ]
}
```
Replace 0.0.0.0 with the list of IP addresses that you want to whitelist. Now, the site is only accessible to the traffic originating from the whitelisted IP addresses in the policy.

Till now, everything is working fine but there is an issue. The problem is that there is always a possibility of unintended or accidental access. For example, some other policies or another allow statement might end up granting additional permissions which are unintended. So, to prevent such a scenario, add a deny statement in conjunction with the allow statement. And the overall policy will look like the below.

```
{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "AllowGetObj",
   "Effect": "Allow",
   "Principal": "*",
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::static-website-host-demo-video/*",
   "Condition": {
    "IpAddress": {
     "aws:SourceIp": "0.0.0.0"
    }
   }
  },
  {
   "Sid": "DenyGetObj",
   "Effect": "Deny",
   "Principal": "*",
   "Action": "s3:GetObject",
   "Resource": "arn:aws:s3:::static-website-host-demo-video/*",
   "Condition": {
    "NotIpAddress": {
     "aws:SourceIp": [
      "0.0.0.0"
     ]
    }
   }
  }
 ]
}
```
The deny statement states that, deny the action, s3:GetObject to everyone, to the objects of defined resource (S3 bucket) for all the traffic except for the origin IP addresses which are mentioned as a part of the condition. And here we have a negate condition that is NotIPAddress.

Add the IP addresses in the conditions that you want to whitelist. Ideally, you can remove the condition from the Allow statement since there is a condition in the Deny statement which will validate the origin IP address.

Note: While you update the bucket policy, you need to be cautious about losing access to yourself. So, please be mindful of that and whitelist your userId as a part of the policy.

For a detailed step-by-step tutorial, implementation and if you want to learn about how the policy evaluation took place, you can refer to the below video.

{% embed https://youtu.be/NO9tVuqSeUc %}

If you have any questions, comment, feedback then please leave them below. [Subscribe to my channel](https://www.youtube.com/srcecde?sub_confirmation=1) for more.