You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lambda使用Cognito认证角色调用S3 GetObject返回AccessDenied错误

Cognito身份ID关联的IAM策略访问S3返回AccessDenied问题

我尝试了所有方法仍无法定位关联Cognito sub 身份ID访问权限的IAM策略问题。我通过Lambda获取认证信息,再使用boto3访问按Cognito用户隔离的S3文件夹中的对象,调用GetObject接口时返回AccessDenied访问被拒错误。

以下是我的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}' # 已认证用户
    app_client_id = '{substitute_with_my_own_data}' # Cognito客户端ID
    key = '{substitute_with_my_own_data}' # Cognito应用客户端密钥
    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)

    # 从返回的认证结果中获取临时凭证,用于后续API调用
    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']) # 到这一步已验证返回了正确的用户Cognito身份ID
    
    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)
    
    # 使用AssumeRole返回的临时凭证连接S3
    s3 = boto3.client(
        's3',
        aws_access_key_id=accessKey, 
        aws_secret_access_key=secretKey, 
        aws_session_token=sessionToken,
    )

    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
        )
        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一致
  • 移除IAM策略中的${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}/*"
            ]
        }
    ]
}

我尝试执行列举桶、获取对象、上传对象操作,全部返回AccessDenied访问被拒。我也调整过策略配置,比如移除ListBucket的条件(此时因已通过认证可正常访问)、将s3:prefix修改为${cognito-identity.amazonaws.com:sub}/*或cognito/${cognito-identity.amazonaws.com:sub}/*,均未解决问题,上传和获取对象操作同样报错。
我的S3文件夹路径规则为bucket-name/cognito/{cognito-user-identity-id}/key。

请问该问题可能出在哪里?


问题解决方案

1. 路径不匹配是核心问题

你代码中请求的S3对象路径前缀为abc/{user_cognito_identity_id}/,但IAM策略中配置的资源路径前缀为cognito/${cognito-identity.amazonaws.com:sub}/,二者完全不一致,直接导致权限校验失败。同时ListBucket的前缀条件也不符合你的实际路径结构。

2. 修正后的IAM策略

将策略中的路径替换为你实际使用的abc/前缀即可:

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

3. 其他需确认配置

  • 确认Cognito身份池的认证用户角色信任策略允许cognito-identity.amazonaws.com服务执行sts:AssumeRoleWithWebIdentity操作
  • 确认S3桶没有配置拦截访问的桶策略,桶策略优先级高于角色权限,存在冲突时会优先执行桶策略规则
  • 可通过STS的get_caller_identity接口打印临时凭证的身份信息,确认凭证关联的Cognito身份ID和你路径中使用的ID完全一致

内容的提问来源于stack exchange,提问作者unacorn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 01:54:03