CloudFormationによるAWS Configの有効化

# CloudFormationとは

CloudFormationとは……
って語ろうとしたんですが、うまい言葉が浮かばなかったので、AWSの公式サイトの説明を拝借します。

```
AWS CloudFormation は Amazon Web Services リソースのモデル化およびセットアップに役立つサービスです。
リソース管理に割く時間を減らし、AWS で実行するアプリケーションにより注力できるようになります。
使用するすべての AWS リソース (Amazon EC2 インスタンスや Amazon RDS DB インスタンスなど) を記述するテンプレートを作成すれば、AWS CloudFormation がお客さまに代わってこれらのリソースのプロビジョニングや設定を受け持ちます。
AWS リソースを個別に作成、設計して、それぞれの依存関係を考える必要はありません。
AWS CloudFormation がすべてを処理します。次のシナリオは AWS CloudFormation がどのように役立つかを示します。
```

元サイト：http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/Welcome.html

だそうです。

つまり、手作業でやってきたことを自動化して誰でも同じ構成をなるべく簡単に作れるようにしましょうっていうことだと思ってます。

# AWS Configとは

AWS Configとは……

ルールを設け、そのルールに適切に従った作成が行われているかどうかをチェックするAWSの一つのサービスです。（簡略説明）
CloudTrailと同じく有効化しておくことで、効果を発揮します。
AWS Configは各サービスの監視を行いますが、CloudTrailは各サービスへの操作を監視します。
両方を有効にしておくことで、セキュアで違反しているものがないかを調べることができます。

## 本題

AWSのCloudFormationを使って、AWS Configを有効化したい。（と思った。）
自社ではいろんな会社様からいろんな案件のご依頼をいただいており、少なくとも一案件一アカウントで運用しています。
その中で、毎回同じ作業を繰り返しているのですが、何回もやるのが手間なので、手順化しちゃおうという話が上がっています。

その中でドキュメントもなく、どう設定したらいいかわからなかったのが、AWS Configでした。

ほかのIAMRoleを作成するとかEC2を作成するとかVPNを作成するとかは記事をたくさん見かけたんですけど、AWS Configはやってる人が少ない（いない）ので、記事化したらcontribution増えるんじゃないかな、とかゲス顔で思ってます（ぉぃ

## jsonファイル

本題の苦労話やcontributionはどうでもいいから早くよこせという方向けに（ぉぃ）以下の通りCloudFormationを使用いただければうまく動作します。
なお、当CloudFormationを動かすことによりCloudTrailが有効かどうかチェックするルールも作成します。

```
{
    "Parameters": {
        "ConfigSnapshotDeliveryValue": {
            "Type": "String",
            "Default": "Six_Hours",
            "Description": "Config Snapshot Delivery Properties.",
            "MinLength": "1",
            "ConstraintDescription": "This parameter is required.",
            "AllowedValues": [
                "One_Hour",
                "Three_Hours",
                "Six_Hours",
                "Twelve_Hours",
                "TwentyFour_Hours"
            ]
        }
    },
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources": {
        "ConfigTopic": {
            "Type": "AWS::SNS::Topic",
            "Properties":{
                "DisplayName": "ConfigTopic",
                "TopicName": "ConfigTopic"
            }
        },
        "S3ConfigBucket": {
             "Type": "AWS::S3::Bucket",
             "Properties": {
                 "BucketName": {"Fn::Join" : ["", [ "config-bucket-", {"Ref":"AWS::AccountId"} ] ] }
             }
         },
        "IAMRoleConfig": {
            "Type": "AWS::IAM::Role",
            "Properties": {
                "RoleName": "ConfigRole",
                "AssumeRolePolicyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [{
                        "Effect": "Allow",
                        "Principal": { "Service": "config.amazonaws.com" },
                        "Action": "sts:AssumeRole"
                    }]
                },
                "ManagedPolicyArns": [ "arn:aws:iam::aws:policy/service-role/AWSConfigRole" ],
                "Policies": [{
                    "PolicyName": "AWSConfigRoleInlinePolicy",
                    "PolicyDocument": {
                        "Version": "2012-10-17",
                        "Statement": [{
                            "Effect": "Allow",
                            "Action": ["s3:PutObject*"],
                            "Resource": {"Fn::Join" : ["", [ "arn:aws:s3:::config-bucket-", {"Ref":"AWS::AccountId"}, "/AWSLogs/", {"Ref":"AWS::AccountId"}, "/*" ] ] },
                            "Condition": {
                                "StringLike": {
                                    "s3:x-amz-acl": "bucket-owner-full-control"
                                }
                            }
                        },
                        {
                            "Effect": "Allow",
                            "Action": ["s3:GetBucketAcl"],
                            "Resource": {"Fn::Join" : ["", [ "arn:aws:s3:::config-bucket-", {"Ref":"AWS::AccountId"} ] ] }
                        },
                        {
                            "Effect": "Allow",
                            "Action": "sns:Publish",
                            "Resource": {"Fn::Join" : ["", ["arn:aws:sns:ap-northeast-1:", {"Ref":"AWS::AccountId"} ] ] }
                        }]
                    }
                }]
            }
        },
        "DeliveryChannel": {
            "Type": "AWS::Config::DeliveryChannel",
            "Properties": {
                "ConfigSnapshotDeliveryProperties": {
                    "DeliveryFrequency": {"Ref": "ConfigSnapshotDeliveryValue"}
                },
                "S3BucketName": {"Ref": "S3ConfigBucket"},
                "SnsTopicARN": {"Ref": "ConfigTopic"}
            },
            "DependsOn": [
                "S3ConfigBucket",
                "ConfigTopic",
                "IAMRoleConfig"
            ]
        },
        "ConfigRecorder": {
            "Type": "AWS::Config::ConfigurationRecorder",
            "Properties": {
                "Name": "AWSConfigRecorder",
                "RecordingGroup": {
                    "IncludeGlobalResourceTypes": "TRUE",
                    "AllSupported": "TRUE"
                },
                "RoleARN": {"Fn::GetAtt" : ["IAMRoleConfig", "Arn"] }
            },
            "DependsOn": [
                "S3ConfigBucket",
                "ConfigTopic",
                "IAMRoleConfig"
            ]
        },
        "CloudTrailEnable": {
            "Type": "AWS::Config::ConfigRule",
            "Properties": {
                "ConfigRuleName": "cloudtrail-enabled",
                "Source": {
                    "Owner": "AWS",
                    "SourceIdentifier": "CLOUD_TRAIL_ENABLED"
                },
                "MaximumExecutionFrequency": "TwentyFour_Hours"
            },
            "DependsOn": [ "ConfigRecorder" ]
        }
    }
}
```

## jsonファイルの解説（が必要かどうかはともかくちょっとした解説やよもやま話）

### ルールのパラメータ化
ルール作成はパラメータ化できないかなーと思いましたけど、汎用的に作ろうとすると細かいチューニングが必要なのと、手動でルール追加できるし、案件によって使うものが変わってくるので、自動生成するのはCloudTrailのみ作ることにしました。

### 最初に必要だったものたち。後に必要だったものたち。
最初に必要だったのは三つです。
S3、SNSTopic、IAMロールの三つの作成です。
後から必要になったのは、DeliveryChannelとConfigurationRecorderです。
一から自分で作ろうとした際は、どこから着手するか悩んだのですが、少なくともConfigRuleだけでは成り立たないんだろう、とは思ってました。（他の作業との合間に作成したので、２ヶ月ほどかかりました）
とりあえずConfigurationRecorderを置いて、適当なIAMロールに紐付け、適当なS3に記録情報を保存しようとしたのですが、うまくいかず……。

### 模範解答を参考に。
解せぬ、ということで、他に情報がないか調べたのですが、皆目見当もつかない状況でした。
ただ、以下のヘルプを読む限り、DeliveryChannelが必要だぜ、おっさん、と言われた気がしたので、DeliveryChannelを作ったのですが、動かない……。正確には、初期処理から微動だにしない。（でも、AWS Configの画面は記録がオフ状態で色々設定できる画面には切り替わる）
http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-config-deliverychannel.html

ある案件を担当することになり、アカウントを開設しつつ、AWS Configを手動で有効化していました。
そこでふと気が付いたのは、これ参考にすればCloudFormation化できんじゃね？ってことです。

どうやらS3は既存のものでも問題ないものの、他に使用していないバケットが良さそうということ、SNSTopicも何かしら作成した方が良さそうなこと、IAMロールは…めんどくせって思いながら作りました。

そののち、２〜３日経て、当jsonファイルが仕上がりました。
何せDeliveryChannelの作成がS3、IAM、SNSの前でも問題ないのかConfigrationRecorderの後なのか順番がわからず２〜３日迷ってました。

# 作ってみた感想

作れたら満足しましたので公開することにしました。
情報がないんじゃ手も足も出せませんからね…。
SNSトピックはこうした方がいいとか、こういうパラメータどうですか、とかご意見いただければと思っています。

これで、私の評価もうなぎ上りだ（図に乗りすぎである）