目标:通过cognito userpool + identitypool为一个用户分配一个自定义属性:tenantId访问他自己在S3中的桶文件夹:S3://[tenantId]/*
我配置:
- 一个带有客户属性tenantId的用户池,并赋予应用客户端对该属性的读权限
- 附加身份池
- 创建一个角色,并将其附加到身份池
通过登录页面,我已经检索了一个有效的idToken,并给定该idToken,我执行以下代码(简化的示例,没有错误处理等):
const REGION = '...';
const USERPOOLID = '...';
const IDENTITYPOOLID = '...';
const BUCKET = '...';
const KEY = '...';
const TEST_JWT_ID_TOKEN = 'xxx.yyy.zzz';
AWS = require('aws-sdk');
AWS.config.region = REGION;
const cognitoIdentityObj = {
IdentityPoolId: IDENTITYPOOLID,
Logins : {
[`cognito-idp.${REGION}.amazonaws.com/${USERPOOLID}`]: TEST_JWT_ID_TOKEN
},
};
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoIdentityObj);
AWS.config.credentials.get(function (err) {
if (!err) {
const accessKeyId = AWS.config.credentials.accessKeyId;
const secretAccessKey = AWS.config.credentials.secretAccessKey;
const sessionToken = AWS.config.credentials.sessionToken;
if (accessKeyId && secretAccessKey && sessionToken) {
const AWS_S3 = new AWS.S3({accessKeyId, secretAccessKey, sessionToken});
const params = {
Bucket: BUCKET,
Key : KEY
};
AWS_S3.getObject(params, function (err, data) {
if (err) {
// err is an Access Denied
console.error(err);
} else {
console.log(data);
}
})
}
}
})
TEST_JWT_ID_TOKEN包含一个有效的ID Token,并且在登录时通过身份池将用户附加到一个角色。该角色具有以下定义的策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::<BUCKET>/${cognito-identity.amazonaws.com:custom:tenantId}/*"
]
}
]
}
然而,当我试图从该桶中读取时,我得到访问拒绝,在策略中添加资源行,如下所示:
arn:aws:s3:::<BUCKET>/*
做到了这一点,所以我相当确定用户池、身份池、角色和策略的整个设置都在工作。然而,属性:${cognitatoidentity.amazonaws.com:custom:tenantId}似乎没有被识别/不评估或…
那么,您需要的是在IAM Authenticated Role策略上添加策略条件,并限制s3策略上的主体访问。查看Amazon S3可用的条件键操作、资源和条件键。在这种情况下,我使用前缀键,在另一种情况下,我将使用ExistingObjectTag。
我从来不知道"认知身份"这个词。在我的项目中,我使用的是"cognito-identity.amazonaws.com:sub"对于身份角色id reference和& cognita-identity.amazonaws.com:aud">
对于IAM Authenticated Role策略,我将语句写入如下:
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Condition": {
"StringLike": {
"s3:prefix": ["${cognito-identity.amazonaws.com:sub}"]
}
},
"Resource": "arn:aws:s3:::<BUCKET_NAME>"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": ["arn:aws:s3:::<BUCKET_NAME>/${cognito-identity.amazonaws.com:sub}/*"]
}
]
在s3策略上,我将只限制已验证角色的主体访问:
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": <IAM_AUTH_ROLE_ARN>
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::<BUCKET_NAME>"
},
{
"Effect": "Allow",
"Principal": {
"AWS": <IAM_AUTH_ROLE_ARN>
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<BUCKET_NAME>/*"
}
]
官方文档Amazon S3:允许Amazon Cognito用户访问其bucket中的对象
这里有一篇很好的文章,解释了如何使用自定义认知属性来限制对桶前缀的访问。
https://www.chaosgears.com/post/enabling-amazon-cognito-identity-pools-and-aws-iam-to-perform-attribute-based-access-control访问控制的属性可以映射到您的自定义认知属性,然后可以通过AWS IAM作为IAM策略变量${AWS:PrincipalTag/tenantId}调用。然后使用s3前缀挑战策略变量。因此,s3前缀由tenantId分隔(即-在s3存储桶中,每个租户都有单独的文件夹(前缀))。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::BUCKET-NAME/*"
],
"Condition": {
"ForAnyValue:StringEquals": {
"aws:PrincipalTag/tenantId": "${s3:prefix}"
}
}
}
]
}