在AWS S3中为权限指定IAM角色

时间:2015-06-23 23:08:28

标签: python amazon-web-services amazon-s3 boto amazon-cognito

我试图将所有AWS Cognito用户限制在我的S3存储桶中他们自己的子目录中。

我不希望他们在我的大桶中列出,阅读或写下其他人的子目录/文件,我只希望他们阅读和阅读。在自己的目录中写入对象。

我吸取灵感from this AWS documentation snippet

这是我的政策:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "subfolder/"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket/subfolder/${cognito-identity.amazonaws.com:sub}",
                "arn:aws:s3:::my-bucket/subfolder/${cognito-identity.amazonaws.com:sub}/*"
            ]
        }
    ]
}

我的代码用user_id = test@test.com检索某个用户的文件,但实际上允许我检索受限制的文件:

import boto

# These keys are *not* hardcoded, I'm just leaving out
# the auth flow to get them from Cognito/STS as described 
# here: https://mobile.awsblog.com/post/Tx2FL1QAPDE0UAH/Understanding-Amazon-Cognito-Authentication-Part-2-Developer-Authenticated-Ident
conn = boto.s3.connect_to_region('us-east-1',
    aws_access_key_id=ACCESS_KEY_FROM_COGNITO,
    aws_secret_access_key=SECRET_KEY_FROM_COGNITO,
    security_token=SECURITY_KEY_FROM_COGNITO)

# get the bucket
b = conn.get_bucket('my-bucket', validate=False)

# try to get an object we SHOULD be able to get
k = Key(b)
k.key = 'subfolder/us-east-1:xxxx-xxxx-xxxx-xxxxxxxxx/foobar'
print "Contents:", k.get_contents_as_string()  # success!

# try to get and object we SHOUDN'T be able to get
k2 = Key(b)
k2.key = 'subfolder/BLAH_BLAH/restricted'
print "Contents:", k2.get_contents_as_string()  # should fail, but doesn't

不幸的是,我可以访问和阅读这两个文件的内容,但我在AWS博客文档文章中遵循完全相同的模式。我也不确定为什么我需要boto连接中的validate=False,但它似乎运行得很好。

我错过了什么?

编辑:在回答下面的答案时,我已尝试将我的角色更新为以下内容,但它没有任何区别:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "subfolder/${cognito-identity.amazonaws.com:sub}/*"
                    ]
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket/subfolder/${cognito-identity.amazonaws.com:sub}/*"
            ]
        }
    ]
}

我还确认我使用的访问凭据来自Cognito,使用从使用Cognito令牌创建boto {{1对象和查询我的角色名称对应于我的身份池的身份验证用户。在这样做时,我在尝试阅读此角色时遇到以下异常(这正是因为我没有授予访问权限所应该发生的事情):

IAMConnection

所以仍然不清楚为什么这不起作用。

3 个答案:

答案 0 :(得分:2)

5件事:

  1. 确保您使用的是亚马逊Cognito Identity服务颁发的凭据,否则$ {cognito-identity.amazonaws.com:sub}将为空并授予您访问所有内容的权限
  2. 确保在更新策略后发布了您使用的Amazon Cognito Identity凭据,该策略嵌入在凭据的会话部分中,因此如果您使用旧凭据,则可能没有附加当前策略。 / LI>
  3. 您无法使用用户的用户名,您必须使用Amazon Cognito Identity ID。因此,不是test@test.com,它将是身份ID:us-east-1:beef-beef-beef-xxxxxxxxx
  4. 您的池有2个与之关联的角色,未经身份验证的角色和经过身份验证的角色。确保您使用正确的角色设置策略,在这种情况下,您似乎使用开发人员身份验证的身份,并且应该修改已验证角色的策略。
  5. 检查您的S3存储桶策略,如果您允许匿名访问存储桶,则Cognito角色策略不会覆盖它。如果是这种情况,请关闭匿名访问。 http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html#example-bucket-policies-use-case-2

答案 1 :(得分:1)

看起来您的代码使用的是硬编码的访问密钥和密钥,并且不使用Cognito来检索凭据。不是为所有用户嵌入相同的访问密钥和密钥,而是利用Cognito,您需要关注Authentication Flow并使用GetId(boto referenceAWS reference)来获取身份ID然后使用GetCredentialsForIdentity(boto reference AWS reference)获取Cognito颁发的当前ID凭据。然后将这些凭据与boto S3连接一起使用。

还要确保为每个用户缓存ID,并在对Cognito进行额外调用时重复使用。

答案 2 :(得分:1)

答案很愚蠢。显然S3中的桶本身有自己的策略(它们相当隐蔽),但我有指令:

Principal: "*"

导致存储桶具有全局可读性。

第二个启示是,如果您使用s3:ListBucket Condition限制一个存储桶,这并不意味着如果您列出存储桶只会获得这些结果 - 您必须将其调用按名字。作为boto中的示例:

wrong = bucket.list()  # will simply 403
right = bucket.list(prefix="base/subdir/<cognito-id>/")  # will succeed

换句话说,S3的设计使得您必须知道所需文件夹的前缀键,这无论如何都是很好的做法。

我不得不说,我对AWS的人们在这里和他们的论坛上诊断这个问题的帮助印象深刻。无论如何,现在对S3有了更好的理解。