要求是通过AWS SDK限制IAM用户访问S3存储桶中的特定子文件夹。通过AWS控制台配置用户策略要容易得多,但是当使用AWS SDK将其转换为Java代码时我失败了。
例如,我希望IAM用户只能访问'mybucket'存储桶中的'subfolder1'文件夹。 以下是可与AWS控制台完美配合的用户策略: (解决方案本身请参考我在AWS控制台中成功验证的here)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": [
"arn:aws:s3:::*"
]
},
{
"Sid": "2",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::mybucket"
],
"Condition": {
"StringEquals": {
"s3:prefix": [
"",
"subfolder1/"
],
"s3:delimiter": [
"/"
]
}
}
},
{
"Sid": "3",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::mybucket/subfolder1/*"
]
}
]
}
以下是生成上述政策的java代码段。
// Attach the required permission user policy to the new user
// 1. Permission to list all the buckets (view)
final Statement allowListStatement = new Statement(Effect.Allow)
.withActions(
S3Actions.ListBuckets,
S3Actions.GetBucketLocation
)
.withResources(new Resource("arn:aws:s3:::*"));
// 2. Permission to list the objects within the bucket
final String dq = (char)(34) + "";
final String prefix = dq + dq + "," + dq + "subfolder1/" + dq;
final Statement allowBucketListStatement = new Statement(Effect.Allow)
.withActions(
S3Actions.ListObjects
)
.withResources(
new S3BucketResource(bucketName)
)
.withConditions(
new StringCondition(
StringComparisonType.StringEquals,
S3ConditionFactory.PREFIX_CONDITION_KEY,
prefix
),
new StringCondition(
StringComparisonType.StringEquals,
S3ConditionFactory.DELIMITER_CONDITION_KEY,
"/"
)
);
// 3. Permission to update the bucket content
final Statement allowBucketOperationsStatement = new Statement(Effect.Allow)
.withActions(
S3Actions.PutObject,
S3Actions.GetObject,
S3Actions.DeleteObject
)
.withResources(
new S3ObjectResource(
bucketName,
usernameIAM + "/*"
)
);
final Policy policy = new Policy()
.withStatements(
allowListStatement,
allowBucketListStatement,
allowBucketOperationsStatement
);
final PutUserPolicyRequest policyRequest = new PutUserPolicyRequest(
usernameIAM,
"policy_subfolder1",
policy.toJson()
);
client.putUserPolicy(policyRequest);
问题发生在'withConditions'行中(除此行外,所有其他策略行都正确生成)。
预期的行将是这样的(在AWS控制台中可以正常工作):
"Condition":{"StringEquals":{"s3:prefix":["","subfolder1/"], "s3:delimiter":["/"]}}
但实际生成的行是这样的:
"Condition":{"StringEquals":{"s3:prefix":["\"\",\"subfolder1/\""], "s3:delimiter":["/"]}}
令人奇怪的是,AWS SDK无法在语句中正确解析双引号(“):所有双引号(”)都被解析为(\“)。
'前缀'定义似乎很奇怪。在我的原始代码中,我使用了这个:
final String prefix = "\"\",\"" + usernameIAM + "/\"";
但这会产生与我目前的方法相同的问题(使用dq ascii代码)。
我不确定它是否是AWS SDK的错误。任何人都可以解决这个问题吗?或者任何其他方法或建议来实现我的要求(但必须使用SDK)?
答案 0 :(得分:2)
感谢user2864740的建议。在此,我只是发布我对这个问题的回答。希望其他人可能更容易找到。 正如user2864740指出的那样,API期望值而不是“手动JSON文本”,双引号(“)将使用转义格式(\”)进行解析。
解决方案是将StringCondition拆分为不同的部分,而不是手动生成JSON字符串。这是最终可行的解决方案:
final String prefix1 = "";
final String prefix2 = "subfolder1/";
final Statement allowBucketListStatement = new Statement(Effect.Allow)
.withActions(
S3Actions.ListObjects
)
.withResources(
new S3BucketResource(bucketName)
)
.withConditions(
new StringCondition(
StringComparisonType.StringEquals,
S3ConditionFactory.PREFIX_CONDITION_KEY,
prefix1
),
new StringCondition(
StringComparisonType.StringEquals,
S3ConditionFactory.PREFIX_CONDITION_KEY,
prefix2
),
new StringCondition(
StringComparisonType.StringEquals,
S3ConditionFactory.DELIMITER_CONDITION_KEY,
"/"
)
);