以编程方式验证 SNS 主题权限以将消息发送到 SQS(使用 IAM?)

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

我目前正在使用 C#,但我相信这个问题在任何 AWS SDK 中都是一样的。

我正在尝试以编程方式验证主题是否可以将消息发送到队列(实际上并不是尝试添加权限,只是检查它是否存在)。

到目前为止,我找到的唯一方法是扫描队列策略以查找与主题 ARN 匹配的语句,即..:

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)))

顺便说一句,这类似于调用 SubscribeQueueAsync 时在 AWS SDK 中完成的方式(请参阅 corresponding code on github)。

我对这种方法的问题是它感觉起来有多脆弱。例如,如果条件有通配符怎么办?如果存在针对特定主体而不是所有主体的授权怎么办?

所以我想我可能会使用 IAM,特别是 SimulatePrincipalPolicy or SimulateCustomPolicy。它们可以用于此吗?

我是这样想的:

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

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

本来可以的,但结果是 Amazon.IdentityManagement.Model.InvalidInputException : Could not extract entity from ARN : arn:aws:sns:eu-west-1:<accountid>:<topicname>

我想这可能与 CallerArn 属性 有关?我注意到发件人帐户 ID 的用户密钥在队列从主题接收的消息中似乎总是相同的 (AIDA******************)。

不确定我正在尝试的是否可行...

开箱即用,您不能使用 SimulatePrincipalPolicy (docs) 检查服务是否具有 IAM 权限:

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.

如果您查看 SimulatePolicyRequest class 的 CallerArn property,您会得到:

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.

我使用 powershell SDK 对此进行了测试 - 它在 .net 上运行并得到了同样的错误。

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

可能的解决方案 该函数确实与 SNS 的 IAM Service Roles. You can create a service role in IAM that delegates 权限一起使用,以将消息发送到 SQS。如果您能够为 SNS 创建服务角色,那么您将能够使用 SimulatePrincipalPolicy 函数。

我在 PS 中再次测试了这个。首先,我在 IAM 控制台中创建了服务角色:

  • 单击左侧菜单中的角色。
  • 单击“创建角色”按钮
  • Select AWS 服务
  • 点击社交网络
  • 它只会展示一个用例 ("Allow SNS to call CloudWatch") - 别担心,我们稍后可以清理它。
  • 点击"Next:Permissions"
  • 点击"Next:Review"
  • 点击"Create Role"

您现在已将某些 CloudWatch 权限委托给 SNS。我们将在几秒钟内删除它,但现在我至少可以调用该函数,传入策略 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}

请注意,EvalDecision 是 implicitDeny。

现在您可以编辑创建的角色。删除Cloudwatch策略,添加相关SQS策略,再次测试:

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

如果您不能t/won设置 SNS 的服务角色,那么我认为唯一的方法就是像您已经完成的那样抓取策略。

更新

经过进一步测试,虽然上面的功能可以正常运行,但实际上我无法让SNS登陆SQS!所以这是一个误报,我认为你又回到了抓取政策的地方。