

# 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) は、オープンソースの汎用ポリシーアズコード評価ツールです。Infrastructure as Code (IaC) テンプレートとサービス構成をポリシールールに照らして検証することで、ガバナンスとコンプライアンスの予防を行えます。これらのルールは、チームや組織の要件に基づいてカスタマイズできます。Lambda 関数の場合、Lambda 関数の作成または更新時に必要なプロパティ設定を定義することで、Guard ルールを使用してリソースの作成と設定の更新を制御できます。

コンプライアンス管理者は、Lambda 関数のデプロイと更新に必要なコントロールとガバナンスポリシーのリストを定義します。プラットフォーム管理者は、コードリポジトリを備えたコミット前の検証 Webhook として CI/CD パイプラインにコントロールを実装し、ローカルワークステーションでテンプレートとコードを検証するためのコマンドラインツールを開発者に提供します。開発者はコードを作成し、コマンドラインツールでテンプレートを検証し、コードをリポジトリにコミットします。リポジトリは、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/ja_jp/lambda/latest/dg/images/governance-cloudformation-guard.png) 

例えば、開発者が必ず最新のランタイムのみを選択するように指定するとします。2 つの異なるポリシーを指定できます。1 つは廃止済みの[ランタイム](lambda-runtimes.md)を識別するためのもので、もう 1 つは間もなく廃止されるランタイムを識別するためのものです。これを行うには、以下の `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
```

Guard ユーティリティを[インストール](https://docs.aws.amazon.com/cfn-guard/latest/ug/setting-up.html)したら、テンプレートを検証します。

```
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 関数を定義する場合、以下のように `AWS::Serverless::Function` リソースタイプを検索するように Guard ルールを更新する必要があることに注意してください。

```
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 プロパティを評価していないため、簡潔にするために短縮形式の組み込み関数を使用しました)。