【AWS】CloudFormation Guardによるテンプレート評価手順

概要

CloudFormationのベストプラクティスの一つである下記に貢献できるツール”AWS CloudFormation Guard(cfn-guard)” を紹介します。

Validate templates before using them

Validate templates for organization policy compliance

引用:AWS CloudFormation best practices - AWS CloudFormation

<記載内容>

GitHubで公開されている3rd Party製CloudFormationテンプレート(以降 CFnテンプレート)の静的チェックツール"cfn-guard"の製品紹介です。インストールして動作させるための手順、評価ルール作成や評価時の具体的なコマンド例を記載しています。さらに、トライアルで利用した際に作成したポリシー例やTips集等、 cfn-guardを初めて使う方に役立つ情報をいくつか紹介します。
(注意)コマンドやルール例は、Markdownの都合上エスケープ処理をしています。そのため、コピー&ペーストでうまく動かない可能性があります。

アジェンダ

  1. AWS CloudFormation Guardとは
  2. Windows10へのインストール方法
  3. 使い方
  4. よく使う評価ルール
  5. 所感
  6. Tips
    • ymlで改行を表現する記法”|(パイプ)”が認識されない
    • 多段階層構造をもつパラメータの評価ルール自動生成時の注意点
    • List形式のパラメータの一部のみの評価ができない

1.AWS CloudFormation Guardとは

github.com

2.Windows10へのインストール方法

  • 公式(GitHub)のインストールガイドに従ってインストール可能。

Windows 10: Install Rust and Cargo

  1. Create a Windows 10 workspace.
  2. Install the version of Microsoft Visual C++ Build Tools 2019 which provides just the Visual C++ build tools: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019.
  3. Download the installer and run it.
  4. Select the "Individual Components" tab and check "Windows 10 SDK".
  5. Select the "Language Packs" tab and make sure that at least "English" is selected.
  6. Click "Install".
  7. Let it download and reboot if asked.
  8. Install Rust.
  9. Download rust-init.exe.
  10. Run it and accept the defaults.

    Cargo-based Installation

    Now that you have rust and cargo installed, installation of cfn-guard is easy: $ cargo install cfn-guard

引用:https://github.com/aws-cloudformation/cloudformation-guard#installation

(注意)上記の手順4についてですが、Windows 10 SDKだけではRustが正常に動作しませんでした。私の環境では、”個別のコンポーネント”ではなく、”ワークロード>C++によるデスクトップ開発”でインストールしたら問題なく動作するようになりました。

3.使い方 評価ルールの作り方

○ルールセット作成コマンド(コマンドプロンプト
$ cfn-guard rulegen -t [CFnテンプレート名] -o [ルールセット名]
例:cfn-guard rulegen -t test.yml -o test.ruleset
○実行例

読み込ませるCFnテンプレート(test.yml)

AWSTemplateFormatVersion: '2010-09-09'
Description: Sample template
Resources:
  SampleVolume:
    Type: AWS::EC2::Volume
    Properties:
      Encrypted: true
      Size: 10
      VolumeType: gp3

生成されるルールセット
EBSにPropertyとして設定した3つのパラメータを評価するルールが生成される。

let aws_ec2_volume_resources = Resources.*[ Type == 'AWS::EC2::Volume' ]
rule aws_ec2_volume when %aws_ec2_volume_resources !empty {​​
  %aws_ec2_volume_resources.Properties.Encrypted == true
  %aws_ec2_volume_resources.Properties.VolumeType == "gp3"
  %aws_ec2_volume_resources.Properties.Size == 10​​​​​​​​​
}

3.使い方 テンプレートの評価方法

  • 検査対象CFnテンプレートと検査内容が記載されたルールセットを引数にコマンドを実行する。
○評価コマンド(コマンドプロンプト
$ cfn-guard validate -d [CFnテンプレート名] -r [ルールセット名]
例:cfn-guard validate -d test.yml -r test.ruleset
○実行例

実行例1:ルールセットに準拠している場合
test.ymlを先ほど生成したルールで評価した例

test.yml Status = [32mPASS[0m[1mPASS rules[0m
test.ruleset/aws_ec2_volume    [32mPASS[0m
---
Evaluation of rules test.ruleset against data test.yml
--
Rule [test.ruleset/aws_ec2_volume] is compliant for template [test.yml]
-

実行例2:ルールセットに準拠していない場合
test.ymlを以下の通り変更してから評価した例

  • Encrypted: true → false
  • Size: 10 → 15
  • VolumeType: gp3 → gp2
test.yml Status = [1;31mFAIL[0m[1mFAILED rules[0m
test.ruleset/aws_ec2_volume    [1;31mFAIL[0m
---
Evaluation of rules test.ruleset against data test.yml
--
Property [/Resources/SampleVolume/Properties/Encrypted] in data [test.yml] is not compliant with [test.ruleset/aws_ec2_volume] because provided value [false] did not match expected value [true]. Error Message []
Property [/Resources/SampleVolume/Properties/VolumeType] in data [test.yml] is not compliant with [test.ruleset/aws_ec2_volume] because provided value ["gp2"] did not match expected value ["gp3"]. Error Message []
Property [/Resources/SampleVolume/Properties/Size] in data [test.yml] is not compliant with [test.ruleset/aws_ec2_volume] because provided value [15] did not match expected value [10]. Error Message []
--

4.よく使う評価ルール

作成したルールを何個か紹介します。
(補足)全てのルールを一つのルールセットファイルに記入しても問題なく動作します。各ルールの一行目(letから始まる行)で検査対象のルールセットを指定しているため、条件に合致しないルールはスキップされます。

  • KMSのキーローテーションが有効か
let aws_kms_key_resources = Resources.*[ Type == 'AWS::KMS::Key' ]
rule aws_kms_key when %aws_kms_key_resources !empty {
  %aws_kms_key_resources.Properties.EnableKeyRotation == true
}
let aws_kms_alias_resources = Resources.*[ Type == 'AWS::KMS::Alias' ]
rule aws_kms_alias when %aws_kms_alias_resources !empty {
  %aws_kms_alias_resources.Properties.AliasName == /alias\/(sample)-(.*)-(.*)/
}
  • Nameタグが付いているか
let aws_backup_backupvault_resources = Resources.*[ Type == 'AWS::Backup::BackupVault’ ]
rule aws_backup_backupvault when %aws_backup_backupvault_resources !empty{
  %aws_backup_backupvault_resources.Properties.BackupVaultTags == {"Name":/.*/}
}
  • S3がパブリック非公開か,暗号化しているか,ログを出力する設定になっているか
let aws_s3_bucket_resources = Resources.*[ Type == 'AWS::S3::Bucket' ]
rule aws_s3_bucket when %aws_s3_bucket_resources !empty {
  %aws_s3_bucket_resources.Properties.PublicAccessBlockConfiguration == {"BlockPublicAcls":true,"BlockPublicPolicy":true,"IgnorePublicAcls":true,"RestrictPublicBuckets":true}
  %aws_s3_bucket_resources.Properties.BucketEncryption.ServerSideEncryptionConfiguration !empty
  %aws_s3_bucket_resources.Properties.LoggingConfiguration !empty
}
  • LBがHTTPSだけListenしているか,最新のSSLポリシーを使用しているか
let aws_elasticloadbalancingv2_listener_resources = Resources.*[ Type == 'AWS::ElasticLoadBalancingV2::Listener' ]
rule aws_elasticloadbalancingv2_listener when %aws_elasticloadbalancingv2_listener_resources !empty {
  %aws_elasticloadbalancingv2_listener_resources.Properties.Protocol == "HTTPS"
  %aws_elasticloadbalancingv2_listener_resources.Properties.SslPolicy == "ELBSecurityPolicy-2016-08“
  %aws_elasticloadbalancingv2_listener_resources.Properties.Port == 443
}

5.所感

  • 主に規約違反やセキュリティ上好ましくない設定の検出に使用可能。
  • 他のセキュリティ系サービスと比較すると、実環境にデプロイする前にCFnテンプレートの段階でポリシー違反を検出できる点がCloudFormation Guardの特徴。
    • Config/Security Hub :デプロイ後のAWSリソースのパラメータを評価
    • Trusted Advisor :AWSリソースの稼働状況を評価
    • Guard Duty:不正なアクティビティを検知
  • プロジェクトや組織としてのポリシーが明確で、繰り返しCloudFormationを実行するような運用を行う場合は有用。
  • CFnテンプレートの記載の仕方によってはうまく評価できない。(Tipsを参照)

6.Tips

ymlで改行を表現する記法”|(パイプ)”が認識されない

ymlで改行を認識するための記法“|(パイプ)”が正しく認識されず、テンプレート上に下記例の様なコードが存在していると、rulegenの際にエラーとなる。

        Type: "AWS::KMS::Key"
        Properties:
            KeyPolicy:  !Sub |     ←この記法が認識されず、rulegenでエラーになる。
                {​​​​​​​
                  "Id" : "key-default-1",
                  "Version" : "2012-10-17",

⇒対処方法

  • 上述の例の構造を正しく評価する方法は見つけられなかった。
  • 一旦当該箇所をコメントアウトした上でrulegenを行えば、評価ルールの作成は可能。
  • validateの際は、テンプレート上存在していても(コメントアウトしていないくても)、問題なく評価可能

多段階層構造をもつパラメータの評価ルール自動生成時の注意点

階層構造のパラメータの例(BackupPlan)

List形式のパラメータの一部のみの評価ができない

リスト形式のパラメータの例(BackupPlanRule)

文字列の値については正規表現の評価が可能なため、"何かしらの値が存在すればよい"という様に実質的に無視することは可能。ただし、数値は正規表現で評価できなかった。