【问题标题】:Cognito Identity Pools - Attribute-based access control with "dynamic" attributesCognito Identity Pools - 具有“动态”属性的基于属性的访问控制
【发布时间】:2022-02-09 19:02:08
【问题描述】:

我在 Cognito 用户池中有数百个 S3 存储桶和数十个用户。我希望能够选择哪个用户可以访问哪个 S3 存储桶,例如:

  • user_a可以访问bucket_1bucket_2bucket_3
  • user_b可以访问bucket_2
  • user_c可以访问bucket_1bucket_4

等等。

我希望能够在不创建用于创建动态策略的专用 API 的情况下做到这一点。我考虑过利用 Cognito 身份池和基于属性的访问控制。

is a cool example 中,用户获得属性"department": "legal",然后被分配一个角色,该角色仅允许查询带有-legalsuffix 的存储桶,这要归功于${aws:PrincipalTag/department} 魔法。

如果我的用户只访问一个存储桶,那将是一个解决方案。 但是,在我的例子中,一个用户可能会被分配到数十个或数百个存储桶(想想 AWS 文档示例中的“多个部门”)。

我想过对每个用户使用多个自定义属性:

  • bucket_1: true
  • bucket_2: false
  • bucket_3: false
  • ..等等

并创建一个策略,当且仅当您具有属性 bucket_n: true 时才允许您访问给定的 bucket_n

如果我最多有 50 个存储桶(Cognito 中自定义属性的硬性限制),这将起作用。

就我而言,这个值略高(几百)。我可以让用户访问 200 多个存储桶,也可以让用户只允许访问一个存储桶。

有什么方法可以通过 Cognito 身份池和 IAM 策略实现我的目标?

【问题讨论】:

标签: amazon-web-services amazon-s3 amazon-cognito amazon-iam


【解决方案1】:

嗯,我找到了一个可能对你们中的某些人有用的“解决方法”。

首先,转到 Cognito 用户池并创建一个您选择的自定义属性,该属性将包含您的所有值。请记住,Cognito 的属性值限制为 2048 个字符。

我们称该属性为attribute_groups。将所有值作为带有您选择的分隔符的字符串放在那里。在我的情况下,user1 带有属性custom:attribute_groups = "123o789" 意味着user1 在逻辑上属于123789 组。

映射这些属性in Cognito Identity Pools。按照示例主体的标记键groups 将从属性名称中选择:custom:attribute_groups

最后,设置用户池中经过身份验证的用户所采用的 IAM 策略,如下所示。就我而言,我想允许群组123 列出s3://my_bucket/123456 列出s3://my_bucket/456 等等。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my_bucket"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "123/*"
                    ],
                    "aws:PrincipalTag/groups": [
                        "*123*"
                    ]
                }
            }
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my_bucket"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "456/*"
                    ],
                    "aws:PrincipalTag/groups": [
                        "*456*"
                    ]
                }
            }
        },
        {
            "Sid": "3",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my_bucket"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "789/*"
                    ],
                    "aws:PrincipalTag/groups": [
                        "*789*"
                    ]
                }
            }
        }
    ]
}

完成我的示例 - 当user1 获得他们的凭据时(您可以通过创建用户、设置其属性然后执行aws cognito-idp initiate-auth 来获取ID token,然后通过aws cognito-identity get-id 获取identity 来测试它最后aws cognito-identity get-credentials-for-identity 获取访问密钥ID/秘密访问密钥/会话令牌),他们可以执行aws s3 ls s3://my_bucket/123aws s3 ls s3://my_bucket/789

很遗憾,这仍然受到以下因素的严重限制:

  • IAM 政策字符数限制 (10240)
  • Cognito 自定义属性长度限制 (2048)

通过这种精细的 IAM 策略,您最多可以拥有 15-20 个“组”。

您可能会以某种方式通过创建多个策略和多个(“假”)Cognito 用户池组来反击,让每个用户都附加到每个组,然后使用 ID token 中的 cognito:roles 属性遍历这些组并假设这些角色使用GetCredentialForIdentity,允许您设置CustomRoleArn。它可以工作(我已经检查过),但真的很hacky。

但是,有一个技巧可以将 Cognito 功能扩展到你们中的某些人并摆脱这个限制。要求是目录的结构是可预测的,并且您不需要访问子目录。我们将使用${s3:prefix} 也是一个变量这一事实。

如果是这样,您的政策可能如下所示:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my_bucket"
            ],
            "Condition": {
                "StringLike": {
                    "aws:PrincipalTag/groups": [
                        "*${s3:prefix}*"
                    ]
                }
            }
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::my_bucket/${s3:prefix}/*"
            ],
            "Condition": {
                "StringLike": {
                    "aws:PrincipalTag/groups": [
                        "*${s3:prefix}*"
                    ]
                }
            }
        }
    ]
}

然后在custom:attribute_groups 中,您必须指定给定用户有权访问的所有前缀(即所有目录)。请注意,不允许他们访问这些目录的子目录,因为 ${s3:prefix} 会有所不同。

例如,用户:

custom:attribute_groups = directoryA####directoryA/subdirectoryAA####directoryC/subdirectoryCA/subsubdirectoryCAA

将被允许访问以下位置的文件:

  • my_bucket/directoryA
  • my_bucket/directoryA/subdirectoryAA
  • my_bucket/directoryC/subdirectoryCA/subsubdirectoryCAA

并且没有其他(子)目录directoryA/subdirectoryAB 无法访问,尽管 directoryA 是。

当然,每个属性最多可以容纳 2048 个字符。但是您可以在 Cognito 中创建多达 50 个自定义属性并相应地扩展您的策略。我认为这对于大多数传统用例来说应该足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-16
    • 2015-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 2022-01-08
    • 2013-07-12
    相关资源
    最近更新 更多