AWS Configの初期設定とマネージドルールを Terraform で設定して、非準拠項目を確認して対処してみる

# 1. はじめに
* AWS Config の初期設定を Terraform (v0.12.9) を使って設定する。
* ついでに、AWS Config マネージドルールを全く設定していなかったので、これも Terraform で設定して、現状の設定が AWS推奨のベストプラクティスに準拠しているかを確認してみる。
* 非準拠対応をしてみる。

# 2. AWS Config 設定の目的
AWS Config の「記録をオン」に設定することで、指定したリソースの変更履歴やイベント履歴のデータを S3 へ格納するす（デフォルトの期間は7年）。このデータを利用して、例えば次のことができるようになる。

* 「ダッシュボード」を使うと、履歴データを可視化してリソースの関係性を確認したり、設定変更やイベント発生を時系列で確認したりできる。<br />⇒ 簡単なトラブルシューティング、リソースの変更内容確認など。

* 「高度なクエリ」を使うと、履歴データへクエリを発行して詳細な分析ができる。<br />⇒ 高度なトラブルシューティング、セキュリティ分析など。

* 「Configルール」を使うと、リソースがAWS推奨のベストプラクティスに準拠しているかや、各企業独自のコンプライアンスに違反していないかを評価することができる。<br /> ⇒ セキュリティチェック、ベストプラクティス準拠チェック、コンプライアンス違反チェックなど。

参考
・[AWS Docs: AWS Configとは](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/WhatIsConfig.html)
・[AWS Docs: AWS Config の概念](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/config-concepts.html)
・[AWS Docs: AWS Config の仕組み](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/how-does-config-work.html)


# 3. AWS Config の初期設定を Terraform (v0.12.9) を使って設定する

### 3.1. Terraform構成

```
anyservice/
└── anyenv
    ├── awsconfig
    │   ├── backend.tf
    │   ├── main.tf
    │   ├── provider.tf -> ../../../provider.tf
    │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
    ├── iam
    │   ├── aws-config.tf
    │   ├── backend.tf
    │   ├── provider.tf -> ../../../provider.tf
    │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
    └── s3
        ├── awsconfig.tf
        ├── backend.tf
        └── provider.tf -> ../../../provider.tf
```

### 3.2. provider.tf, credentials

* provider.tf

```provider.tf
provider "aws" {
  version                 = "2.48.0"
  shared_credentials_file = "../../../credentials"
  profile                 = "terraform"
  region                  = "ap-northeast-1"
}
```

* credentials

```
[terraform]
aws_access_key_id = チョメチョメ
aws_secret_access_key = チョメチョメ
```

### 3.3. 履歴データを格納する S3 バケットを作成

* 作成概要
 * バケット名: awsconfig-AWSアカウントID
 * リージョン: ap-northeast-1
 * バージョニング: 有効
 * バケットポリシー設定

* anyservice/anyenv/s3/backend.tf

```backend.tf
terraform {
  required_version = ">= 0.12.9"
  backend "s3" {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    region                  = "ap-northeast-1"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/s3/terraform.tfstate"
  }
}
```


* anyservice/anyenv/s3/awsconfig.tf

```awsconfig.tf
data "aws_caller_identity" "current" {
}
resource "aws_s3_bucket" "awsconfig" {
  bucket        = "awsconfig-${data.aws_caller_identity.current.account_id}"
  acl           = "private"
  force_destroy = "false"
  region        = "ap-northeast-1"
  versioning {
    enabled = true
  }
}
data "aws_iam_policy_document" "s3bucket_policy-awsconfig" {
  version = "2012-10-17"
  statement {
    sid    = "AWSConfigBucketPermissionsCheck"
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["config.amazonaws.com"]
    }
    actions = [
      "s3:GetBucketAcl"
    ]
    resources = [
      "${aws_s3_bucket.awsconfig.arn}"
    ]
  }
  statement {
    sid    = "AWSConfigBucketDelivery"
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["config.amazonaws.com"]
    }
    actions = [
      "s3:PutObject"
    ]
    resources = [
      "${aws_s3_bucket.awsconfig.arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/Config/*"
    ]
    condition {
      test     = "StringEquals"
      variable = "s3:x-amz-acl"
      values   = ["bucket-owner-full-control"]
    }
  }
}
resource "aws_s3_bucket_policy" "awsconfig" {
  bucket = "${aws_s3_bucket.awsconfig.bucket}"
  policy = "${data.aws_iam_policy_document.s3bucket_policy-awsconfig.json}"
}
output "awsconfig_arn" {
  value = aws_s3_bucket.awsconfig.arn
}
output "awsconfig_name" {
  value = aws_s3_bucket.awsconfig.id
}
```

* terraform_remote_state.tf

```terraform_remote_state.tf
data "terraform_remote_state" "S3" {
  backend = "s3"
  config = {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    region                  = "ap-northeast-1"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/s3/terraform.tfstate"
  }
}
```

