AWS Cloudformation Guardやってみた

記事タイトルとURLをコピーする

こんにちは!SRE2課の篠﨑です。

Cloudformation Guardご存じですか?私は知らなかったです。。。

docs.aws.amazon.com

本日、Build AWS Config rules using AWS CloudFormation Guardというアップデートを見て、気になったので簡単にやってみました。

こんな機能あるんだぁと思ってもらえたらと思います!

Cloudformation Guardとは?

ざっくりですが、作成したCloudFormationテンプレートがコンプライアンスに沿って作成されているかチェックするツールで、テンプレートを作成する端末にインストールをして利用することができます。

例えば、ルールとしてS3バケットは暗号化しないといけないというものがあった場合、CloudFormation Guardに記載します。 CloudFormation Guardで作成したS3用のCloudFormationがそのルールに沿っているかをチェックすることができます。

やってみた

概要を書いてみましたが、やってみた方が早いかなと思いますので、やってみました!

実行環境は Amazon Linux2ですが、WindowsやmacOSなども対応していますので、興味のある方はぜひやってみてください。

CloudFormation Guardのインストール

インストール方法はこちらです

docs.aws.amazon.com

Amazon Linux2で実行したコマンドは以下の通りです。

curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/aws-cloudformation/cloudformation-guard/main/install-guard.sh | sh

その後、公式ドキュメントでは以下のようにPATHを編集するようになっていますが、このようにするとcfn-guard以外のコマンドが打てなくなりますので、ご注意ください。

PATH=~/.guard/bin/

今回は~/.bash_profileに追記をし、再起動します。

echo 'export PATH="$HOME/.guard/bin:$PATH"' >> ~/.bash_profile 
sudo reboot

ルールの作成

どのようにルールを記載するのか、イメージを持ってもらうためCloudFormationからルールを作成します。

初めに以下のようなテンプレートファイルを作成します。 今回は、sample-s3.yamlというファイル名で保存しました。

Resources:
 S3Bucket:
   Type: "AWS::S3::Bucket"
   Properties:
     BucketName: "MyServiceS3Bucket"
     BucketEncryption:
       ServerSideEncryptionConfiguration:
         - ServerSideEncryptionByDefault:
             SSEAlgorithm: 'aws:kms'
             KMSMasterKeyID: 'arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400'
     Tags:
       - Key: "stage"
         Value: "prod"
       - Key: "service"
         Value: "myService"

次に、このテンプレートからルーツの抽出をして、test.guardというファイルに出力します。

cfn-guard rulegen --template sample-s3.yaml --output test.guard

test.guardは次のようになっていました。

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.Tags == [{"Key":"stage","Value":"prod"},{"Key":"service","Value":"myService"}]
  %aws_s3_bucket_resources.Properties.BucketName == "MyServiceS3Bucket"
  %aws_s3_bucket_resources.Properties.BucketEncryption == {"ServerSideEncryptionConfiguration":[{"ServerSideEncryptionByDefault":{"SSEAlgorithm":"aws:kms","KMSMasterKeyID":"arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400"}}]}

よく見ると、暗号化についてや、タグの設定、バケット名についてのルールが作成されました。 バケット名はすべてのAWSアカウントでユニークである必要があるため、バケット名はルールから削除します。

ルールに準拠しているかのチェック

次に、作成したルールにテンプレートが準拠しているかのチェックを行います。

$ cfn-guard validate --data sample-s3.yaml --output-format yaml --rules test.guard --show-summary all
Other
sample-s3.yaml Status = PASS
PASS rules
output.guard/aws_s3_bucket    PASS
---
---
name: ""
metadata: {}
status: PASS
not_compliant: []
not_applicable: []
compliant:
  - aws_s3_bucket

抽出した元となっているテンプレートファイルをチェックしているのでPASSするのは当たり前ですね。

それでは、以下のように、SSEAlgorithmeの部分を変更します。

Resources:
 S3Bucket:
   Type: "AWS::S3::Bucket"
   Properties:
     BucketName: "MyServiceS3Bucket"
     BucketEncryption:
       ServerSideEncryptionConfiguration:
         - ServerSideEncryptionByDefault:
             SSEAlgorithm: 'AES256'
     Tags:
       - Key: "stage"
         Value: "prod"
       - Key: "service"
         Value: "myService"

次に同じようにコマンドを打つとどうなるでしょうか。

$ cfn-guard validate --data sample-s3.yaml --output-format yaml --rules test.guard --show-summary all
Other
sample-s3.yaml Status = FAIL
FAILED rules
output.guard/aws_s3_bucket    FAIL
---
---
name: ""
metadata: {}
status: FAIL
not_compliant:
  - Rule:
      name: aws_s3_bucket
      metadata: {}
      messages:
        custom_message: ~
        error_message: ~
      checks:
        - Clause:
            Binary:
              context: " %aws_s3_bucket_resources[*].Properties.BucketEncryption EQUALS  {\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"aws:kms\",\"KMSMasterKeyID\":\"arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400\"}}]}"
              messages:
                custom_message: ""
                error_message: "Check was not compliant as property value [Path=/Resources/S3Bucket/Properties/BucketEncryption[L:7,C:40] Value={\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"AES256\"}}]}] not equal to value [Path=[L:0,C:0] Value={\"ServerSideEncryptionConfiguration\":[{\"ServerSideEncryptionByDefault\":{\"SSEAlgorithm\":\"aws:kms\",\"KMSMasterKeyID\":\"arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400\"}}]}]."
              check:
                Resolved:
                  from:
                    path: /Resources/S3Bucket/Properties/BucketEncryption
                    value:
                      ServerSideEncryptionConfiguration:
                        - ServerSideEncryptionByDefault:
                            SSEAlgorithm: AES256
                  to:
                    path: ""
                    value:
                      ServerSideEncryptionConfiguration:
                        - ServerSideEncryptionByDefault:
                            SSEAlgorithm: "aws:kms"
                            KMSMasterKeyID: "arn:aws:kms:us-east-1:123456789:key/056ea50b-1013-3907-8617-c93e474e400"
                  comparison:
                    - Eq
                    - false
not_applicable: []
compliant: []

すると、このようにルールに非準拠な箇所がFAILとして表示されました。

おわりに

今回はCloudFormation Guardについてインストールから実際に触ってみるところまでやってみました。

ドキュメントが日本語対応していないなど、少しとっつきにくいところはありますが、チーム単位で構築する際には利用してもいいかもしれないですね!

気になる方はぜひ触ってみてはいかがでしょうか!!

参考:

篠﨑 勇輔(書いた記事を見る)

クラウドインテグレーション部 SRE2課

入社3年目