Cognito 身份池 - 具有 "dynamic" 个属性的基于属性的访问控制
Cognito Identity Pools - Attribute-based access control with "dynamic" attributes
我在 Cognito 用户池中有数百个 S3 存储桶和数十个用户。我希望能够 select 哪个用户可以访问哪个 S3 存储桶,例如:
user_a
可以访问 bucket_1
、bucket_2
、bucket_3
user_b
可以访问 bucket_2
user_c
可以访问 bucket_1
, bucket_4
等等。
我希望能够在不创建专用 API 创建动态策略的情况下做到这一点。我考虑过使用 Cognito 身份池和基于属性的访问控制。
那里 is a cool example 用户获得属性 "department": "legal"
然后被分配一个角色,允许只查询带有 -legal
后缀的桶,感谢 ${aws:PrincipalTag/department}
魔法.
如果我的用户只能访问一个存储桶,那将是一种解决方案。 但是,在我的例子中,一个用户可能会被分配到数十个或数百个存储桶(想想 AWS 文档示例中的“多个部门”)。
我想到了对每个用户使用多个自定义属性:
bucket_1: true
bucket_2: false
bucket_3: false
- ..等等
并创建允许您访问给定 bucket_n
当且仅当您具有属性 bucket_n: true
.
的策略
如果我最多有 50 个存储桶(Cognito 中自定义属性的硬限制),这将有效。
在我的例子中,这个值略高(几百)。我可以让用户访问 200 多个存储桶,也可以让用户只允许访问一个存储桶。
有什么方法可以通过 Cognito 身份池和 IAM 策略实现我的目标吗?
好吧,我找到了一个可能对你们中的某些人有用的“解决方法”。
首先,转到 Cognito 用户池并创建一个您选择的自定义属性来保存您的所有值。请记住,Cognito 的属性值限制为 2048 个字符。
我们称该属性为 attribute_groups
。将所有值作为一个字符串放在那里,并带有您选择的分隔符。在我的例子中 user1
属性 custom:attribute_groups = "123o789"
意味着 user1
在逻辑上属于组 123
和 789
.
映射这些属性 in Cognito Identity Pools。按照示例 主体 的标签键:groups
将从 属性名称 中选择:custom:attribute_groups
.
最后,设置您在用户池中经过身份验证的用户采用的 IAM 策略,如下所示。就我而言,我想允许组 123
列出 s3://my_bucket/123
,456
列出 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/secret 访问 key/session 令牌),他们可以执行 aws s3 ls s3://my_bucket/123
和 aws s3 ls s3://my_bucket/789
.
不幸的是,这仍然受到严重限制:
- IAM 策略字符限制 (10240)
- Cognito 自定义属性长度限制 (2048)
使用如此精细的 IAM 策略,您最多可以拥有 15-20 个“组”。
您可以通过创建多个策略和多个(“假的”)Cognito 用户池组来以某种方式反击,让每个用户附加到每个组,然后使用 cognito:roles
属性遍历这些组 ID token
并使用允许您设置 CustomRoleArn
的 GetCredentialForIdentity 承担这些角色。它有效(我已经检查过),但真的很笨拙。
但是,有一个技巧可以将 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 个自定义属性并相应地扩展您的策略。我认为这对于大多数常规用例来说应该足够了。
我在 Cognito 用户池中有数百个 S3 存储桶和数十个用户。我希望能够 select 哪个用户可以访问哪个 S3 存储桶,例如:
user_a
可以访问bucket_1
、bucket_2
、bucket_3
user_b
可以访问bucket_2
user_c
可以访问bucket_1
,bucket_4
等等。
我希望能够在不创建专用 API 创建动态策略的情况下做到这一点。我考虑过使用 Cognito 身份池和基于属性的访问控制。
那里 is a cool example 用户获得属性 "department": "legal"
然后被分配一个角色,允许只查询带有 -legal
后缀的桶,感谢 ${aws:PrincipalTag/department}
魔法.
如果我的用户只能访问一个存储桶,那将是一种解决方案。 但是,在我的例子中,一个用户可能会被分配到数十个或数百个存储桶(想想 AWS 文档示例中的“多个部门”)。
我想到了对每个用户使用多个自定义属性:
bucket_1: true
bucket_2: false
bucket_3: false
- ..等等
并创建允许您访问给定 bucket_n
当且仅当您具有属性 bucket_n: true
.
如果我最多有 50 个存储桶(Cognito 中自定义属性的硬限制),这将有效。
在我的例子中,这个值略高(几百)。我可以让用户访问 200 多个存储桶,也可以让用户只允许访问一个存储桶。
有什么方法可以通过 Cognito 身份池和 IAM 策略实现我的目标吗?
好吧,我找到了一个可能对你们中的某些人有用的“解决方法”。
首先,转到 Cognito 用户池并创建一个您选择的自定义属性来保存您的所有值。请记住,Cognito 的属性值限制为 2048 个字符。
我们称该属性为 attribute_groups
。将所有值作为一个字符串放在那里,并带有您选择的分隔符。在我的例子中 user1
属性 custom:attribute_groups = "123o789"
意味着 user1
在逻辑上属于组 123
和 789
.
映射这些属性 in Cognito Identity Pools。按照示例 主体 的标签键:groups
将从 属性名称 中选择:custom:attribute_groups
.
最后,设置您在用户池中经过身份验证的用户采用的 IAM 策略,如下所示。就我而言,我想允许组 123
列出 s3://my_bucket/123
,456
列出 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/secret 访问 key/session 令牌),他们可以执行 aws s3 ls s3://my_bucket/123
和 aws s3 ls s3://my_bucket/789
.
不幸的是,这仍然受到严重限制:
- IAM 策略字符限制 (10240)
- Cognito 自定义属性长度限制 (2048)
使用如此精细的 IAM 策略,您最多可以拥有 15-20 个“组”。
您可以通过创建多个策略和多个(“假的”)Cognito 用户池组来以某种方式反击,让每个用户附加到每个组,然后使用 cognito:roles
属性遍历这些组 ID token
并使用允许您设置 CustomRoleArn
的 GetCredentialForIdentity 承担这些角色。它有效(我已经检查过),但真的很笨拙。
但是,有一个技巧可以将 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 个自定义属性并相应地扩展您的策略。我认为这对于大多数常规用例来说应该足够了。