我们使用机器学习技术将英文博客翻译为简体中文。您可以点击导航栏中的“中文(简体)”切换到英文版本。
使用 CloudFormation Lambda Hooks 验证您的 Lambda
导言
这篇文章演示了如何利用 Amazon CloudFormation Lambda Hooks 在配置时强制执行合规规则,使您能够在部署之前根据自定义策略评估和验证 Lambda 函数配置。这些策略通常会影响软件的构建方式,从而限制语言版本和运行时间。一个很好的例子是在 Amazon Lambda 上应用这些策略,这是一种无需预置或管理服务器即可运行代码的无服务器计算服务。尽管 Amazon Lambda 已经对运行时的弃用进行了管理,以防止您部署不受支持的运行时,但组织可能需要提供和执行与弃用特定语言版本没有直接关联的特定合规规则。
Lambda Hooks 简介
Amazon CloudFormation Lambda Hooks 是一项强大的功能,它允许开发者根据作为 Lambda 函数实现的自定义代码来评估 CloudFormation 和 Amazon Cloud Control API 的操作。此功能允许在配置之前主动检查资源配置,从而增强安全性、合规性和运营效率。
Lambda Hooks 提供了一种机制来拦截和评估各种 CloudFormation 操作,包括资源操作、堆栈操作和变更集操作(它们也可以与云控制 API 一起使用,但在这篇文章中我们将重点介绍 CloudFormation)。通过激活 Lambda 挂钩,CloudFormation 会在您的账户注册表中创建一个作为私有挂钩的条目,允许您为特定的亚马逊云科技账户和区域对其进行配置。配置 Lambda 挂钩时,您可以指定一个或多个 Lambda 函数以在评估过程中调用。这些函数可以与 Hook 位于同一亚马逊云科技账户和区域中,也可以位于您拥有的其他账户中,前提是设置了适当的权限。评估过程发生在 CloudFormation 堆栈生命周期的特定时刻。例如,在堆栈创建、更新或删除期间,将调用配置的 Lambda 函数,根据您定义的合规性规则评估提议的变更。根据评估结果,挂钩可以阻止操作或发出警告,从而允许操作继续进行。
Lambda Hook 在通过 CloudFormation 配置资源之前对其进行评估,从而提供先发制人的监管层。这意味着可以捕获不合规的资源并阻止其部署,而不必进行追溯性修复。通过利用 Lambda Hooks,组织可以对所有亚马逊云科技账户和区域的合规性检查进行自动化和标准化。这种集中化的策略实施方法可确保一致性并减少手动管理合规性的开销。
解决方案概述
以下部分演示了 Amazon CloudFormation Lambda Hooks 的实际用例,重点介绍在 Amazon Lambda 运行时上执行合规规则。
认识一下 AnyCompany,这是一家具有前瞻性思维的企业,拥有一套强大的合规规则来管理其软件开发实践。这些规则中有一条关于使用特定 Amazon Lambda 运行时的严格政策。
随着他们继续采用无服务器架构,AnyCompany 面临着挑战:如何防止部署使用不合规运行时的 Lambda 函数。鉴于他们承诺使用 Amazon CloudFormation 部署 Lambda 函数,AnyCompany 渴望利用 Amazon CloudFormation Lambda Hooks 的力量。
我们将探讨设置流程,演示该挂钩的实际应用,并讨论在动态云环境中保持合规性的更广泛影响。
架构
以下架构重点介绍了 Lambda 挂钩的实现。在此实施中,我们使用 Amazon CloudFormation Lambda 挂钩来拦截 Lambda 函数的部署并对这些资源进行合规性检查。Lambda Hook 将与 Amazon Lambda 函数进行交互,后者将执行合规性检查。最后,我们使用 Amazon Systems Manager 参数存储库来存储配置参数,其中包含允许的 Lambda 运行时列表。
图 1:解决方案的架构
- 开发人员(或 CI/CD 管道)部署包含 Lambda 函数的 CloudFormation 堆栈。
- CloudFormation 调用相应的 Lambda Hook,该挂钩配置为拦截在 Amazon Lambda 资源上的操作。如果检查不成功,我们将此挂钩设置为 "失败" 部署。
- Lambda Hook 会检查 Lambda 的运行时间是否被允许或违反了公司的合规性。为此,它会检查运行时是否存在于 Amazon Systems Manager 参数存储区中作为参数保存的预先配置的允许运行时列表中。请记住,我们正在使用 SSM 参数存储库来存储此特定示例的配置,但其他替代方案也可能可行(Amazon DynamoDB、Amazon Secrets Manager 或 AppConfig lambda-function-settings-check 预防规则)
- Lambda Hook 在检查运行时合规性后回复:
- 如果 Lambda 运行时不合规,则出现故障
- 如果 Lambda 运行时合规,则成功
- 根据 Lambda Hook 的响应,可能会进行也可能不进行部署。
存储库结构
您可以在此链接中找到该解决方案的所有代码。以下是存储库结构:
.
├── README.md
├── deploy.sh
├── cleanup.sh
├── hook-lambda
│ ├── index.ts
│ ├── package.json
│ ├── services
│ │ └── parameter-store.ts
│ └── tsconfig.json
├── sample
│ ├── deploy_sample.sh
│ ├── cleanup_sample.sh
│ └── lambda_template.yml
└── template.yml
- hook-lambda:包含与 CloudFormation Lambda Hook(验证 Lambda 函数和解决方案的 CloudFormation 模板)相关的所有代码的目录
- 示例:包含用于测试 CloudFormation Lambda Hook 的示例代码的目录
- deploy.sh:通过亚马逊云科技 CLI 部署解决方案的实用程序脚本
- cleanup.sh:通过亚马逊云科技 CLI 清理 Amazon CloudFormation Hook 基础设施的实用脚本
- template.yml:包含解决方案中涉及的所有亚马逊云科技资源的 Amazon CloudFormation 模板
先决条件
此解决方案必须具备以下先决条件:
- 一个亚马逊云科技账户或注册以创建和激活一个。
- 您的开发计算机上安装了以下软件:
- 安装亚马逊云科技命令行接口 (亚马逊云科技 CLI) 并将其配置为指向您的亚马逊云科技账户。
- 安装 Node.js 并使用诸如 npm 之类的包管理器。
- 用于与您的亚马逊云科技账户中的资源进行交互的相应的亚马逊云科技证书。
演练
创建 Amazon Lambda 验证函数 — Lambda 代码
CloudFormation Lambda Hook 与特定的 Lambda(在本文的其余部分中称为 Validation Lambda)进行交互,该挂钩是在涉及 Lambda 函数的 CloudFormation 创建和更新堆栈操作期间调用的。目标是检查这些 Lambda 函数的运行时是否符合 AnyCompany 的规则。
以下是验证 Lambda 函数处理程序遵循的步骤的详细描述(代码是用 Typescript 编写的)。
首先,验证 Lambda 检索一个环境变量,该变量包含 SSM 参数存储参数名称,其中包含合规的运行时列表。此外,安全检查可确保仅考虑 Lambda 资源并定义其运行时属性。
请注意,可以跳过这两项安全检查,因为挂钩应该已经配置为仅与 Lambda 资源交互,而且 Lambda 的运行时属性始终是必需的。但是,它们仍然存在,可以演示如何从处理程序中的 Lambda Hook 事件中检索这些信息。
const parameterName = process.env.PERMITTED_RUNTIMES_PARAM;
if (!parameterName) {
throw new Error('Permitted Runtimes Parameter is not set');
}
const resourceProperties = event.requestData.targetModel.resourceProperties;
// Check if this is a Lambda function resource
if (event.requestData.targetType !== 'AWS::Lambda::Function') {
console.log("Resource is not a Lambda function, skipping");
return {
hookStatus: 'SUCCESS',
message: 'Not a Lambda function resource, skipping validation',
clientRequestToken: event.clientRequestToken
}
}
// Check runtime version compliance
const runtime = resourceProperties.Runtime;
if (!runtime) {
console.log("Runtime not defined, failing");
return {
hookStatus: 'FAILURE',
errorCode: 'NonCompliant',
message: 'Runtime is required for Lambda functions',
clientRequestToken: event.clientRequestToken
}
}
然后,验证 Lambda 通过名为 ParameterStoreService 的实用程序类从 SSM 参数存储中检索配置参数的值。在这篇文章中,请考虑该配置参数中的值是一个字符串列表,其中每个字符串都包含一个可能的 Lambda 运行时值,您可以在此处找到该值(例如nodejs22.x,nodejs20.x,python3.11,python3.10,java17,java11,dotnet6)。检索该值后,验证 Lambda 会检查 Lambda 资源的运行时是否符合已配置的允许运行时。如果运行时不兼容,您将收到格式正确的响应,其失败状态为 HookStatus,否则响应将包含成功挂接状态。
// Retrieve configuration from Parameter Store
const compliantRuntimes = await parameterStoreService.getParameterFromStore(parameterName);
// Check if Lambda runtime is permitted or not
if (!compliantRuntimes.includes(runtime)) {
console.log("Runtime " + runtime + " not compliant ");
return {
hookStatus: 'FAILURE',
errorCode: 'NonCompliant',
message: `Runtime ${runtime} is not compliant. Please use one of: ${compliantRuntimes.join(', ')}`,
clientRequestToken: event.clientRequestToken
}
}
return {
hookStatus: 'SUCCESS',
message: 'Runtime version compliance check passed',
clientRequestToken: event.clientRequestToken
}
有关 CloudFormation Lambda Hooks Lambda 可能的响应值的更多信息,请查看此链接。
创建验证 Lambda — Lambda CloudFormation 定义
校验 Lambda 函数将通过 CloudFormation 在具有 CloudFormation Lambda Hook 定义和 Amazon Systems Manager 参数存储参数的同一个堆栈中部署。以下是包含其定义的 CloudFormation 模板的片段:
# Lambda Function
ValidationFunction:
Type: AWS::Lambda::Function
Properties:
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
S3Bucket: !Ref DeploymentBucket
S3Key: hook-lambda.zip
Runtime: nodejs22.x
Timeout: 60
MemorySize: 128
Environment:
Variables:
PERMITTED_RUNTIMES_PARAM: !Ref ParameterStoreParamName
您需要将 IAM 角色与适当的权限关联才能访问 Amazon Systems Manager 参数存储参数:
# Lambda Function Role
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# IAM Policy to access Parameter Store
ParameterStoreAccessPolicy:
Type: AWS::IAM::RolePolicy
Properties:
RoleName: !Ref LambdaExecutionRole
PolicyName: ParameterStoreAccess
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ssm:GetParameter
Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter${ParameterStoreParamName}
创建 CloudFormation Lambda
此时,你只需要编写一个合适的 CloudFormation Lambda Hook 即可。Hook 需要:
- 要在创建和更新 CloudFormation 操作期间激活,
- 仅考虑 AWS::Lambda::Function CloudFormation 资源
- 在 CloudFormation 模板的预配置期间采取行动
- 以堆栈和资源操作为目标
- 以已经定义的 Lambda 验证函数为目标
以下是 CloudFormation 模板中的定义:
# Lambda Hook
ValidationHook:
Type: AWS::CloudFormation::LambdaHook
Properties:
Alias: Private::Lambda::LambdaResourcesComplianceValidationHook
LambdaFunction: !GetAtt ValidationFunction.Arn
ExecutionRole: !GetAtt HookExecutionRole.Arn
FailureMode: FAIL
HookStatus: ENABLED
TargetFilters:
Actions:
- CREATE
- UPDATE
InvocationPoints:
- PRE_PROVISION
TargetNames:
- AWS::Lambda::Function
TargetOperations:
- RESOURCE
- STACK
请注意,上述模板包含对 IAM 角色的引用,因为挂钩需要适当的权限才能调用目标(Lambda 函数)。以下是 IAM 角色定义:
# Hook Execution Role
HookExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: hooks.cloudformation.amazonaws.com
Action: sts:AssumeRole
# IAM Policy for Lambda Invocation
LambdaInvokePolicy:
Type: AWS::IAM::RolePolicy
Properties:
RoleName: !Ref HookExecutionRole
PolicyName: LambdaInvokePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: !GetAtt ValidationFunction.Arn
配置兼容的运行时-使用系统管理器参数存储库
Amazon Systems Manager 参数存储是一项安全的分层存储服务,用于配置数据管理和密钥管理,允许用户存储和检索配置、数据库字符串等数据作为参数值。
在这个具体的示例中,我们将利用参数存储来存储我们允许的 Lambda 运行时配置。此配置值是一个 StringList 参数,包含以逗号分隔的允许运行时列表。以下是定义参数的 CloudFormation 模板的片段:
# Parameter Store Parameter
ConfigParameter:
Type: AWS::SSM::Parameter
Properties:
Name: !Ref ParameterStoreParamName
Type: StringList
Value: !Ref ParameterStoreDefaultValue
Description: "Configuration for Lambda Hook"
请注意在 "名称" 和 "值" 属性中使用了 CloudFormation 参数,允许在部署 CloudFormation 模板时进行动态输入。
部署解决方案
要部署解决方案,您可以利用存储库根文件夹deploy.sh中的脚本。此脚本将执行以下操作:
- 编译和构建验证 Lambda 函数
- 创建 Amazon S3 存储桶来存储 CloudFormation 模板
- 将 CloudFormation 模板和 Lambda 代码上传到 S3 存储桶
- 部署 CloudFormation 模板
测试 Lambda Hook
要测试 CloudFormation Lambda Hook,请部署一个包含 Hello World Lambda 函数的简单测试 CloudFormation 模板首先,测试使用允许的 Lambda 运行时配置的 Lambda,然后修改模板以使用不合规的运行时配置 Lambda。
以下是测试 CloudFormation 模板的初始定义:
# Lambda Function
HelloWorldFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: hello-world-function
Runtime: nodejs22.x
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
exports.handler = async (event, context) => {
console.log('Hello World!');
const response = {
statusCode: 200,
body: JSON.stringify('Hello World!')
};
return response;
};
Timeout: 30
MemorySize: 128
请注意,运行时值为 nodejs22.x,该值目前在允许的运行时列表中。预计该职能的部署将取得成功。
通过亚马逊云科技 CLI 部署此模板:
aws cloudformation deploy \
--template-file ./lambda_template.yml \
--capabilities CAPABILITY_IAM \
--stack-name lambda-sample
查看 CloudFormation 控制台:
图 2:显示成功部署堆栈的 CloudFormation 控制台
正如预期的那样,部署成功。通过查看 CloudWatch 日志,你还可以看到 CloudFormation Lambda Hook 已被调用:
图 3:验证成功后的 Lambda 函数日志
现在修改原始示例模板以设置不在允许运行时列表中的 Lambda 运行时:
# Lambda Function
HelloWorldFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: hello-world-function
Runtime: nodejs18.x
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Code:
ZipFile: |
exports.handler = async (event, context) => {
console.log('Hello World!');
const response = {
statusCode: 200,
body: JSON.stringify('Hello World!')
};
return response;
};
Timeout: 30
MemorySize: 128
使用之前使用的相同命令通过亚马逊云科技 CLI 部署此模板,然后检查 CloudFormation 控制台:
图 4:CloudFormation 控制台显示由于挂钩干预导致堆栈部署失败
正如预期的那样,部署不成功。CloudFormation Lambda Hook 已被调用,由于允许的运行时列表中不存在 Lambda 运行时,因此部署失败。
你还可以在 CloudWatch 日志中看到挂钩失败了:
图 5:验证出现验证错误的 Lambda 函数日志
清理
要清理与示例相关的资源,可以在sample文件夹cleanup_sample.sh内运行脚本。该脚本将通过亚马逊云科技 CLI 删除示例的 CloudFormation 模板。
要根据 Amazon CloudFormation Lambda Hook 清理与上述解决方案相关的资源,您可以利用仓库根文件夹cleanup.sh中的脚本。此脚本将执行以下操作:
- 删除 CloudFormation 堆栈
- 清空用于部署堆栈的 S3 存储桶
- 删除 S3 存储桶
结论
在这篇文章中,您探讨了如何实施 CloudFormation 挂钩,以在整个亚马逊云科技基础设施中强制执行 Lambda 函数的运行时合规性。通过利用 Lambda 挂钩的功能,您学习了如何创建预防性控件,在部署之前验证 Lambda 运行时配置。
通过激活 Lambda 挂钩并实现自定义 Lambda 函数验证器,您建立了一种自动化机制,确保在 CloudFormation 堆栈创建和更新期间,您的组织的 Lambda 函数中仅使用合规运行时。该解决方案与亚马逊云科技 CLI、亚马逊云科技 SAM、CI/CD 管道和亚马逊云科技 CDK 等常见开发工具集成,可以直接在现有工作流程中实施这些控制,无需手动运行时检查或部署后补救。
本文中演示的验证方法不仅限于 Lambda 运行时,可以适应 CloudFormation 支持的不同亚马逊云科技资源,从而允许您在亚马逊云科技提供的不同基础设施组件上执行策略。
作者简介
*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您发展海外业务和/或了解行业前沿技术选择推荐该服务。