9

The client app requests a presigned URL for S3. Currently we limit the time the URL is valid but would like to also restrict it to the client's IP address.

Is it possible to create a S3 presigned URL that is restricted to a specific IP address?

From what I can tell only CloudFront will let me do this.

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
user1604402
  • 101
  • 1
  • 3

1 Answers1

24

Yes!

First, it is worth explaining the concept of a Pre-Signed URL.

Objects in Amazon S3 are private by default. Therefore, if somebody tries to access it without providing credentials, access will be denied.

For example, this would not work for a private object:

https://my-bucket.s3.amazonaws.com/foo.json

To grant temporary access to the object, a Pre-signed URL can be generated. It looks similar to:

https://my-bucket.s3.amazonaws.com/x.json?AWSAccessKeyId=AKIAIVJQM12345CY3A3Q&Expires=1531965074&Signature=g7Jz%2B%2FYyqc%2FDeL1rzo7WM61RusM%3D

The URL says "I am *this* particular Access Key and I authorize temporary access until *this* time and here is my calculated signature to prove it is me".

When the Pre-Signed URL is used, it temporarily uses the permissions of the signing entity to gain access to the object. This means that I can generate a valid pre-signed URL for an object that I am permitted to access, but the pre-signed URL will not work if I am not normally permitted to access the object.

Therefore, to "create a S3 presigned URL that is restricted to a specific IP address", you should:

  • Create an IAM entity (eg IAM User) that has access to the object (or the whole bucket) with a IP address restriction, and
  • Use that entity to generate the pre-signed URL

Here is a sample policy for the IAM User:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "IPAllow",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::my-bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": "54.22.33.44/32"
                }
            }
        }
    ]
}

The result will be a pre-signed URL that works successfully to access the object, but is then rejected by S3 because the IP address restriction is not met. The user will receive an Access Denied message.

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
  • 1
    But what if we what to limit IP address dynamically to the specific end user making the request? – openwonk Aug 31 '19 at 02:12
  • @openwonk Probably by programatically creating the user with ip restriction and generate signed url after switching users – cyril94440 Sep 06 '19 at 15:15
  • @openwonk No, this is not a method for generating a pre-signed URL for a user's specific IP address. The intention with a pre-signed URL is that the time-limit will grant the user temporary access to the object. While that user could Tweet the URL to the world and other people would be able to access the object during that time period, the user could equally just distribute the file to people anyway. So, the assumption is that a time-limit is sufficient protection for most use-cases, without having to further limit the pre-signed URL to a specific IP address. – John Rotenstein Sep 07 '19 at 10:08
  • That was my understanding too. Thanks – openwonk Sep 07 '19 at 20:27
  • @jbooker Pre-signed URLs do not have policies. They simply grant access based upon an existing user's permissions. Think of it like signing a cheque -- as the account owner, you are granting permission for the bearer of the cheque to withdraw money. The cheque does not contain the permission, it simply contains your authorization for access. However, it only grants access to _your_ account. – John Rotenstein Jul 02 '20 at 03:23
  • 1
    To clarify: My proposal does not require the app generating the presigned URL to be "in the same IP". Rather, the app generating the presigned URL merely needs to be using a set of credentials that has a policy that limits what it is allowed to access. The client using the presigned URL will be similarly limited when attempting to access the object. (When generating the presigned URL, the app can use a special set of credentials that has been limited, which might be different to the identity that the app uses for the rest of its operations.) – John Rotenstein Jul 02 '20 at 23:21
  • 1
    @jbooker Yes, I just tested it and it works fine for multiple IP addresses. To specify multiple IP addresses, use the format like shown in [Cloudflare IP Range Whitelist to S3 bucket through CloudFront : aws](https://www.reddit.com/r/aws/comments/bd8m8v/cloudflare_ip_range_whitelist_to_s3_bucket/). I created one user with S3 permissions for 3 IP addresses and created a presigned URL. It worked from those IP addresses, but not others. – John Rotenstein Jul 04 '20 at 04:17
  • Gotcha here worth mentioning: whitelisting at both user policy level and bucket policy level. :/ – Judy007 Jul 07 '20 at 05:21
  • ?? No bucket policy is required for the above to work. – John Rotenstein Jul 07 '20 at 06:29
  • I meant to say, if you whitelist at user policy level and bucket policy level, you will have to maintain TWO sets of white lists. Minor GOTCHA – Judy007 Jul 26 '20 at 01:30