CloudFormation - 从 Lambda 代码访问参数
CloudFormation - Access Parameter from Lambda Code
我有一个 CloudFormation
模板,如下所示:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template will deploy stuff",
"Parameters":{
"myParamToLambdaFunction" : {
"Description" : "Please enter the the value",
"Type" : "String",
"ConstraintDescription" : "must have some value."
}
},
"Resources": {
"SecGrpValidatorFromCFTemplate": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "mylambdafunctionname",
"Handler": "myfile.lambda_handler",
"Role": {
"Fn::GetAtt": ["somerole", "Arn"]
},
"Timeout": "30",
"Runtime": "python2.7",
"Code": {
"S3Bucket":"mybucket",
"S3Key":"mylambdafunction.zip"
}
}
}
}
我需要将 myParamToLambdaFunction
的值传递给 Lambda 函数。
有办法吗?
一旦您像在模板中那样创建了 lambda 函数,您就可以定义一个 Lambda 支持的自定义资源来调用带有自定义参数的函数,并且您还可以处理来自 lambda 的响应。有关详细信息和示例,请参阅 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html。
如果您的 lambda 不太复杂,您可以将其内联到您的模板中,而不是依赖上传的 zip 文件。
这是我使用输入参数所做的一个:
"CopyLogsStreamToFirehose": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": {
"Fn::Join": [
"",
[
"import base64\n",
"import boto3\n",
"def on_new_kinesis_data(event, context):\n",
" client = boto3.client('firehose')\n",
" records = [ {'Data': base64.b64decode(r['kinesis']['data']) + '\n' } for r in event['Records']]\n",
" client.put_record_batch(DeliveryStreamName='",
{
"Ref": "LogsDeliveryStream"
},
"', Records=records)\n",
" print 'Successfully processed {} records.'.format(len(event['Records']))\n"
]
]
}
},
"Description": "Kinesis Stream to Firehose Stream",
"Handler": "index.on_new_kinesis_data",
"Role": {
"Fn::GetAtt": [
"CopyLogsStreamToFirehoseRole",
"Arn"
]
},
"Runtime": "python2.7",
"Timeout": 5
}
这是 Lambda 需要环境变量的地方。这对我的工作来说是个大问题。我试过两种方法。
1 - 您的 lambda 函数名称将包含您的堆栈名称。使用一些拆分,提取该值,例如 var stackName = context.functionName.split('-')[0];
,然后调用 describeStacks 来检索您的堆栈。从那里从 outputs/parameters 中提取所需的数据。这工作正常,但请注意查询 CloudFormation 堆栈有一个相当适度的限制。如果您的 lambda 发射速度很快,选项 2 更适合您。
2 - 将您的端点手动输出到 DynamoDB table,并将堆栈名称作为键(S3 中的文件也可以,具体取决于您的延迟要求)并查询您的环境数据。如果您真的想要,您可以使用自定义 cloudformation 资源自动执行此堆栈数据输出。
调用 lambda 函数的任何内容都可以在调用时将元数据传递给 lambda 函数。
例如,对于自动缩放组,您可能希望在实例启动或终止时调用 lambda 函数。在这种情况下,AWS::AutoScaling::LifecycleHook
资源包括 NotificationMetadata
,它包含一个包含一项的字典,Route53ZoneId
:
"MyLifecycleHook": {
"Type": "AWS::AutoScaling::LifecycleHook",
"Properties": {
"AutoScalingGroupName": { "Ref": "MyASG" },
"LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING",
"NotificationMetadata": { "Fn::Join": [ "", [
"{",
" \"Route53ZoneId\": \"YOUR_ROUTE53_ZONE_IDENTIFIER_HERE\"",
"}"
] ] },
"NotificationTargetARN": { "Ref": "MyTopic" },
"RoleARN": { "Fn::GetAtt": [ "MyLifecycleHookRole", "Arn" ] }
}
}
然后在您的 lambda 处理程序中,假设您在 Python 中编写它,您可以访问该字典中的变量,例如:
def handler(event, context):
message = json.loads(event[u'Records'][0][u'Sns'][u'Message'])
metadata = json.loads(message['NotificationMetadata'])
logger.info("Route53 Zone Identifier {0}".format(metadata['Route53ZoneId']))
如果您的 Lambda 函数在 API 网关后面,您可以使用 RequestTemplates 在请求到达函数之前修改请求。下面的配置将发送原始请求主体以及定义为 YourCloudformationParameter
:
的参数
"RequestTemplates": {
"application/json": {
"Fn::Join": [
"",
[
"{",
"\"body\": $input.json('$'),",
"\"env\": {",
"\"yourCloudformationParameter\": \"", { "Ref": "YourCloudformationParameter" }, "\"",
"}",
"}"
]
]
}
},
截至 18 Nov 2016, AWS Lambda now supports environment variables, which CloudFormation supports through the Environment
property on the AWS::Lambda::Function
资源。
像这样向您的资源添加 Environment
属性:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template will deploy stuff",
"Parameters":{
"myParamToLambdaFunction" : {
"Description" : "Please enter the the value",
"Type" : "String",
"ConstraintDescription" : "must have some value."
}
},
"Resources": {
"SecGrpValidatorFromCFTemplate": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "mylambdafunctionname",
"Handler": "myfile.lambda_handler",
"Role": {
"Fn::GetAtt": ["somerole", "Arn"]
},
"Timeout": "30",
"Runtime": "python2.7",
"Code": {
"S3Bucket":"mybucket",
"S3Key":"mylambdafunction.zip"
},
"Environment": {
"Variables": {
"myParam": {
"Ref": "myParamToLambdaFunction"
}
}
}
}
}
}
然后根据您的运行时平台从您部署的 Lambda 函数中引用环境变量(例如 Python 中的 os.environ['myParam']
)。
在互联网上搜索了一个很好的答案,但找不到任何答案。这是我自己想出来的,它比我迄今为止看到的任何东西都容易。使用自定义资源:
Resources:
TriggerAccountLambda:
Type: "Custom::TriggerAccountLambda"
DeletionPolicy: Retain
Properties:
ServiceToken: "arn:aws:lambda:us-east-1:123436875680:function:your-function"
var1: !Ref var1
var2: !Ref var2
我有一个 CloudFormation
模板,如下所示:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template will deploy stuff",
"Parameters":{
"myParamToLambdaFunction" : {
"Description" : "Please enter the the value",
"Type" : "String",
"ConstraintDescription" : "must have some value."
}
},
"Resources": {
"SecGrpValidatorFromCFTemplate": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "mylambdafunctionname",
"Handler": "myfile.lambda_handler",
"Role": {
"Fn::GetAtt": ["somerole", "Arn"]
},
"Timeout": "30",
"Runtime": "python2.7",
"Code": {
"S3Bucket":"mybucket",
"S3Key":"mylambdafunction.zip"
}
}
}
}
我需要将 myParamToLambdaFunction
的值传递给 Lambda 函数。
有办法吗?
一旦您像在模板中那样创建了 lambda 函数,您就可以定义一个 Lambda 支持的自定义资源来调用带有自定义参数的函数,并且您还可以处理来自 lambda 的响应。有关详细信息和示例,请参阅 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html。
如果您的 lambda 不太复杂,您可以将其内联到您的模板中,而不是依赖上传的 zip 文件。
这是我使用输入参数所做的一个:
"CopyLogsStreamToFirehose": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": {
"Fn::Join": [
"",
[
"import base64\n",
"import boto3\n",
"def on_new_kinesis_data(event, context):\n",
" client = boto3.client('firehose')\n",
" records = [ {'Data': base64.b64decode(r['kinesis']['data']) + '\n' } for r in event['Records']]\n",
" client.put_record_batch(DeliveryStreamName='",
{
"Ref": "LogsDeliveryStream"
},
"', Records=records)\n",
" print 'Successfully processed {} records.'.format(len(event['Records']))\n"
]
]
}
},
"Description": "Kinesis Stream to Firehose Stream",
"Handler": "index.on_new_kinesis_data",
"Role": {
"Fn::GetAtt": [
"CopyLogsStreamToFirehoseRole",
"Arn"
]
},
"Runtime": "python2.7",
"Timeout": 5
}
这是 Lambda 需要环境变量的地方。这对我的工作来说是个大问题。我试过两种方法。
1 - 您的 lambda 函数名称将包含您的堆栈名称。使用一些拆分,提取该值,例如 var stackName = context.functionName.split('-')[0];
,然后调用 describeStacks 来检索您的堆栈。从那里从 outputs/parameters 中提取所需的数据。这工作正常,但请注意查询 CloudFormation 堆栈有一个相当适度的限制。如果您的 lambda 发射速度很快,选项 2 更适合您。
2 - 将您的端点手动输出到 DynamoDB table,并将堆栈名称作为键(S3 中的文件也可以,具体取决于您的延迟要求)并查询您的环境数据。如果您真的想要,您可以使用自定义 cloudformation 资源自动执行此堆栈数据输出。
调用 lambda 函数的任何内容都可以在调用时将元数据传递给 lambda 函数。
例如,对于自动缩放组,您可能希望在实例启动或终止时调用 lambda 函数。在这种情况下,AWS::AutoScaling::LifecycleHook
资源包括 NotificationMetadata
,它包含一个包含一项的字典,Route53ZoneId
:
"MyLifecycleHook": {
"Type": "AWS::AutoScaling::LifecycleHook",
"Properties": {
"AutoScalingGroupName": { "Ref": "MyASG" },
"LifecycleTransition": "autoscaling:EC2_INSTANCE_LAUNCHING",
"NotificationMetadata": { "Fn::Join": [ "", [
"{",
" \"Route53ZoneId\": \"YOUR_ROUTE53_ZONE_IDENTIFIER_HERE\"",
"}"
] ] },
"NotificationTargetARN": { "Ref": "MyTopic" },
"RoleARN": { "Fn::GetAtt": [ "MyLifecycleHookRole", "Arn" ] }
}
}
然后在您的 lambda 处理程序中,假设您在 Python 中编写它,您可以访问该字典中的变量,例如:
def handler(event, context):
message = json.loads(event[u'Records'][0][u'Sns'][u'Message'])
metadata = json.loads(message['NotificationMetadata'])
logger.info("Route53 Zone Identifier {0}".format(metadata['Route53ZoneId']))
如果您的 Lambda 函数在 API 网关后面,您可以使用 RequestTemplates 在请求到达函数之前修改请求。下面的配置将发送原始请求主体以及定义为 YourCloudformationParameter
:
"RequestTemplates": {
"application/json": {
"Fn::Join": [
"",
[
"{",
"\"body\": $input.json('$'),",
"\"env\": {",
"\"yourCloudformationParameter\": \"", { "Ref": "YourCloudformationParameter" }, "\"",
"}",
"}"
]
]
}
},
截至 18 Nov 2016, AWS Lambda now supports environment variables, which CloudFormation supports through the Environment
property on the AWS::Lambda::Function
资源。
像这样向您的资源添加 Environment
属性:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "This template will deploy stuff",
"Parameters":{
"myParamToLambdaFunction" : {
"Description" : "Please enter the the value",
"Type" : "String",
"ConstraintDescription" : "must have some value."
}
},
"Resources": {
"SecGrpValidatorFromCFTemplate": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "mylambdafunctionname",
"Handler": "myfile.lambda_handler",
"Role": {
"Fn::GetAtt": ["somerole", "Arn"]
},
"Timeout": "30",
"Runtime": "python2.7",
"Code": {
"S3Bucket":"mybucket",
"S3Key":"mylambdafunction.zip"
},
"Environment": {
"Variables": {
"myParam": {
"Ref": "myParamToLambdaFunction"
}
}
}
}
}
}
然后根据您的运行时平台从您部署的 Lambda 函数中引用环境变量(例如 Python 中的 os.environ['myParam']
)。
在互联网上搜索了一个很好的答案,但找不到任何答案。这是我自己想出来的,它比我迄今为止看到的任何东西都容易。使用自定义资源:
Resources:
TriggerAccountLambda:
Type: "Custom::TriggerAccountLambda"
DeletionPolicy: Retain
Properties:
ServiceToken: "arn:aws:lambda:us-east-1:123436875680:function:your-function"
var1: !Ref var1
var2: !Ref var2