Correct way to block unsecured access

0

We're trying to lock things down on our S3 buckets, and I'm running into a weird error. When my policy looks like this:

    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::000:user/username"
        },
        "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:DeleteObject",
            "s3:ListBucket"
        ],
        "Resource": [
            "arn:aws:s3:::bucketname",
            "arn:aws:s3:::bucketname/*"
        ]
    },
    {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:*",
        "Resource": [
            "arn:aws:s3:::bucketname",
            "arn:aws:s3:::bucketname/*"
        ],
        "Condition": {
            "Bool": {
                "aws:SecureTransport": "false"
            }
        }
    }

I get an error saying:

User: arn:aws:iam::000:user/username is not authorized to perform: s3:ListBucket on resource: "arn:aws:s3:::bucketname" with an explicit deny in a resource-based policy

If I remove the Deny part it starts working again.

What is the right way to do this?

4 Answers
1
Accepted Answer

Hello.

I have tried accessing the bucket using the following bucket policy in my AWS account:
It has been confirmed that access is possible normally if you access via HTTPS.
I don't know how you are accessing S3, but it's possible that you are not accessing it via HTTPS when executing "s3:ListBucket".

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:user/test"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ]
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::bucket-name",
                "arn:aws:s3:::bucket-name/*"
            ],
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        }
    ]
}
profile picture
EXPERT
answered 25 days ago
profile pictureAWS
EXPERT
reviewed 19 days ago
  • Yes, apparently I missed putting in a useHttp=false and it was trying to connect insecurely... 🤦‍♂️Thanks for the reply!

1

Your policy looks correct, therefore, it could be related to how you calling the S3 API. From command line or your code, make sure you are not passing the --no-verify-ssl flag. For example,

aws s3 ls s3://bucketname --endpoint-url https://s3.amazonaws.com

Optionally, if you want to make an exception for this user, you can add it to the policy as shown below.

{
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
        "arn:aws:s3:::bucketname",
        "arn:aws:s3:::bucketname/*"
    ],
    "Condition": {
        "Bool": {
            "aws:SecureTransport": "false"
        },
        "StringNotEquals": {
            "aws:PrincipalArn": "arn:aws:iam::000:user/username"
        }
    }
}

answered 25 days ago
  • Yeah, apparently I made a mistake and it was trying to access insecurely. At least I know that the policy is effective at denying insecure access, so it wasn't total waste of time. Thanks for the policy tips, I'm still learning how those all work.

0

In all AWS policies, explicit-deny statements are evaluated before explicit-allow, regardless of the order in which they appear in the policy.

That means if any user attempts to connect using an insecure connection, they will be denied by the second statement in your policy. It won't even go on to try and evaluate the first statement (whether the user is equal to arn:aws:iam::000:user/username).

Only if the connection is secure will the first statement be evaluated.

Your error message shows that your connection is in-scope of this explicit deny. As other answers have said, make sure you are using a secure transport protocol. This document may help https://repost.aws/knowledge-center/s3-enforce-modern-tls

Lastly, by removing the "Effect": "Deny" part of the policy, you are reducing the policy to only checking if the principal is arn:aws:iam::000:user/username and not bothering to check the security of the connection beforehand. That's why you don't get an error with the reduced policy.

profile picture
EXPERT
answered 25 days ago
-1

The issue you're encountering is due to the order of evaluation of the policy statements. In S3 bucket policies, an explicit deny always takes precedence over an allow statement. In your case, the "Deny" statement is blocking all non-HTTPS access, including the actions you're trying to allow for your specific user.

To resolve this, you need to modify your policy to allow secure access for your specified user while still denying unsecured access for everyone else. Here's the correct way to structure your policy:

  1. First, include an "Allow" statement for your specific user, ensuring it only applies to HTTPS connections:
{
    "Effect": "Allow",
    "Principal": {
        "AWS": "arn:aws:iam::000:user/username"
    },
    "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
    ],
    "Resource": [
        "arn:aws:s3:::bucketname",
        "arn:aws:s3:::bucketname/*"
    ],
    "Condition": {
        "Bool": {
            "aws:SecureTransport": "true"
        }
    }
}
  1. Then, include a "Deny" statement to block non-HTTPS access for everyone:
{
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
        "arn:aws:s3:::bucketname",
        "arn:aws:s3:::bucketname/*"
    ],
    "Condition": {
        "Bool": {
            "aws:SecureTransport": "false"
        }
    }
}

This configuration ensures that your specified user can perform the allowed actions over HTTPS, while all non-HTTPS access is denied for everyone, including your specified user.

Remember, when working with S3 bucket policies, it's crucial to carefully consider the order and interaction of your policy statements to achieve the desired access control.
Sources
Amazon Simple Storage Service (Amazon S3) controls - AWS Control Tower
Configuring block public access settings for your S3 buckets - Amazon Simple Storage Service

profile picture
answered 25 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions