AWS CloudFormation Guard による Lambda のプロアクティブコントロール - AWS Lambda

AWS CloudFormation Guard による Lambda のプロアクティブコントロール

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

コンプライアンス管理者は、Lambda 関数のデプロイと更新に必要なコントロールとガバナンスポリシーのリストを定義します。プラットフォーム管理者は、コードリポジトリを備えたコミット前の検証 Webhook として CI/CD パイプラインにコントロールを実装し、ローカルワークステーションでテンプレートとコードを検証するためのコマンドラインツールを開発者に提供します。開発者はコードを作成し、コマンドラインツールでテンプレートを検証し、コードをリポジトリにコミットします。リポジトリは、AWS 環境へのデプロイ前に CI/CD パイプラインを介して自動的に検証されます。

Guard では、以下のようにドメイン固有の言語を使用してルールを記述し、コントロールを実装できます。

Guard rules include resource type, property name, operator, expression value, and optional comment

例えば、開発者が必ず最新のランタイムのみを選択するように指定するとします。2 つの異なるポリシーを指定できます。1 つは廃止済みのランタイムを識別するためのもので、もう 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 ユーティリティをインストールしたら、テンプレートを検証します。

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 パイプラインに適用できます。

注意

AWS Serverless Application Model (AWS SAM) テンプレートを使用して Lambda 関数を定義する場合、以下のように AWS::Serverless::Function リソースタイプを検索するように Guard ルールを更新する必要があることに注意してください。

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

Guard では、プロパティがリソース定義に含まれていることも想定しています。一方、AWS SAM テンプレートではプロパティを別の [Globals] セクションで指定できます。Globals セクションで定義されているプロパティは、Guard ルールでは検証されません。

Guard のトラブルシューティングドキュメントで説明されているように、Guard は !GetAtt!Sub のような短縮形式の組み込み関数をサポートしておらず、Fn::GetAttFn::Sub の拡張形式を使用する必要があることに注意してください。(前の例では Role プロパティを評価していないため、簡潔にするために短縮形式の組み込み関数を使用しました)。