简体   繁体   中英

Programmatically verify SNS topic permission to send messages to SQS (using IAM?)

I am currently working in C# but I believe that the issue would be the same in any AWS SDK.

I'm trying to verify programmatically that a topic can send messages to a queue (not actually trying to add the permission, just checking that it's there).

So far the only way I found is by scanning the queue policy for statements that match the topic ARN, ie.:

policy.Statements.Any(
    statement =>
        statement.Effect == Statement.StatementEffect.Allow
        && statement.Principals.Any(
            principal => string.Equals(
                principal.Id,
                Principal.AllUsers.Id,
                StringComparison.OrdinalIgnoreCase))
        && statement.Actions.Any(
            identifier => string.Equals(
                identifier.ActionName,
                SQSActionIdentifiers.SendMessage.ActionName,
                StringComparison.OrdinalIgnoreCase))
        && statement.Resources.Any(resource => resource.Id == queueArn)
        && statement.Conditions.Any(
            condition =>
                (string.Equals(
                     condition.Type,
                     ConditionFactory.StringComparisonType.StringLike.ToString(),
                     StringComparison.OrdinalIgnoreCase)
                 || string.Equals(
                     condition.Type,
                     ConditionFactory.StringComparisonType.StringEquals.ToString(),
                     StringComparison.OrdinalIgnoreCase)
                 || string.Equals(
                     condition.Type,
                     ConditionFactory.ArnComparisonType.ArnEquals.ToString(),
                     StringComparison.OrdinalIgnoreCase)
                 || string.Equals(
                     condition.Type,
                     ConditionFactory.ArnComparisonType.ArnLike.ToString(),
                     StringComparison.OrdinalIgnoreCase))
                && string.Equals(
                    condition.ConditionKey,
                    ConditionFactory.SOURCE_ARN_CONDITION_KEY,
                    StringComparison.OrdinalIgnoreCase)
                && condition.Values.Contains(topicArn)))

This is by the way similar to how it's done in the AWS SDK when calling SubscribeQueueAsync (see corresponding code on github ).

My issue with this method is how brittle it feels. For instance what if the condition has wildcard(s)? What if an authorization exists for specific principals instead of all?

So I thought I'd maybe use IAM, specifically SimulatePrincipalPolicy or SimulateCustomPolicy . Can they be used for that?

I thought something like this:

var simulatePrincipalPolicyRequest = new SimulatePrincipalPolicyRequest
{
    ActionNames = { SQSActionIdentifiers.SendMessage.ActionName },
    ResourceArns = { queueArn },
    PolicySourceArn = topicArn
};

var response = await _iamService.SimulatePrincipalPolicyAsync(
    request: simulatePrincipalPolicyRequest,
    cancellationToken: cancellationToken);

Would have worked but I'm getting Amazon.IdentityManagement.Model.InvalidInputException : Could not extract entity from ARN : arn:aws:sns:eu-west-1:<accountid>:<topicname> as a result.

I thought maybe it had to do with the CallerArn property? I've noticed that the user key that the sender account id seems to be always the same in the messages a queue receives from a topic (AIDA*****************).

Not sure if what I'm trying is possible...

Out of the box, you can't use SimulatePrincipalPolicy ( docs ) to check if a service has an IAM permission:

The entity can be an IAM user, group, or role. If you specify a user, then the simulation also includes all of the policies that are attached to groups that the user belongs to.

If you look at the CallerArn property of the SimulatePolicyRequest class you get:

You can specify only the ARN of an IAM user. You cannot specify the ARN of an assumed role, federated user, or a service principal.

I tested this using powershell SDK - which runs over the .net one and got the same error.

Test-IAMPrincipalPolicy -ActionName 'sqs:SendMessage' -PolicySourceArn arn:aws:sns:::sim-test -ResourceArn arn:aws:sqs:::sim-test

Test-IAMPrincipalPolicy : Could not extract entity from ARN : arn:aws:sns:::sim-test

Possible Solution The function does work with IAM Service Roles . You can create a service role in IAM that delegates permission to SNS to send messages to SQS. If you are in a position to create a service role for SNS, then you will be able to use the SimulatePrincipalPolicy function.

I tested this in PS again. First I created the service role in IAM console:

  • Click on Roles in the left hand menu.
  • Click Create Role button
  • Select AWS service
  • Click SNS
  • It will only present one use case ("Allow SNS to call CloudWatch") - don't worry about this we can clean it up later.
  • Click "Next:Permissions"
  • Click "Next:Review"
  • Click "Create Role"

You have now delegated some CloudWatch permission to SNS. We will remove this in a sec, but for now I can at least call the function, passing in the policy ARN:

Test-IAMPrincipalPolicy -ActionName 'sqs:SendMessage' -PolicySourceArn arn:aws:iam:::role/sim-test-servicerole -ResourceArn arn:aws:sqs:::sim-test

EvalActionName              : sqs:SendMessage
EvalDecision                : implicitDeny
EvalDecisionDetails         : {}
EvalResourceName            : arn:aws:sqs:::sim-test
MatchedStatements           : {}
MissingContextValues        : {}
OrganizationsDecisionDetail :
ResourceSpecificResults     : {arn:aws:sqs:::sim-test}

Note that the EvalDecision is implicitDeny.

Now you can edit the created role. Delete the Cloudwatch policy and add the relevant SQS policy and test again:

EvalActionName              : sqs:SendMessage
EvalDecision                : allowed
EvalDecisionDetails         : {}
EvalResourceName            : arn:aws:sqs:::sim-test
MatchedStatements           : {AmazonSQSFullAccess}
MissingContextValues        : {}
OrganizationsDecisionDetail :
ResourceSpecificResults     : {arn:aws:sqs:::sim-test}

If you can't/won't setup the service role for SNS then I think the only way is to scrape the policy as you have already done.

Update

After further testing, even though the above gets the function to work, I can't actually get the SNS to land in SQS! So it's a false positive, and I think you are back to scraping the policy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM