按Lambda调用限制S3存储桶内的前缀访问权限
解决方案:限制Lambda仅访问自身生成的S3前缀
核心思路
要实现Lambda每次调用只能操作自己生成的时间戳前缀,关键是让权限与单次调用的上下文绑定,而非依赖静态策略或动态修改权限。以下是两种可靠的实现方式:
方案1:IAM会话标签 + S3桶策略条件判断
利用IAM会话标签标记当前Lambda调用的目标前缀,再通过S3桶策略的条件判断,仅允许带有对应标签的请求访问指定前缀。
步骤1:给Lambda角色添加会话标签权限
修改Lambda的执行角色,添加sts:TagSession权限,允许Lambda为自身会话打标签:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:TagSession", "Resource": "*" } ] }
步骤2:修改Lambda代码,添加会话标签
在代码中生成时间戳前缀后,为当前会话打上对应标签,再用该会话操作S3:
import boto3 import time def lambda_handler(event, context): # 生成唯一时间戳前缀 timestamp_prefix = time.strftime("%Y%m%d%H%M%S") + "/" # 为当前Lambda会话添加前缀标签 sts_client = boto3.client('sts') sts_client.tag_session( Tags=[ { 'Key': 'S3TargetPrefix', 'Value': timestamp_prefix } ] ) # 使用带标签的会话写入S3 s3_client = boto3.client('s3') s3_client.put_object( Bucket="your-bucket-name", Key=f"{timestamp_prefix}data.json", Body="your-data-content" ) return {"status": "success", "prefix": timestamp_prefix}
步骤3:配置S3桶策略,实现权限隔离
设置桶策略,仅允许带有匹配标签的请求访问对应前缀,同时拒绝访问其他前缀:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:role/your-lambda-execution-role" }, "Action": ["s3:PutObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:::your-bucket-name/${aws:PrincipalTag/S3TargetPrefix}*", "arn:aws:s3:::your-bucket-name" ], "Condition": { "StringEquals": { "aws:PrincipalTag/S3TargetPrefix": "${aws:ResourcePrefix}" } } }, { "Effect": "Deny", "Principal": { "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:role/your-lambda-execution-role" }, "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"], "Resource": "arn:aws:s3:::your-bucket-name/*", "Condition": { "StringNotEquals": { "aws:PrincipalTag/S3TargetPrefix": "${aws:ResourcePrefix}" } } } ] }
方案2:动态生成STS临时凭证
让Lambda每次调用时,向STS请求一个仅允许访问当前时间戳前缀的临时凭证,用该凭证操作S3,实现完全的权限隔离。
步骤1:创建专用的S3写入角色
创建一个仅允许访问特定前缀的IAM角色(例如S3PrefixRestrictedWriter):
- 信任策略:允许Lambda执行角色扮演该角色,并通过
ExternalId传递前缀信息:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::YOUR_ACCOUNT_ID:role/your-lambda-execution-role" }, "Action": "sts:AssumeRole", "Condition": { "StringLike": { "sts:ExternalId": "prefix-*" } } } ] }
- 权限策略:仅允许操作
ExternalId指定的前缀:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["s3:PutObject"], "Resource": "arn:aws:s3:::your-bucket-name/${sts:ExternalId:prefix-}*" } ] }
步骤2:修改Lambda代码,获取临时凭证并写入S3
import boto3 import time def lambda_handler(event, context): timestamp_prefix = time.strftime("%Y%m%d%H%M%S") + "/" sts_client = boto3.client('sts') # 请求临时凭证,传递前缀作为ExternalId assumed_role_resp = sts_client.assume_role( RoleArn="arn:aws:iam::YOUR_ACCOUNT_ID:role/S3PrefixRestrictedWriter", RoleSessionName=f"prefix-writer-{timestamp_prefix}", ExternalId=f"prefix-{timestamp_prefix}" ) # 使用临时凭证创建S3客户端 temp_creds = assumed_role_resp['Credentials'] s3_client = boto3.client( 's3', aws_access_key_id=temp_creds['AccessKeyId'], aws_secret_access_key=temp_creds['SecretAccessKey'], aws_session_token=temp_creds['SessionToken'] ) # 写入数据 s3_client.put_object( Bucket="your-bucket-name", Key=f"{timestamp_prefix}data.json", Body="your-data-content" ) return {"status": "success", "prefix": timestamp_prefix}
为什么不推荐预先修改权限?
- 并发冲突:多个Lambda实例同时修改IAM策略或桶策略时,会出现竞态条件,导致权限设置失效或错误。
- 违反最小权限原则:修改权限会临时扩大Lambda的访问范围,增加安全风险。
- 维护成本高:需要处理权限的回滚、冲突等问题,复杂度远高于上述方案。
内容的提问来源于stack exchange,提问作者Ian L
相关产品推荐
相关产品推荐

