【问题标题】:Specifying IAM roles for permissions in AWS S3在 AWS S3 中为权限指定 IAM 角色
【发布时间】:2015-09-09 23:21:33
【问题描述】:

我正在尝试将我的所有 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,方法是使用从 STS 检索到的访问/秘密/安全令牌三倍,使用 Cognito 令牌创建 boto IAMConnection 对象并查询我的角色与我的身份池的经过身份验证的 cognito 用户相对应的名称。这样做时,我在尝试读取此角色时遇到了以下异常(这正是我没有授予访问权限而应该发生的情况):

BotoServerError: BotoServerError: 403 Forbidden
<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
  <Error>
    <Type>Sender</Type>
    <Code>AccessDenied</Code>
    <Message>User: arn:aws:sts::MY_AWS_ACCT_ID:assumed-role/my_policy_role_name/session_name_here is not authorized to perform: iam:GetRole on resource: role awsNameFor_Role_Given_123012313</Message>
  </Error>
  <RequestId>xxx-xxxx-xxxx-xxxx-xxxxx</RequestId>
</ErrorResponse>

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

【问题讨论】:

  • 您能否澄清更改后的问题是什么?与原始问题相同(您可以访问子文件夹下的任何键)还是其他问题?
  • 是的,同样的问题。当我的GetObjectPutObject 访问权限应仅限于用户文件夹时,我可以访问任何密钥。此外,我能够列出整个存储桶中的所有对象,而不仅仅是具有指定前缀的对象。
  • 您的存储桶策略中是否有任何特殊内容允许比您的角色更多的访问权限?除了您在此处列出的角色之外,您是否有附加到该角色的其他策略?
  • 如果您在我们的论坛上发帖或以其他方式向我们提供您的帐户 ID,我们还可以查看您的帐户详细信息并进行更仔细的调试。
  • @BobKinney:据我所知,我的存储桶中没有其他角色,也没有什么特别之处。不过肯定有问题。

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


【解决方案1】:

5 件事:

  1. 确保您使用的是由 Amazon Cognito Identity 服务颁发的凭证,否则 ${cognito-identity.amazonaws.com:sub} 将为空并授予您访问所有内容的权限
  2. 确保您使用的 Amazon Cognito 身份凭证是在您更新策略后颁发的,该策略嵌入在凭证的会话部分中,因此如果您使用旧凭证,它们可能没有附加当前策略。
  3. 您不能使用用户的用户名,您必须使用 Amazon Cognito 身份 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)我该如何测试呢?有什么方法可以查看这是否为非空?以及 3)我如何从我的终端看到我的开发人员用户 id (test@test.com) 和 AWS 之间的映射?
  • 我已经用讨论的一些要点更新了这个问题,但仍然不起作用。嗯。
  • 我还在 3) 中找到了您的观点的答案,只要 Cognito 在您向 STS 索取凭据之前授予您网络令牌,就会立即给出此 IdentityId。
  • 嗯,是的,我知道。我有两个角色,一个是经过身份验证的,另一个是未经身份验证的。
  • 我将此标记为答案,因为它可能是关于我所面临的问题以及尝试调试自己问题的人们的最有用的信息。
【解决方案2】:

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

还要确保缓存每个用户的 ID,并在对 Cognito 进行其他调用时重复使用它。

【讨论】:

  • 不,我只是没有发布整个身份验证流程的代码。我(正如我在帖子中提到的)正在联系 Cognito 和 STS 以获取密钥。此外,您提到的流程效率低下,您可以简单地使用 GetOpenIDTokenForDeveloperIdentity 并从那里使用 AssumeRoleWithWebIdentity 和 STS - see the AWS blog here
  • 查看我帖子的最后一段以及相关的 403,我在其中表明我的凭据确实来自 Cognito。
【解决方案3】:

答案相当愚蠢。显然,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 有了更好的理解。

【讨论】:

    猜你喜欢
    • 2021-01-03
    • 1970-01-01
    • 2020-10-08
    • 2022-08-18
    • 1970-01-01
    • 2021-04-09
    • 2021-01-18
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多