如何从Lambda函数向SSM Run Command文档传递密钥变量
解决Lambda传递Secrets Manager密钥到SSM文档的InvalidParameters错误
看起来你已经能成功从Secrets Manager拿到密钥了,但卡在了把密钥传给SSM文档这一步。咱们一步步拆解问题,搞定这个InvalidParameters错误:
1. 先修正最明显的参数传递错误
你当前代码里的Parameters部分犯了两个小错误:
Parameters={ 'AWS_ACCESS_KEY_ID': [ 'secret_key', ] }
- 你写的
'secret_key'是字符串字面量,不是从Secrets Manager拿到的secret_key变量 - 要传递
AWS_ACCESS_KEY_ID,对应的应该是access_key变量,不是secret_key
正确的写法应该是:
Parameters={ 'AWS_ACCESS_KEY_ID': [access_key], 'AWS_SECRET_ACCESS_KEY': [secret_key] # 如果你的SSM文档需要这个参数的话 }
注意:SSM要求Parameters的值必须是列表类型,哪怕是单个值也要放在方括号里,这部分你之前的格式是对的,只是变量引用错了。
2. 检查SSM文档的参数定义
这是很容易忽略的点:你的Secrets_Management文档必须提前定义好对应的参数名,否则SSM会认为参数无效。
比如你的SSM文档(YAML格式)里应该有类似这样的参数定义:
parameters: AWS_ACCESS_KEY_ID: type: String description: "AWS Access Key ID from Secrets Manager" AWS_SECRET_ACCESS_KEY: type: String description: "AWS Secret Access Key from Secrets Manager"
参数名要和你Lambda里传递的完全一致(大小写敏感!),否则肯定会触发InvalidParameters错误。
3. 优化密钥获取的作用域(可选但推荐)
你现在把获取密钥的代码放在了lambda_handler外面,虽然Lambda容器复用的时候可能能工作,但把这部分逻辑移到handler内部会更可靠,避免冷启动或者意外的变量复用问题:
def lambda_handler(event, context): # 把获取密钥的逻辑移到handler内部 secret_name = "***/***/***" endpoint_url = "https://secretsmanager.eu-west-1.amazonaws.com" region_name = "eu-west-1" session = boto3.session.Session() client = session.client( service_name='secretsmanager', region_name=region_name, endpoint_url=endpoint_url ) try: get_secret_value_response = client.get_secret_value(SecretId=secret_name) except ClientError as e: if e.response['Error']['Code'] == 'ResourceNotFoundException': print("The requested secret " + secret_name + " was not found") raise e # 抛出异常让Lambda返回错误,方便排查 elif e.response['Error']['Code'] == 'InvalidRequestException': print("The request was invalid due to:", e) raise e elif e.response['Error']['Code'] == 'InvalidParameterException': print("The request had invalid params:", e) raise e else: if 'SecretString' in get_secret_value_response: secret = json.loads(get_secret_value_response['SecretString']) else: # 如果是二进制密钥,需要解码(大部分场景用不到,但加上更严谨) import base64 binary_secret_data = base64.b64decode(get_secret_value_response['SecretBinary']) secret = json.loads(binary_secret_data) access_key = secret['AWS_ACCESS_KEY_ID'] secret_key = secret['AWS_SECRET_ACCESS_KEY'] region = secret['AWS_DEFAULT_REGION'] # 后面的实例筛选逻辑保留 running_with = [] running_without = [] for instance in ec2.instances.all(): if instance.state['Name'] != 'running': continue has_tag = False for tag in instance.tags: if tag['Key'] == 'AutoDiskGrowth' and tag['Value'] == 'True': has_tag = True break if has_tag: running_with.append(instance.id) else: running_without.append(instance.id) print("access_key: %s" % access_key) print("Instances found with AutoDiskGrowth Tag: %s" % running_with) # 修正后的SendCommand调用 ssmCommand = ssm.send_command( Targets = [ {'Key': 'tag:AutoDiskGrowth', 'Values': [ 'True'] } ], DocumentName = 'Secrets_Management', TimeoutSeconds = 6000, Comment = 'Extending disk volume by 50%', Parameters={ 'AWS_ACCESS_KEY_ID': [access_key], 'AWS_SECRET_ACCESS_KEY': [secret_key] } ) return { 'statusCode': 200, 'message': 'Command sent successfully', 'commandId': ssmCommand['Command']['CommandId'] }
4. 最后验证权限(兜底检查)
确保你的Lambda执行角色有这些权限:
secretsmanager:GetSecretValue:用于读取Secrets Manager的密钥ssm:SendCommand:用于发送SSM命令ec2:DescribeInstances:用于筛选EC2实例
另外,EC2实例上的SSM Agent角色也要能接收SSM命令,如果文档里要用密钥执行操作,实例角色也要有对应的权限。
按照这些步骤修复后,应该就能成功把密钥传递到SSM文档里了。
内容的提问来源于stack exchange,提问作者Desnoyll
相关产品推荐
相关产品推荐