### 3.4. IAMポリシー、ロールを作成する

* 作成概要
 * IAMポリシー名: awsconfig
 * IAMロール名: awsconfig
 * 信頼されたエンティティ: config.amazonaws.com
 * アタッチするポリシー: AWSConfigRole（AWS 管理ポリシー）, awsconfig（管理ポリシー）

* anyservice/anyenv/iam/backend.tf

```backend.tf
terraform {
  required_version = ">= 0.12.9"
  backend "s3" {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    region                  = "ap-northeast-1"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/iam/terraform.tfstate"
  }
}
```

* anyservice/anyenv/iam/awsconfig.tf

```awsconfig.tf
data "aws_caller_identity" "current" {
}
data "aws_iam_policy_document" "assume_role_policy-awsconfig" {
  version = "2012-10-17"
  statement {
    sid    = ""
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["config.amazonaws.com"]
    }
    actions = [
      "sts:AssumeRole"
    ]
  }
}
resource "aws_iam_role" "role_awsconfig" {
  name               = "awsconfig"
  path               = "/service-role/"
  assume_role_policy = "${data.aws_iam_policy_document.assume_role_policy-awsconfig.json}"
}
resource "aws_iam_role_policy_attachment" "awsconfig_AWSConfigRole" {
  role       = aws_iam_role.role_awsconfig.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSConfigRole"
}
data "aws_iam_policy_document" "iam_policy-awsconfig" {
  version = "2012-10-17"
  statement {
    effect = "Allow"
    actions = [
      "s3:PutObject*"
    ]
    resources = [
      "${data.terraform_remote_state.S3.outputs.awsconfig_arn}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"
    ]
    condition {
      test     = "StringLike"
      variable = "s3:x-amz-acl"
      values   = ["bucket-owner-full-control"]
    }
  }
  statement {
    effect = "Allow"
    actions = [
      "s3:GetBucketAcl"
    ]
    resources = [
      data.terraform_remote_state.S3.outputs.awsconfig_arn
    ]
  }
}
resource "aws_iam_policy" "iam_policy-awsconfig" {
  name   = "awsconfig"
  policy = "${data.aws_iam_policy_document.iam_policy-awsconfig.json}"
}
resource "aws_iam_role_policy_attachment" "awsconfig" {
  role       = aws_iam_role.role_awsconfig.name
  policy_arn = "${aws_iam_policy.iam_policy-awsconfig.arn}"
}
output "role_awsconfig_arn" {
  value = aws_iam_role.role_awsconfig.arn
}
```

* terraform_remote_state.tf

```terraform_remote_state.tf
data "terraform_remote_state" "IAM" {
  backend = "s3"
  config = {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    region                  = "ap-northeast-1"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/iam/terraform.tfstate"
  }
}
```

### 3.5. AWS Config を作成する

* 作成概要
 * 名前: awsconfig-AWSアカウントID
 * AWS Config ロール名: awsconfig
 * 記録するリソースタイプ
      - このリージョンでサポートされているすべてのリソースを記録する
      - グローバルリソース (AWS IAM リソースなど) を含める
 * 配信方法:
        - S3バケット: awsconfig-アカウントID
        - SNS トピック名: - （今回は AWS Config から SNS への通知設定はしない）
 * データ保持期間: デフォルト（７年）

* anyservice/anyenv/awsconfig/backend.tf

```backend.tf
terraform {
  required_version = ">= 0.12.9"
  backend "s3" {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    region                  = "ap-northeast-1"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/awsconfig/terraform.tfstate"
  }
}
```

* anyservice/anyenv/awsconfig/main.tf

```main.tf
data "aws_caller_identity" "current" {
}
resource "aws_config_configuration_recorder" "awsconfig" {
  name     = "awsconfig-${data.aws_caller_identity.current.account_id}"
  role_arn = data.terraform_remote_state.IAM.outputs.role_awsconfig_arn
  recording_group {
    all_supported                 = "true"
    include_global_resource_types = "true"
  }
}
resource "aws_config_delivery_channel" "awsconfig" {
  name           = "awsconfig-${data.aws_caller_identity.current.account_id}"
  s3_bucket_name = data.terraform_remote_state.S3.outputs.awsconfig_name
  depends_on     = ["aws_config_configuration_recorder.awsconfig"]
  snapshot_delivery_properties {
    delivery_frequency = "One_Hour"
  }
}
```

* AWS Config を作成すると、「記録はオン」となり、履歴データが S3 バケットへ配信される。

|![20200217-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/a15324cb-89b4-5c99-9fb3-bb336ba82555.png)|
|:-:|

# 4. 「3.」で作成した設定の確認

### 4.1. 履歴データを格納する S3 バケット (awsconfig-AWSアカウントID）のバケットポリシー

|![20200217-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/e2073ac1-2237-da7c-3be1-8239497854d3.png)|
|:-:|

### 4.2. IAMポリシー（awsconfig）

