通过 Lambda 到 GetObject 的 Cognito 身份验证角色 - 调用 GetObject 操作时发生错误 (AccessDenied):访问被拒绝

Posted

技术标签:

【中文标题】通过 Lambda 到 GetObject 的 Cognito 身份验证角色 - 调用 GetObject 操作时发生错误 (AccessDenied):访问被拒绝【英文标题】:Cognito authenticated role via Lambda to GetObject - An error occurred (AccessDenied) when calling the GetObject operation: Access Denied 【发布时间】:2021-12-19 09:35:12 【问题描述】:

我已经尝试了所有方法,但不知道我的 IAM 政策有什么问题与 Cognito sub 和身份 ID 访问权限有关

我正在使用 Lambda 获取身份验证详细信息 > 从 Cognito 用户使用 boto3 分隔的文件夹中获取对象。

这是我的 Lambda 代码:

import json
import urllib.parse
import boto3
import sys
import hmac, hashlib, base64

print('Loading function')

cognito = boto3.client('cognito-idp')
cognito_identity = boto3.client('cognito-identity')

def lambda_handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))
    
    username = 'substitute_with_my_own_data' //authenticated user
    app_client_id = 'substitute_with_my_own_data' //cognito client id
    key = 'substitute_with_my_own_data' //cognito app client secret key
    cognito_provider = 'cognito-idp.region.amazonaws.com/cognito-pool-id' 
    
    message = bytes(username+app_client_id,'utf-8')
    key = bytes(key,'utf-8')
    secret_hash = base64.b64encode(hmac.new(key, message, digestmod=hashlib.sha256).digest()).decode()
    
    print("SECRET HASH:",secret_hash)
        
    
    auth_data =  'USERNAME': username, 'PASSWORD':'substitute_user_password', 'SECRET_HASH': secret_hash
    auth_response = cognito.initiate_auth(
        AuthFlow='USER_PASSWORD_AUTH',
        AuthParameters=auth_data,
        ClientId=app_client_id
        )
    
    print(auth_response)

    # From the response that contains the assumed role, get the temporary 
    # credentials that can be used to make subsequent API calls
    auth_result=auth_response['AuthenticationResult']
    id_token=auth_result['IdToken']
    
    id_response =  cognito_identity.get_id(
        IdentityPoolId='sub_cognito_identity_pool_id',
        Logins=cognito_provider: id_token
        )
    print('id_response = ' + id_response['IdentityId']) // up to this stage verified correct user cognito identity id returned
    
    credentials_response = cognito_identity.get_credentials_for_identity(
        IdentityId=id_response['IdentityId'],
        Logins=cognito_provider: id_token
        )
        
    secretKey = credentials_response['Credentials']['SecretKey']
    accessKey = credentials_response['Credentials']['AccessKeyId']
    sessionToken = credentials_response['Credentials']['SessionToken']
    
    print('secretKey = ' + secretKey)
    print('accessKey = ' + accessKey)
    print('sessionToken = ' + sessionToken)
    
    # Use the temporary credentials that AssumeRole returns to make a 
    # connection to Amazon S3  
    s3 = boto3.client(
        's3',
        aws_access_key_id=accessKey, 
        aws_secret_access_key=secretKey, 
        aws_session_token=sessionToken,
    )
    
    # Use the Amazon S3 resource object that is now configured with the 
    # credentials to access your S3 buckets. 
    # for bucket in s3.buckets.all():
    #     print(bucket.name)
    

    # Get the object from the event and show its content type
    bucket = 'bucket-name'
    key = 'abc/user_cognito_identity_id/test1.txt'
    prefix = 'abc/user_cognito_identity_id'
    
    try:
        response = s3.get_object(
            Bucket=bucket,
            Key=key
        )
        # response = s3.list_objects(
        #     Bucket=bucket,
        #     Prefix=prefix,
        #     Delimiter='/'
        # )
        print(response)
        return response
    except Exception as e:
        print(e)
        print('Error getting object  from bucket . Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

我已验证的内容:

认证成功 具有正确假定角色的身份(打印 cognito 身份 ID 并验证它是具有该 ID 的正确身份验证用户) 删除了 $cognito-identity.amazonaws.com:sub 并授予对经过身份验证的角色的一般访问权限 > 我将能够获得,但是 $cognito-identity.amazonaws.com:sub 似乎无法很好地检测和匹配

看来 IAM 政策存在问题

IAM 政策


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

我尝试列出存储桶/获取对象/放置对象,所有访问被拒绝。

我确实尝试过一些策略,例如删除 listbucket 条件(显然它允许访问,因为我已经过身份验证)/将“s3:prefix”更改为“$cognito-identity.amazonaws.com:sub/" 或 "cognito/$cognito-identity.amazonaws.com:sub/" 但无法正常工作。

put 或 get 对象也是如此。

我的 S3 文件夹是bucket-name/cognito/cognito-user-identity-id/key

我提到: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_cognito-bucket.html

https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication-part-3-roles-and-policies/

关于哪里可能出错的任何见解?

【问题讨论】:

【参考方案1】:

在更改 GetObjectPutObject 策略 Resources 后,我设法解决了这个问题

"arn:aws:s3:::bucket-name/cognito/$cognito-identity.amazonaws.com:sub/",
"arn:aws:s3:::bucket-name/cognito/$cognito-identity.amazonaws.com:sub/*"

"arn:aws:s3:::bucket-name/*/$cognito-identity.amazonaws.com:sub/",
"arn:aws:s3:::bucket-name/*/$cognito-identity.amazonaws.com:sub/*"

它神奇地工作。我不太明白为什么 cognito 会阻止访问,因为我的存储桶在存储桶根之后有 cognito 前缀,但现在已经解决了。

【讨论】:

以上是关于通过 Lambda 到 GetObject 的 Cognito 身份验证角色 - 调用 GetObject 操作时发生错误 (AccessDenied):访问被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

在我的S3存储桶上执行getObject操作时,如何触发Lambda函数?

lambda 内的 s3.getObject 不返回任何内容

根据字符串从资源中取出对应的资源ResourceManager.GetObject

AWS Lambda 返回权限被拒绝尝试从 S3 存储桶获取对象

AWS Lambda S3 访问被拒绝

如何在 AWS Lambda 中等待异步操作?