AWS Lambda中从外部文件引用策略字典的问题排查
AWS Lambda中从外部文件引用策略字典的问题排查
我来帮你梳理下问题所在,以及怎么解决这个问题~
你遇到的核心问题
你最后碰到的"'function' object has no attribute 'data_pols'"错误,主要有两个原因:
- 变量作用域问题:你把
data_pol放到了policies.py的lambda_handler函数内部,这个变量是函数的局部变量,外部模块(index.py)根本无法直接访问它。 - 拼写小失误:你在index.py里写的是
policies.data_pols,但实际变量名是data_pol,多了个s,不过这只是次要问题,核心还是作用域。
再往前推的两个错误(BUCKETNAME未定义、event未定义),本质也是因为你没处理好动态参数(event)和环境变量的传递/加载逻辑:
- 一开始policies.py里没加载环境变量,所以找不到BUCKETNAME;
- 后来环境变量加载了,但
data_pol里用到了event(Lambda请求的动态数据),而模块顶层代码在Lambda冷启动时就执行了,这时候还没有event,自然会报错。
正确的解决方案
我们可以把policies.py改成一个提供策略生成函数的模块,通过函数参数把动态的event传进去,同时在模块顶层加载环境变量(因为环境变量是固定的,冷启动时加载没问题)。
第一步:修改policies.py
把策略生成逻辑封装成一个可调用的函数,接收event参数,返回构造好的策略字典:
import os # 提前加载环境变量(模块加载时执行,只加载一次) BUCKETNAME = os.environ['bucketname'] PUBLICKEYSBUCKETNAME = os.environ['publickkeysbucketname'] def get_transfer_policy(event): """根据Lambda的event参数生成对应的S3访问策略""" data_pol = { "Version": "2012-10-17", "Statement": [{ "Sid": "AllowListAccessToBucket", "Action": ["s3:ListBucket"], "Effect": "Allow", "Resource": ["arn:aws:s3:::" + BUCKETNAME, "arn:aws:s3:::" + PUBLICKEYSBUCKETNAME], "Condition": { "StringLike": { "s3:prefix": [ event["username"] + "/*", event["username"]]}}}, {"Sid": "GetAccessForPublicKeys", "Effect": "Allow", "Action": ["s3:GetObject","s3:GetObjectAcl","s3:GetObjectVersion","s3:GetBucketLocation"], "Resource": ["arn:aws:s3:::" + PUBLICKEYSBUCKETNAME + "/" + event["username"], "arn:aws:s3:::" + PUBLICKEYSBUCKETNAME + "/" + event["username"] + "/*"]}, {"Sid": "PublicKeysPubFilePutAccess", "Effect": "Allow", "Action": ["s3:PutObject","s3:PutObjectAcl"], "Resource": ["arn:aws:s3:::" + PUBLICKEYSBUCKETNAME + "/" + event["username"] + "/*.pub"]}, {"Sid": "TransferDataBucketAccess", "Effect": "Allow", "Action": ["s3:PutObject","s3:PutObjectAcl","s3:GetObject","s3:GetObjectAcl","s3:GetObjectVersion","s3:GetBucketLocation","s3:DeleteObject","s3:DeleteObjectVersion"], "Resource": ["arn:aws:s3:::" + BUCKETNAME + "/" + event["username"], "arn:aws:s3:::" + BUCKETNAME + "/" + event["username"] + "/*"]}]} return data_pol
第二步:修改index.py
导入policies模块后,在自己的lambda_handler里调用这个函数,传入event参数获取策略:
import boto3 import json import os import policies # 导入policies模块 # 保留你原来的环境变量加载(如果需要在index.py里用到的话) BUCKETNAME = os.environ['bucketname'] PUBLICKEYSBUCKETNAME = os.environ['publickkeysbucketname'] TRANSFERACCESSADMINROLE = os.environ['transferaccessadminrole'] TRANSFERACCESSREADROLE = os.environ['transferaccessreadrole'] TRANSFERACCESSHUBADMINROLE = os.environ['transferaccesshubadminrole'] PRIMARY_REGION = os.environ['AWS_REGION'] SSM_PREFIX = os.environ['transferssmparameter'] def lambda_handler(event, context): auth_response = {} data_ret = {} # 调用policies里的函数获取动态生成的策略 data_pol = policies.get_transfer_policy(event) data_ret["Policy"] = json.dumps(data_pol) data_ret["HomeDirectoryType"] = "PATH" #data_ret["HomeDirectoryDetails"] = json.dumps(directorymapping) data_ret["HomeDirectory"] = "/" + BUCKETNAME + "/" + event["username"] return data_ret
为什么这么做能解决问题
- 环境变量在policies.py的模块顶层加载,冷启动时就完成初始化,不会重复加载,效率高;
- 策略生成逻辑封装在函数里,通过参数接收动态的event,确保每次请求都能拿到当前用户的username;
- 函数返回的字典可以直接被index.py使用,不存在作用域访问不到的问题。
备注:内容来源于stack exchange,提问作者Jason Stanley
相关产品推荐
相关产品推荐

