Thanks to visit codestin.com
Credit goes to github.com

Skip to content

AccessDenied error with IAM auth enabled and valid policy #9581

@BrandonLWhite

Description

@BrandonLWhite

When using Moto with IAM authorization enabled, AccessDenied errors are produced in situations where they should be allowed. The particular scenario that this bug report pertains to is due to the default behavior when BaseResponse._determine_resource is not implemented for a particular resource (which seems to be just about all of them).

Here is a script that reproduces the issue using an SQS queue.

import json
import boto3
from moto import mock_aws
from moto.core import enable_iam_authentication


@mock_aws
def test_moto_arn_matching_bug():
    sqs = boto3.resource("sqs")
    queue = sqs.create_queue(QueueName="test-queue")
    queue_arn = queue.attributes['QueueArn']

    iam = boto3.client("iam")
    role_arn = iam.create_role(
        RoleName="test-role",
        AssumeRolePolicyDocument=json.dumps(dict(
            Version="2012-10-17",
            Statement=[
                dict(Effect="Allow", Principal=dict(AWS="*"), Action="sts:AssumeRole")
            ]
        ))
    )["Role"]["Arn"]

    policy_arn = iam.create_policy(
        PolicyName="test-policy",
        PolicyDocument=json.dumps(dict(
            Version="2012-10-17",
            Statement=[
                dict(Effect="Allow", Action="sqs:*", Resource=queue_arn)
            ]
        ))
    )["Policy"]["Arn"]

    iam.attach_role_policy(
        RoleName="test-role",
        PolicyArn=policy_arn
    )

    sts = boto3.client("sts")
    crendentials = sts.assume_role(RoleArn=role_arn, RoleSessionName="test-session")["Credentials"]

    with enable_iam_authentication():
        restriced_session = boto3.Session(aws_access_key_id=crendentials["AccessKeyId"],
                                          aws_secret_access_key=crendentials["SecretAccessKey"],
                                          aws_session_token=crendentials["SessionToken"])
        restricted_queue = restriced_session.resource("sqs").Queue(queue.url)
        restricted_queue.send_message(MessageBody="Test message with IAM auth")


if __name__ == "__main__":
    test_moto_arn_matching_bug()

The final call to restricted_queue.send_message should succeed, but instead fails with AccessDenied. The behavior is such that the Allow policy does not match the queue's ARN.

This is because of the code in BaseResponse.call_action

    def call_action(self) -> TYPE_RESPONSE:
        headers = self.response_headers
        if hasattr(self, "_determine_resource"):
            resource = self._determine_resource()
        else:
            resource = "*"

This causes the resource to default to * which does not match the Allowed ARN in the policy.

I suspect that _determine_resource needs to be implemented for all BaseResponse child classes in order to address this problem.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions