2

I am attempting to deny public users from accessing signedUrl paths directly, unless it's loaded by my website <img> tag.

Typical users should not allow to copy the image URL directly in the address bar and download the image.

The allow policy

    {
        "Sid": "Allow public with signedUrl",
        "Effect": "Allow",
        "Principal": "*",
        "Action": [
            "s3:GetObject",
            "s3:PutObject"
        ],
        "Resource": "arn:aws:s3:::my-chat-attachments-development/*",
        "Condition": {
            "StringLike": {
                "aws:Referer": [
                    "http://localhost:4000/*",
                    "http://localhost:3000/*",
                    "https://mydomain1/*",
                    "https://mydomain2/*"
                ]
            }
        }
    },

Below explicitly deny public access. Without the following policy, public users can still copy and paste image URL directly in the address bar (undesirable).

    {
        "Sid": "Statement to deny anybody without referrer",
        "Effect": "Deny",
        "NotPrincipal": {
            "AWS": [
                "arn:aws:iam::1234:user/S3UserfullAccess",
                "arn:aws:iam::1234:role/LambdaFullAccess"
            ]
        },
        "Action": [
            "s3:GetObject",
            "s3:PutObject"
        ],
        "Resource": "arn:aws:s3:::my-chat-attachments-development/*",
        "Condition": {
            "StringNotLike": {
                "aws:Referer": [
                    "http://localhost:4000/*",
                    "http://localhost:3000/*",
                    "https://mydomain1/*",
                    "https://mydomain2/*"
                ]
            }
        }
    }

Problem

I have the above policy settings, and it works well (public users are shown a access denied page). However, it also means my lambda, and my nodejs app servers cannot access the S3 even though I added NotPrincipal in the policy.

Please advise how can I correct my policy to achieve my desire behavior.

PS: I do note the above referer hack will not stop technical users from spoofing referring addresses.

Someone Special
  • 12,479
  • 7
  • 45
  • 76
  • To confirm, I think you're saying that the above combination of policy fragments in your S3 bucket policy appears to preventing your Lambda function from accessing this S3 bucket. What IAM policies are associated with the IAM role the Lambda executes with? – jarmod Dec 08 '21 at 14:11
  • LambdaFullAccess and S3Fullaccess on my lambda role. When I remove the DENY policy, I am able to execute my lambda function (to retrieve and put objects in the bucket) – Someone Special Dec 08 '21 at 14:30
  • Right, but those are an IAM user and an IAM role ARN. Your Lambda function is configured with a single role ARN, which is presumably neither of the listed ARNs and hence it's captured by the NotPrincipal. – jarmod Dec 08 '21 at 14:35
  • I think I have found my answer. For the deny policy, I use `"Principal": { "AWS": ["role which generates the signedUrl"]}` In this way, it only denies the images from being access directly but I still can use lambda – Someone Special Dec 08 '21 at 14:36
  • Didn't realise the role is tied to the signedUrl access token. I hope I'm right – Someone Special Dec 08 '21 at 14:37
  • The permissions associated with a signed URL are those of the credentials originally used to sign the URL (typically an IAM user or IAM role). Note in the case of a IAM role, that pre-signed URL is not valid beyond the lifetime of the temporary credentials associated with the assumed IAM role. – jarmod Dec 08 '21 at 14:42
  • You meant the link will expire, am I right? I only need the link to be valid for 1 hour which I will then regenerate new ones . – Someone Special Dec 08 '21 at 15:14
  • 1
    Basically, yes. The pre-signed URL will expire at the earlier of the expiration time you indicated when signing the URL and the expiration of the underlying credentials. If you sign a URL with STS credentials 5 minutes before those credentials expire then the URL will expire in 5 minutes. Also, see https://stackoverflow.com/questions/57791307/s3-signed-urls-expiring-before-argument-passed – jarmod Dec 08 '21 at 15:43
  • Oh, learnt something new. Not to worry, I only used the Lambda to resize images. I signed URL in my nodejs application, with specified IAM role, so I assume I'm safe. – Someone Special Dec 08 '21 at 15:51
  • IAM role => STS credentials => time-limited. As long as you're OK with the expiration time indicated when you invoked AssumeRole, you're ok. – jarmod Dec 08 '21 at 15:52
  • 1
    I will read up on that. Thank you very much @jarmod for sharing these precious info. – Someone Special Dec 08 '21 at 17:27

0 Answers0