|![20200217-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/e788e44c-e819-d80d-9709-bb0397843178.png)|
|:-:|

### 4.3. IAMロール（awsconfig）

|![20200217-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/412371d1-a91d-378a-b2a3-f4ee142d1754.png)|
|:-:|

|![20200217-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/fd3b3f0c-b71d-62cc-41fb-69ec9bcf7b7f.png)|
|:-:|

### 4.4. AWS Config

|![20200217-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/07d69313-680d-fe27-c264-41285bd596fd.png)|
|:-:|

# 5. AWS Config ルール

### 5.1. AWS Config ルールは２通りある

* マネージドルール（AWS側で作成して提供しているルール）
 * 定義済みのカスタマイズ可能なルールであり、AWS リソースが一般的なベストプラクティスに準拠しているかどうかを評価するために AWS Config で使用します。
 * [AWSが提供している AWS Config マネージドルールのリスト](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/managed-rules-by-aws-config.html)の中から利用したいものを選んでルールの使用を有効にする。
 * ルールを有効化すると、AWS Config はリソースをルールの条件と比較します。この初期評価後は、評価がトリガーされるたびに AWS Config で評価が実行されます。
 * 評価のトリガーは２タイプある
      - 設定変更 – ルールの範囲に該当するリソースで設定が変更されると、AWS Config によって評価がトリガーされます。
      - 定期的 – 指定した間隔 (24 時間ごとなど) で、AWS Config でのルールの評価が実行されます。

* カスタムルール（ユーザ側で作成するルール）
 * カスタムルールを作成して AWS Config に追加できます。各カスタムルールは AWS Lambda 関数と関連付けます。この関数には、AWS リソースがルールに準拠しているかどうかを評価するロジックが含まれています。
 * この関数をルールに関連付け、設定変更または定期的な間隔に応じてルールから関数を呼び出します。
 * 次に、関数はリソースがルールに準拠しているかどうかを評価し、評価結果を AWS Config に送信します。

引用
・ [AWS Docs: AWS Config マネージドルール](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/evaluate-config_use-managed-rules.html)
・ [AWS Docs: AWS Config カスタムルール](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/evaluate-config_develop-rules.html)


### 5.2. 今回使用するマネージドルール
* **分析**
 * [elasticache-redis-cluster-automatic-backup-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/elasticache-redis-cluster-automatic-backup-check.html)
     - Amazon ElastiCache Redis クラスターで自動バックアップが有効になっているかどうかを確認します。

* **コンピューティング**
 * [ebs-optimized-instance](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ebs-optimized-instance.html)
     - EBS 最適化できる EC2 インスタンスに対して EBS 最適化が有効になっているかどうかを確認します。
 * [ec2-stopped-instance](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ec2-stopped-instance.html)
     - 許可されている日数よりも長く停止しているインスタンスがあるかどうかを確認します。
     - デフォルトは30日。ここでは、６０日に設定する。
 * [ec2-instance-managed-by-systems-manager](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ec2-instance-managed-by-ssm.html)
     - アカウントの Amazon EC2 インスタンスが AWS Systems Manager で管理されているかどうかを確認します。 
 * [ec2-security-group-attached-to-eni](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ec2-security-group-attached-to-eni.html)
     - セキュリティグループが EC2 インスタンスまたは Elastic Network Interface にアタッチされていることを確認します。
 * [ec2-volume-inuse-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ec2-volume-inuse-check.html)
     - EBS ボリュームが EC2 インスタンスにアタッチされているかどうかを確認します。
 * [eip-attached](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/eip-attached.html)
     - VPC に割り当てられたすべての Elastic IP アドレスが、EC2 インスタンスまたは使用中の Elastic Network Interface (ENI) にアタッチされているかどうかを確認します。 
 * [elb-logging-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/elb-logging-enabled.html)
      - Application Load Balancer と クラシックロードバランサー でログ記録が有効になっているかどうかを確認します。
 * [restricted-ssh](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/restricted-ssh.html)
     - セキュリティグループの受信 SSH トラフィックがアクセス可能かどうかを確認します。

* **データベース**
 * [db-instance-backup-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/db-instance-backup-enabled.html)
     - RDS DB インスタンスでバックアップが有効になっているかどうかを確認します。
 * [dynamodb-throughput-limit-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/dynamodb-throughput-limit-check.html)
     - DynamoDB プロビジョンドスループットがアカウントの上限に近づいているかどうかを確認します。
 * [rds-instance-public-access-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/rds-instance-public-access-check.html)
     - Amazon Relational Database Service インスタンスがパブリックにアクセス可能でないかどうかを確認します。
 * [rds-multi-az-support](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/rds-multi-az-support.html)
     - RDS DB インスタンスの高可用性が有効になっているかどうかを確認します。
 * [rds-snapshots-public-prohibited](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/rds-snapshots-public-prohibited.html)
     - Amazon Relational Database Service (Amazon RDS) スナップショットがパブリックかどうかを確認します。

