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