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
相关产品推荐
相关产品推荐

