Using Logical OR statements for S3 bucket policy with multiple statements

Hi folks,

Looking for guidance on how to do an S3 bucket policy with multiple statements that are evaluated as a LOGICAL OR . I knew that multiple conditions in the same statement are “Logical AND” but I thought breaking out a second statement would be evaluated as “Logical OR”. I am obviously wrong though as I locked everyone out of the bucket and now I have to get root creds to unfix my error. Embarassing!

This was the intent:
• Internal developers want to use s3 static website hosting
• The website hosting is for private internal services only that can’t be exposed to the world
• however s3 static hosting requires public read permissions on bucket and objects so …
◦ The idea was to drop a bucket policy in place with two different rules:
◦ Deny access if not coming from one of the known internet egress IPs used by the org
◦ Deny access if not coming from a VPC endpoint of ours
But my policy did not work as expected. Is there a way to clean up or correct something like this?

{
“Version”: “2012-10-17",
“Id”: “111",
“Statement”: [{
“Sid”: “DenyExceptForKnownEgressIPs”,
“Effect”: “Deny”,
“Principal”: “”,
“Action”: “s3:
“,
“Resource”: [
“arn:aws:s3:::redacted-bucket/“,
“arn:aws:s3:::redacted-bucket”
],
“Condition”: {
“NotIpAddress”: {
“aws:SourceIp”: [
“xx.xx.xx.xx/32”,
]
}
}
}, {
“Sid”: “DenyExceptFromVPCendpoint”,
“Effect”: “Deny”,
“Principal”: “
”,
“Action”: “s3:“,
“Resource”: [
“arn:aws:s3:::redacted-bucket/
“,
“arn:aws:s3:::redacted-bucket”
],
“Condition”: {
“StringNotEquals”: {
“aws:SourceVpce”: [
“vpc-xxxxxxx”
]
}
}
}]
}

Why are you using s3:* here? Show us the policy you’d use to allow public read access for the S3 website hosting

Also for the policy you’ve specified the two are a logical OR

If the IP is NOT in the given range OR if the VPC is NOT in the given list

i.e. the user must have a recognised IP AND be in the right VPC

If you want to permit “user must have a recognised IP OR be in the right VPC”

Then you can combine them in one NOT block with a logical AND

“if the IP is NOT in the given range AND if the VPC is NOT in the given list, deny”

Thanks much appreciated. “if the IP is NOT in the given range AND if the VPC is NOT in the given list, deny” … is exactly what I was going for. Sounds like I just need to collapse down to one NOT block with the VPCe and SrcIP statements connected by a local AND

Yes, though be aware that at the moment you’re applying these restrictions to all operations on said bucket, not just viewing

Nested conditionals in policies are new for me so I’m gonna puzzle this out on a test bucket. The goal is really to allow static website hosting of internal apps without making those files reachable from the world via bucket policy restrictions.

If I can’t make this work then plan B is to do Cloudfront + WAF w/ Web-ACL to do the same thing but also allow the users to do HTTPS with a custom domain name

Yeah I’d start by limiting which actions you block. Denying s3:* across the board is probably where you started to go wrong - I imagine your website policy hasn’t allowed s3:* to the world?!

(and yes, always testing complex policies on not-live things makes sense, though I am confused why you required root to fix the issue if you’re able to edit policies)

I”m editing on a new bucket; need root to go back and delete the bad policy on the first one