* **マネジメントとガバナンス**
 * [cloud-trail-cloud-watch-logs-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/cloud-trail-cloud-watch-logs-enabled.html)
     - AWS CloudTrail 証跡がログを Amazon CloudWatch Logs に送信するように設定されているかどうかを確認します。
 * [cloudtrail-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/cloudtrail-enabled.html)
     - AWS アカウントで AWS CloudTrail が有効になっているかどうかを確認します。
 * [cloud-trail-encryption-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/cloud-trail-encryption-enabled.html)
     - AWS CloudTrail がサーバー側の暗号化 (SSE) AWS Key Management Service (AWS KMS) カスタマーマスターキー (CMK) 暗号化を使用するよう設定されているかどうかを確認します。
 * [cloud-trail-log-file-validation-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/cloud-trail-log-file-validation-enabled.html)
     - AWS CloudTrail でログを含むダイジェストファイルを作成するかどうかを確認します。
 * [cloudtrail-s3-dataevents-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/cloudtrail-s3-dataevents-enabled.html)
     - 少なくとも 1 つの AWS CloudTrail 証跡がすべての S3 バケットの Amazon S3 データイベントをログ記録しているかどうかを確認します。
 * [multi-region-cloud-trail-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/multi-region-cloud-trail-enabled.html)
     - マルチリージョン AWS CloudTrail が少なくとも 1 つあることを確認します。

* **ネットワークとコンテンツ配信**
 * [internet-gateway-authorized-vpc-only](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/internet-gateway-authorized-vpc-only.html)
     - インターネットゲートウェイ (IGW) が承認された Amazon Virtual Private Cloud (VPC) にのみアタッチされていることを確認します。
     - authorizedVpcIds パラメータに、IGWのアタッチが許可されたVPCのidをリストする（複数ある場合はカンマ区切り）。
 * [vpc-default-security-group-closed](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/vpc-default-security-group-closed.html)
     - いずれの Amazon Virtual Private Cloud (VPC) のデフォルトのセキュリティグループでもインバウンドとアウトバウンドのいずれのトラフィックも許可しないことを確認します。
 * [vpc-flow-logs-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/vpc-flow-logs-enabled.html)
     - Amazon Virtual Private Cloud フローログが見つかり、Amazon VPC に対して有効になっているかどうかを確認します。

* **セキュリティ、アイデンティティ、コンプライアンス**
 * [access-keys-rotated](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/access-keys-rotated.html)
     - アクティブなアクセスキーが、maxAccessKeyAge で指定された日数内にローテーションされるかどうかを確認します。
     - デフォルトは9０日。ここでは１８０日に設定する。
 * [acm-certificate-expiration-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/acm-certificate-expiration-check.html)
     - アカウントの ACM 証明書が、指定の日数内に有効期限切れとしてマークされているかどうかを確認します。
     - ここでは14日に設定する。
 * [iam-group-has-users-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-group-has-users-check.html)
     - IAM グループに少なくとも 1 つの IAM ユーザーが存在するかどうかを確認します。
 * [iam-password-policy](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-password-policy.html)
     - IAM ユーザーのアカウントパスワードポリシーが、指定した要件を満たしているかどうかを確認します。
     - ここではパスワードポリシーを次のとおりに決める。
         - MaxPasswordAge             = "90"
         - MinimumPasswordLength      = "12"
         - PasswordReusePrevention    = "3"
         - RequireLowercaseCharacters = "true"
         - RequireNumbers             = "true"
         - RequireSymbols             = "true"
         - RequireUppercaseCharacters = "true"
 * [iam-root-access-key-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-root-access-key-check.html)
     - ルートユーザーアクセスキーがあるかどうかを確認します。ユーザーアクセスキーが存在しない場合、ルールは COMPLIANT です。
 * [iam-user-group-membership-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-user-group-membership-check.html)
     - IAM ユーザーが少なくとも 1 つの IAM グループのメンバーであるかどうかを確認します。
 * [iam-user-no-policies-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-user-no-policies-check.html)
     - いずれの IAM ユーザーにもポリシーがアタッチされていないことを確認します。IAM ユーザーは、IAM グループまたはロールからアクセス許可を継承する必要があります。
 * [iam-user-unused-credentials-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/iam-user-unused-credentials-check.html)
     - IAMユーザーが、指定した日数以内に使用されたことのないパスワードまたはアクティブなアクセスキーを持っているかどうかを確認します。
     - デフォルトは90日。ここでは180日に設定する。
 * [mfa-enabled-for-iam-console-access](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/mfa-enabled-for-iam-console-access.html)
     - コンソールパスワードを使用するすべての IAM ユーザーについて MFA が有効になっているかどうかを確認します。
 * [root-account-mfa-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/root-account-mfa-enabled.html)
     - AWS アカウントのユーザーが、ルートの認証情報を使用してサインインする際に MFA デバイスが必要かどうかを確認します。

* **ストレージ**
 * [ebs-snapshot-public-restorable-check](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/ebs-snapshot-public-restorable-check.html)
     - Amazon Elastic Block Store のスナップショットがパブリックで復元可能でないかどうかを確認します。
 * [elb-deletion-protection-enabled](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/elb-deletion-protection-enabled.html)
     - Elastic Load Balancing で削除保護が有効になっているかどうかを確認します。
 * [s3-account-level-public-access-blocks](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-account-level-public-access-blocks.html)
     - 必要なパブリックアクセスブロック設定がアカウントレベルから設定されているかどうかを確認します。
 * [s3-bucket-public-read-prohibited](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-public-read-prohibited.html)
     - Amazon S3 バケットでパブリック読み取りアクセスが許可されないことを確認します。
 * [s3-bucket-public-write-prohibited](https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-public-write-prohibited.html)
     - Amazon S3 バケットでパブリック書き込みアクセスが許可されないことを確認します。

# 6. AWS Config ルールの設定を Terraform (v0.12.9）を使って設定する

### 6.1. Terraform構成

「3.1. Terraform構成」に次のファイルを追加

* AWS Config ルールを設定する terraform
 * anyservice/anyenv/awsconfig/config-rule.tf

* AWS Config ルールからの通知を Amazon SNS へ送るための CloudWatch Events を設定する terraform
 * anyservice/anyenv/cloudwatchevents 

```
anyservice/
└── anyenv
    ├── awsconfig
    │   ├── backend.tf
    │   ├── config-rule.tf
    │   ├── main.tf
    │   ├── provider.tf -> ../../../provider.tf
    │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
    ├── cloudwatchevents
    │   ├── awsconfig.tf
    │   ├── backend.tf
    │   ├── provider.tf -> ../../../provider.tf
    ├── iam
    │   ├── aws-config.tf
    │   ├── backend.tf
    │   ├── provider.tf -> ../../../provider.tf
    │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
    └── s3
        ├── awsconfig.tf
        ├── backend.tf
        └── provider.tf -> ../../../provider.tf
```

### 6.2. AWS Config ルールからの通知を Amazon SNS へ送るための CloudWatch Events を作成する

* 作成概要
 * CloudWatch イベントルール名: AWSConfig
 * イベントパターン:
     -  source: aws.config
     -  detail-type: "Config Rules Compliance Change"
 * ターゲット: SNS トピック（適当なものを使うか、新規で作るか。AWS Chatbot にも対応している。）

* anyservice/anyenv/cloudwatchevents/awsconfig.tf

```awsconfig.tf
resource "aws_cloudwatch_event_rule" "awsconfig" {
  name = "AWSConfig"
  event_pattern = jsonencode(
    {
      detail-type = [
        "Config Rules Compliance Change",
      ]
      source = [
        "aws.config",
      ]
    }
  )
}
resource "aws_cloudwatch_event_target" "awsconfig" {
  rule      = "${aws_cloudwatch_event_rule.awsconfig.name}"
  arn       = "SNSトピックの ARN"
}
```

### 6.3. AWS Config ルールを作成する

* 作成概要
 * 作成する Config ルール: 「5.2. 今回使用するマネージドルール」
 * 初回作成後（ルール適用直後）は、SNSに大量に通知が飛んでくる。

* anyservice/anyenv/awsconfig/config-rule.tf

```config-rule.tf
#------------------------------------------------------------
# AWS Config Rule
#------------------------------------------------------------
#
# Analytics
#
resource "aws_config_config_rule" "elasticache-redis-cluster-automatic-backup-check" {
  name = "elasticache-redis-cluster-automatic-backup-check"
  source {
    owner             = "AWS"
    source_identifier = "ELASTICACHE_REDIS_CLUSTER_AUTOMATIC_BACKUP_CHECK"
  }
}
#
# Compute
#
resource "aws_config_config_rule" "ebs-optimized-instance" {
  name = "ebs-optimized-instance"
  source {
    owner             = "AWS"
    source_identifier = "EBS_OPTIMIZED_INSTANCE"
  }
}
resource "aws_config_config_rule" "ec2-stopped-instance" {
  name = "ec2-stopped-instance"
  source {
    owner             = "AWS"
    source_identifier = "EC2_STOPPED_INSTANCE"
  }
  input_parameters = jsonencode(
    {
      AllowedDays = "60"
    }
  )
}
resource "aws_config_config_rule" "ec2-instance-managed-by-systems-manager" {
  name = "ec2-instance-managed-by-systems-manager"
  source {
    owner             = "AWS"
    source_identifier = "EC2_INSTANCE_MANAGED_BY_SSM"
  }
}
resource "aws_config_config_rule" "ec2-security-group-attached-to-eni" {
  name = "ec2-security-group-attached-to-eni"
  source {
    owner             = "AWS"
    source_identifier = "EC2_SECURITY_GROUP_ATTACHED_TO_ENI"
  }
}
resource "aws_config_config_rule" "ec2-volume-inuse-check" {
  name = "ec2-volume-inuse-check"
  source {
    owner             = "AWS"
    source_identifier = "EC2_VOLUME_INUSE_CHECK"
  }
}
resource "aws_config_config_rule" "eip-attached" {
  name = "eip-attached"
  source {
    owner             = "AWS"
    source_identifier = "EIP_ATTACHED"
  }
  scope {
    compliance_resource_types = [
      "AWS::EC2::EIP"
    ]
  }
}
resource "aws_config_config_rule" "elb-logging-enabled" {
  name = "elb-logging-enabled"
  source {
    owner             = "AWS"
    source_identifier = "ELB_LOGGING_ENABLED"
  }
  scope {
    compliance_resource_types = [
      "AWS::ElasticLoadBalancing::LoadBalancer",
      "AWS::ElasticLoadBalancingV2::LoadBalancer"
    ]
  }
}
resource "aws_config_config_rule" "restricted-ssh" {
  name = "restricted-ssh"
  source {
    owner             = "AWS"
    source_identifier = "INCOMING_SSH_DISABLED"
  }
  scope {
    compliance_resource_types = [
      "AWS::EC2::SecurityGroup"
    ]
  }
}
#
# Database
#
resource "aws_config_config_rule" "db-instance-backup-enabled" {
  name = "db-instance-backup-enabled"
  source {
    owner             = "AWS"
    source_identifier = "DB_INSTANCE_BACKUP_ENABLED"
  }
}
resource "aws_config_config_rule" "dynamodb-throughput-limit-check" {
  name = "dynamodb-throughput-limit-check"
  source {
    owner             = "AWS"
    source_identifier = "DYNAMODB_THROUGHPUT_LIMIT_CHECK"
  }
}
resource "aws_config_config_rule" "rds-instance-public-access-check" {
  name = "rds-instance-public-access-check"
  source {
    owner             = "AWS"
    source_identifier = "RDS_INSTANCE_PUBLIC_ACCESS_CHECK"
  }
  scope {
    compliance_resource_types = [
      "AWS::RDS::DBInstance"
    ]
  }
}
resource "aws_config_config_rule" "rds-multi-az-support" {
  name = "rds-multi-az-support"
  source {
    owner             = "AWS"
    source_identifier = "RDS_MULTI_AZ_SUPPORT"
  }
  scope {
    compliance_resource_types = [
      "AWS::RDS::DBInstance"
    ]
  }
}
resource "aws_config_config_rule" "rds-snapshots-public-prohibited" {
  name = "rds-snapshots-public-prohibited"
  source {
    owner             = "AWS"
    source_identifier = "RDS_SNAPSHOTS_PUBLIC_PROHIBITED"
  }
  scope {
    compliance_resource_types = [
      "AWS::RDS::DBInstance"
    ]
  }
}
#
# Management and Governance
#
resource "aws_config_config_rule" "cloud-trail-cloud-watch-logs-enabled" {
  name = "cloud-trail-cloud-watch-logs-enabled"
  source {
    owner             = "AWS"
    source_identifier = "CLOUD_TRAIL_CLOUD_WATCH_LOGS_ENABLED"
  }
}
resource "aws_config_config_rule" "cloudtrail-enabled" {
  name = "cloudtrail-enabled"
  source {
    owner             = "AWS"
    source_identifier = "CLOUD_TRAIL_ENABLED"
  }
  maximum_execution_frequency = "TwentyFour_Hours"
}
resource "aws_config_config_rule" "cloud-trail-encryption-enabled" {
  name = "cloud-trail-encryption-enabled"
  source {
    owner             = "AWS"
    source_identifier = "CLOUD_TRAIL_ENCRYPTION_ENABLED"
  }
}
resource "aws_config_config_rule" "cloud-trail-log-file-validation-enabled" {
  name = "cloud-trail-log-file-validation-enabled"
  source {
    owner             = "AWS"
    source_identifier = "CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED"
  }
}
resource "aws_config_config_rule" "cloudtrail-s3-dataevents-enabled" {
  name = "cloudtrail-s3-dataevents-enabled"
  source {
    owner             = "AWS"
    source_identifier = "CLOUDTRAIL_S3_DATAEVENTS_ENABLED"
  }
}
resource "aws_config_config_rule" "multi-region-cloud-trail-enabled" {
  name = "multi-region-cloud-trail-enabled"
  source {
    owner             = "AWS"
    source_identifier = "MULTI_REGION_CLOUD_TRAIL_ENABLED"
  }
}
#
# Network and Content Delivery
#
resource "aws_config_config_rule" "internet-gateway-authorized-vpc-only" {
  name = "internet-gateway-authorized-vpc-only"
  source {
    owner             = "AWS"
    source_identifier = "INTERNET_GATEWAY_AUTHORIZED_VPC_ONLY"
  }
  input_parameters = jsonencode(
    {
      AuthorizedVpcIds = "vpc-チョメチョメ,vpc-チョメチョメ"
    }
  )
}
resource "aws_config_config_rule" "vpc-default-security-group-closed" {
  name = "vpc-default-security-group-closed"
  source {
    owner             = "AWS"
    source_identifier = "VPC_DEFAULT_SECURITY_GROUP_CLOSED"
  }
}
resource "aws_config_config_rule" "vpc-flow-logs-enabled" {
  name = "vpc-flow-logs-enabled"
  source {
    owner             = "AWS"
    source_identifier = "VPC_FLOW_LOGS_ENABLED"
  }
}
#
# Security, Identity & Compliance
#
resource "aws_config_config_rule" "access-keys-rotated" {
  name = "access-keys-rotated"
  source {
    owner             = "AWS"
    source_identifier = "ACCESS_KEYS_ROTATED"
  }
  input_parameters = jsonencode(
    {
      maxAccessKeyAge = "180"
    }
  )
}
resource "aws_config_config_rule" "acm-certificate-expiration-check" {
  name = "acm-certificate-expiration-check"
  source {
    owner             = "AWS"
    source_identifier = "ACM_CERTIFICATE_EXPIRATION_CHECK"
  }
  input_parameters = jsonencode(
    {
      daysToExpiration = "14"
    }
  )
  maximum_execution_frequency = "TwentyFour_Hours"
  scope {
    compliance_resource_types = [
      "AWS::ACM::Certificate",
    ]
  }
}
resource "aws_config_config_rule" "iam-group-has-users-check" {
  name = "iam-group-has-users-check"
  source {
    owner             = "AWS"
    source_identifier = "IAM_GROUP_HAS_USERS_CHECK"
  }
}
resource "aws_config_config_rule" "iam-password-policy" {
  name = "iam-password-policy"
  source {
    owner             = "AWS"
     source_identifier = "IAM_PASSWORD_POLICY"
   }
  depends_on  = ["aws_config_configuration_recorder.awsconfig"]
  description = ""
  input_parameters = jsonencode(
    {
      MaxPasswordAge             = "90"
      MinimumPasswordLength      = "12"
      PasswordReusePrevention    = "3"
      RequireLowercaseCharacters = "true"
      RequireNumbers             = "true"
      RequireSymbols             = "true"
      RequireUppercaseCharacters = "true"
    }
  )
  maximum_execution_frequency = "TwentyFour_Hours"
}
resource "aws_config_config_rule" "iam-root-access-key-check" {
  name = "iam-root-access-key-check"
  source {
    owner             = "AWS"
    source_identifier = "IAM_ROOT_ACCESS_KEY_CHECK"
  }
}
resource "aws_config_config_rule" "iam-user-group-membership-check" {
  name = "iam-user-group-membership-check"
  source {
    owner             = "AWS"
    source_identifier = "IAM_USER_GROUP_MEMBERSHIP_CHECK"
  }
}
resource "aws_config_config_rule" "iam-user-no-policies-check" {
  name = "iam-user-no-policies-check"
  source {
    owner             = "AWS"
    source_identifier = "IAM_USER_NO_POLICIES_CHECK"
  }
}
resource "aws_config_config_rule" "iam-user-unused-credentials-check" {
  name = "iam-user-unused-credentials-check"
  source {
    owner             = "AWS"
    source_identifier = "IAM_USER_UNUSED_CREDENTIALS_CHECK"
  }
  input_parameters = jsonencode(
    {
      maxCredentialUsageAge = "180"
    }
  )
}
resource "aws_config_config_rule" "mfa-enabled-for-iam-console-access" {
  name = "mfa-enabled-for-iam-console-access"
  source {
    owner             = "AWS"
    source_identifier = "MFA_ENABLED_FOR_IAM_CONSOLE_ACCESS"
  }
  description                 = ""
  maximum_execution_frequency = "One_Hour"
}
resource "aws_config_config_rule" "root-account-mfa-enabled" {
  name = "root-account-mfa-enabled"
  source {
    owner             = "AWS"
    source_identifier = "ROOT_ACCOUNT_MFA_ENABLED"
  }
  maximum_execution_frequency = "TwentyFour_Hours"
}
#
# Storage
#
resource "aws_config_config_rule" "ebs-snapshot-public-restorable-check" {
  name = "ebs-snapshot-public-restorable-check"
  source {
    owner             = "AWS"
    source_identifier = "EBS_SNAPSHOT_PUBLIC_RESTORABLE_CHECK"
  }
  maximum_execution_frequency = "TwentyFour_Hours"
}
resource "aws_config_config_rule" "elb-deletion-protection-enabled" {
  name = "elb-deletion-protection-enabled"
  source {
    owner             = "AWS"
    source_identifier = "ELB_DELETION_PROTECTION_ENABLED"
  }
}
resource "aws_config_config_rule" "s3-account-level-public-access-blocks" {

  name = "s3-account-level-public-access-blocks"
  source {
    owner             = "AWS"
    source_identifier = "S3_ACCOUNT_LEVEL_PUBLIC_ACCESS_BLOCKS"
  }
}
resource "aws_config_config_rule" "s3-bucket-public-write-prohibited" {
  name = "s3-bucket-public-write-prohibited"
  source {
    owner             = "AWS"
    source_identifier = "S3_BUCKET_PUBLIC_WRITE_PROHIBITED"
  }
  maximum_execution_frequency = "TwentyFour_Hours"
  scope {
    compliance_resource_types = [
      "AWS::S3::Bucket"
    ]
  }
}
resource "aws_config_config_rule" "s3-bucket-public-read-prohibited" {
  name = "s3-bucket-public-read-prohibited"
  source {
    owner             = "AWS"
    source_identifier = "S3_BUCKET_PUBLIC_READ_PROHIBITED"
  }
  maximum_execution_frequency = "TwentyFour_Hours"
  scope {
    compliance_resource_types = [
      "AWS::S3::Bucket"
    ]
  }
}
```


# 7. 「6.」で作成した設定の確認

### 7.1. CloudWatch イベントルール
|![20200218-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/1494d47c-8f00-9d05-0e00-4fc487315092.png)|
|:-:|

### 7.2. AWS Config ルール
|![20200218-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/5601cf44-6802-1f4b-45e5-705038683ffa.png)|
|:-:|

### 7.3. AWS Config ルール からの通知

※ AWS Chatbot から Slack へ飛ばしている

* 準拠の例

|![20200218-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/095c53ad-6492-fb03-66a7-440203fb8847.png)|
|:-:|


* 非準拠の例

|![20200218-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/f068111d-9c28-b5ae-cb1f-88ad65374875.png)|
|:-:|

### 7.4. AWS Config ダッシュボード

結構赤いｗ（非準拠多い・・）

|![20200218-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/f9611097-628f-12f0-d957-5e21eb2eb9a1.png)|
|:-:|


# 8. 非準拠項目の確認例

* access-keys-rotated を見てみる

|![20200218-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/8cb515c9-c4de-2372-de58-3ad48b5cc34d.png)|
|:-:|

↓
9個の IAMユーザーが access-keys-rotated ルールに準拠していない。。

|![20200218-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/9ba2abd2-06dc-2469-6588-d948c8039b9f.png)|
|:-:|

↓
その中の IAMユーザーの dev-test-user を見てみると、「iam-user-group-membership-check」ルールと「iam-user-no-policies-check」ルールにも準拠していない。。

|![20200218-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/e98050ea-a40d-5bbe-01ff-7a669899cb8f.png)|
|:-:|

↓

コンプライアンスタイムライン なんていうものもある

|![20200218-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/91103b0e-9f0e-edc5-a07d-eeaad8784394.png)|
|:-:|

↓

|![20200218-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/06c082c7-a63c-a761-1fcd-0c185d13682d.png)|
|:-:|


# 9. 非準拠項目の対応例

### 9.1. iam-user-group-membership-check ルールの非準拠対応
新規にIAMグループ testgroup を作成して、IAMユーザーの dev-test-user をそのグループに属してみる。
↓
しばらく（数十分）すると、Config ルールから通知が届いた
↓

|![20200218-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/25737a42-9b3f-df95-fe71-a0daf207d52d.png)|
|:-:|

* 上の通知は、iam-user-group-membership-check ルールの通知で、IAMユーザー dev-test-user がIAMグループに属したのでルールに準拠したという通知。

* 下の通知は、iam-group-has-users-check ルールの通知で、新規に作成した IAMグループ testgroup がIAMユーザー dev-test-user を持っているので、ルールに準拠しているという通知。

### 9.2. コンプライタイムラインの確認
IAM ユーザー dev-test-user の コンプライアンスタイムライン を確認すると、非準拠ルールが３個から２個に減った。

|![20200218-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/3cf3610b-fde8-eaf1-eceb-4b9595401c53.png)|
|:-:|

↓

「関係」を見てみる

|![20200218-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/3df27bf7-15c5-7c8f-9121-b70a39ab5718.png)|
|:-:|

↓

リンク踏むと、IAMユーザー dev-test-user の設定タイムラインページへ飛ぶ
設定タイムラインの「変更」を見ると、IAMグループ testgroup に属したことが確認できる。

|![20200218-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/79ae99e7-72f1-5dfe-aa5d-c6552077ba0f.png)|
|:-:|


IAM ユーザー dev-test-user の コンプライアンスタイムライン に戻って、「変更」を見てみる。
コンプライアンスタイムラインの「変更」を見ると、Configルール iam-user-group-membership-check が NON_COMPLIANT から COMPLIANT へ変わったことが確認できる。

|![20200218-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/cfbd7771-3972-fe83-1f49-63ac3f6941cd.png)|
|:-:|



#10. IAMベストプラクティスにほぼほぼ準拠したIAMユーザ・グループ作成について
https://qiita.com/tonishy/items/f9cdacd1a51b92724d15