如何为SAM模板中的Lambda配置Secret Manager读取权限及获取ARN?
用SAM CLI模板创建了Lambda函数,需要调用Secrets Manager获取第三方密钥。为了把代码存到公开GitHub,初始密钥设为空,重建SAM时手动更新值。但Lambda没有调用getSecretValue()的权限,尝试多种策略配置都无效,请问还有什么方法能获取Secretkey资源的ARN并传递给Lambda的Policies?
CloudWatch报错信息
"User: arn:aws:sts::######:assumed-role/FunctionRole-######/getAllItemsFunction-###### is not authorized to perform: secretsmanager:GetSecretValue on resource: Secretkey because no identity-based policy allows the secretsmanager:GetSecretValue action"
当前SAM模板代码
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "Description", "Transform": ["AWS::Serverless-2016-10-31"], "Resources": { "getAllItemsFunction": { "Type": "AWS::Serverless::Function", "Properties": { "Handler": "src/handlers/get-all-items.getAllItemsHandler", "Runtime": "nodejs14.x", "Architectures": ["x86_64"], "MemorySize": 128, "Timeout": 100, "Description": "Description", "Policies": [ { "AWSSecretsManagerGetSecretValuePolicy": { "SecretArn": { "Ref": "Secretkey" } } } ], "Events": { "Api": { "Type": "Api", "Properties": { "Path": "/", "Method": "GET" } } } } }, "Secretkey": { "Type": "AWS::SecretsManager::Secret", "Properties": { "Description": "Secret key from API that keeps API secure from outside calls", "SecretString": "{\"secret\": \"\"}" } } }, "Outputs": { "WebEndpoint": { "Description": "API Gateway endpoint URL for Prod stage", "Value": { "Fn::Sub": "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" } } } }
以下几种方法可以解决权限问题:
1. 使用自定义IAM策略语句替代SAM策略宏
SAM提供的AWSSecretsManagerGetSecretValuePolicy宏有时会因为ARN匹配问题失效,直接用自定义策略更可靠。修改Lambda的Policies部分:
"Policies": [ { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": { "Ref": "Secretkey" } } ] } ]
如果Secrets Manager的ARN带有随机后缀(比如创建时自动添加的一串字符),可以用Fn::Sub拼接带通配符的ARN确保匹配:
"Resource": { "Fn::Sub": "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:${Secretkey}-*" }
2. 手动创建IAM角色并关联到Lambda
绕过SAM自动生成角色的逻辑,手动定义IAM角色并明确授予权限,这样可以完全控制权限范围:
"Resources": { "getAllItemsFunction": { "Type": "AWS::Serverless::Function", "Properties": { // ... 其他属性保持不变 "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] } } }, "LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }, "Policies": [ { "PolicyName": "SecretsManagerAccess", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "secretsmanager:GetSecretValue", "Resource": { "Ref": "Secretkey" } } ] } } ], "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" ] } }, // ... Secretkey资源保持不变 }
注意要添加AWSLambdaBasicExecutionRole托管策略,确保Lambda能正常写入CloudWatch日志。
3. 强制更新IAM角色权限
如果之前部署过SAM模板,SAM可能不会自动更新现有角色的权限。可以执行以下操作:
- 删除自动生成的Lambda角色(在IAM控制台找到
FunctionRole-xxxxxx角色) - 重新执行
sam deploy --guided,让SAM重新生成带正确权限的角色 - 或者添加
--no-fail-on-empty-changeset参数强制部署,触发权限更新
4. 验证Secret资源的ARN引用
确认Ref: "Secretkey"返回的是正确的ARN:可以在模板的Outputs里添加Secret的ARN输出,部署后查看是否正确:
"Outputs": { // ... 原有输出 "SecretArn": { "Description": "ARN of the Secretkey resource", "Value": { "Ref": "Secretkey" } } }
部署后检查输出的ARN是否和CloudWatch报错里的资源ARN一致,如果不一致,说明引用有误,需要调整。
内容的提问来源于stack exchange,提问作者Mnai

