

# 使用 AWS CloudFormation Guard 主动控制 Lambda
<a name="governance-cloudformation-guard"></a>

[AWS CloudFormation Guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html) 是一款开源、通用、策略即代码评估工具。通过根据策略规则验证基础设施即代码（IaC）模板和服务组合，可用于预防性治理和合规性。这些规则可以根据您的团队或组织的要求进行自定义。对于 Lambda 函数，Guard 规则可用于通过定义创建或更新 Lambda 函数时所需的属性设置来控制资源创建和配置更新。

合规性管理员定义部署和更新 Lambda 函数所需的控制和治理策略列表。平台管理员在 CI/CD 管道中实施控制，将其作为带有代码存储库的预提交验证 Webhook，并为开发人员提供命令行工具，以便在本地工作站上验证模板和代码。开发人员编写代码，使用命令行工具验证模板，然后将代码提交到存储库，在部署到 AWS 环境中之前，会自动通过 CI/CD 管道验证存储库。

Guard 允许您使用特定域的语言[编写规则](https://docs.aws.amazon.com/cfn-guard/latest/ug/writing-rules.html)和实施控制，如下所示。

 ![\[Guard rules include resource type, property name, operator, expression value, and optional comment\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/governance-cloudformation-guard.png) 

例如，假设要确保开发人员只选择最新的运行时系统。可以指定两种不同的策略，一种用于识别已弃用的[运行时系统](lambda-runtimes.md)，另一种用于识别即将弃用的运行时系统。为此，可以编写以下 `etc/rules.guard` 文件：

```
let lambda_functions = Resources.*[
    Type == "AWS::Lambda::Function"
]

rule lambda_already_deprecated_runtime when %lambda_functions !empty {
    %lambda_functions {
        Properties {
            when Runtime exists {
                Runtime !in ["dotnetcore3.1", "nodejs12.x", "python3.6", "python2.7", "dotnet5.0", "dotnetcore2.1", "ruby2.5", "nodejs10.x", "nodejs8.10", "nodejs4.3", "nodejs6.10", "dotnetcore1.0", "dotnetcore2.0", "nodejs4.3-edge", "nodejs"] <<Lambda function is using a deprecated runtime.>>
            }
        }
    }
}

rule lambda_soon_to_be_deprecated_runtime when %lambda_functions !empty {
    %lambda_functions {
        Properties {
            when Runtime exists {
                Runtime !in ["nodejs16.x", "nodejs14.x", "python3.7", "java8", "dotnet7", "go1.x", "ruby2.7", "provided"] <<Lambda function is using a runtime that is targeted for deprecation.>>
            }
        }
    }
}
```

现在，假设您编写了以下定义 Lambda 函数的 `iac/lambda.yaml` CloudFormation 模板：

```
  Fn:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      CodeUri: src
      Handler: fn.handler
      Role: !GetAtt FnRole.Arn
      Layers:
        - arn:aws:lambda:us-east-1:111122223333:layer:LambdaInsightsExtension:35
```

[安装](https://docs.aws.amazon.com/cfn-guard/latest/ug/setting-up.html) Guard 实用程序后，请验证您的模板：

```
cfn-guard validate --rules etc/rules.guard --data iac/lambda.yaml
```

该输出类似于以下示例：

```
lambda.yaml Status = FAIL
FAILED rules
rules.guard/lambda_soon_to_be_deprecated_runtime
---
Evaluating data lambda.yaml against rules rules.guard
Number of non-compliant resources 1
Resource = Fn {
  Type      = AWS::Lambda::Function
  Rule = lambda_soon_to_be_deprecated_runtime {
    ALL {
      Check =  Runtime not IN  ["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"] {
        ComparisonError {
          Message          = Lambda function is using a runtime that is targeted for deprecation.
          Error            = Check was not compliant as property [/Resources/Fn/Properties/Runtime[L:88,C:15]] was not present in [(resolved, Path=[L:0,C:0] Value=["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"])]
        }
          PropertyPath    = /Resources/Fn/Properties/Runtime[L:88,C:15]
          Operator        = NOT IN
          Value           = "python3.7"
          ComparedWith    = [["nodejs16.x","nodejs14.x","python3.7","java8","dotnet7","go1.x","ruby2.7","provided"]]
          Code:
               86.  Fn:
               87.    Type: AWS::Lambda::Function
               88.    Properties:
               89.      Runtime: python3.7
               90.      CodeUri: src
               91.      Handler: fn.handler

      }
    }
  }
}
```

 Guard 使开发人员从本地开发人员工作站看到他们需要更新模板才能使用组织允许的运行时系统。这种情况发生在提交到代码存储库以及随后在 CI/CD 管道中检查失败之前。这样一来，开发人员会收到有关如何开发合规模板，以及如何将时间转向编写可带来商业价值的代码的反馈。此控件可以应用于本地开发人员工作站、预提交验证 Webhook 和/或部署前的 CI/CD 管道中。

## 警告
<a name="governance-cloudformation-guard-considerations"></a>

如果您使用 AWS Serverless Application Model（AWS SAM）模板来定义 Lambda 函数，请注意，您需要更新 Guard 规则以搜索如下所示的 `AWS::Serverless::Function` 资源类型。

```
let lambda_functions = Resources.*[
    Type == "AWS::Serverless::Function"
]
```

Guard 还希望这些属性包含在资源定义中。同时，AWS SAM 模板使单独的 [Globals](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html) 部分中可以指定属性。Globals 部分中定义的属性不会通过您的 Guard 规则进行验证。

正如 Guard 故障排除[文档](https://docs.aws.amazon.com/cfn-guard/latest/ug/troubleshooting.html)中所述，请注意，Guard 不支持 `!GetAtt` 或 `!Sub` 之类的短格式内置函数，而是要求使用扩展形式 `Fn::GetAtt` 和 `Fn::Sub`。（[前面的示例](#guard-iac-yaml)没有评估 Role 属性，因此为了简单起见，使用了短格式内置函数。）