insightwatchのセキュリティチェックでオールグリーンを目指す(その2: CISベンチマーク ロギング編)

insightwatch

オペレーション部 江口です。 「insightwatchのセキュリティチェックでオールグリーンを目指す」シリーズの第2回です。

第1回はこちら

insightwatchのセキュリティチェックでオールグリーンを目指す(その1: CISベンチマーク IAM設定編)

今回は「CIS 2. Logging」の対処を行なっていきます。名前のとおりログ周りの設定となります。 項目数は9項目と少ないのですが、きちんとログを取るため「全リージョンで設定を有効にする」という要件の項目が複数あり、対応はなかなか大変でした・・・

最初のチェック結果

このパートの最初の結果は以下の通りです。9項目中注意4・重要3の指摘がありました。

以下、指摘事項の対処を行なっていきます。

CIS 2.2 CloudTrailログファイルの検証が有効化されていること

CloudTrailのログファイルが変更や削除を検知する整合性の検証を有効にする、という要件です。 概要や設定手順は下記のAWS公式ドキュメントが参考になります。

AWS CLIでは下記のように設定変更できます。

aws cloudtrail update-trail --name [トレイル名] --enable-log-file-validation

CIS 2.4 CloudTrailログがCloudWatch Logsに配信設定されていること

CloudTrailのログファイルをCloudWatch Logsに配信するようにします。 手順の公式ドキュメントは以下。

https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/send-cloudtrail-events-to-cloudwatch-logs.html

ざっくり必要な設定は下記です。

  1. CloudWatch Logsに配信用のロググループを作成(* 既存のロググループに飛ばすこともできます)、CloudTrailの証跡側でこのロググループを指定
  2. CloudTrailに、CloudWatch Logsへログを配信するためのIAMロールを割り当て

これらの設定は、CloudTrailコンソールからCloudWatch Logsの設定を行う場合は一気に新規作成できます。 ただ、私の環境では、前回通常の検証用とIAM権限とでロールを分けてしまった関係で、IAMロールをこの画面では作成できません(通常検証用に使っているロールにIAMロールを作成する権限がないので)。かなしみ。 ということで、手動で作成する必要があります。

IAMロールでは、CloudWatch LogsのロググループのARNを指定する必要があるため、まずロググループを先に行います。 その後にIAMロールを作成します。この際に割り当てるべきポリシーは前掲の公式ドキュメントに記載されています。 下記にそのポリシーを転載しておきます(インラインポリシーで設定)。Resource内のARNは、自分のCloudWatch LogsのロググループのARNに置き換えてください。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AWSCloudTrailCreateLogStream20141101",
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogStream"
      ],
      "Resource": [
        arn:aws:logs:region:[アカウントID]:log-group:[ロググループ名]:log-stream:[アカウントID]_CloudTrail_[リージョン名]*"
      ]
    },
    {
      "Sid": "AWSCloudTrailPutLogEvents20141101",
      "Effect": "Allow",
      "Action": [
        "logs:PutLogEvents"
      ],
      "Resource": [
        arn:aws:logs:region:[アカウントID]:log-group:[ロググループ名]:log-stream:[アカウントID]_CloudTrail_[リージョン名]*"
      ]
    }
  ]
}

ロググループとIAMロールを設定したら、CloudTrail側でCloudWatch Logsへの配信設定を行います。 コンソールのメニュー「証跡情報」から対象の証跡を選択、表示される設定の一覧で「CloudWatch Logs」の編集をクリックし、ロググループとIAMロールを入力します。

上記の例ではロググループは「DefaultLogGroup」、IAMロールは「CloudTrail_CloudWatchLogs_Role」としてます。

CIS 2.5 全リージョンでAWS Configが有効であること

冒頭で上げた「全リージョンで有効化する」シリーズです。AWS Configの設定を全リージョンで有効化しますが、この際下記もチェック条件となっています。

  • すべてのリソース配下の「このリージョンではサポートされているすべてのリソースを記録します」のチェックボックスが有効になっていること
  • すべてのリソース配下の「グローバルリソース (AWS IAM リソースなど) を含める」は少なくとも1つのリージョンでチェックボックスが有効になっていること
  • S3バケットが設定されていること
  • SNSトピックが設定されていること

SNSはリージョンサービスなので、各リージョンで作成する必要があります。

流石にコンソールで人力で作成したくはないので、ここは複数のリージョンでCloudFormationを実行できる、CloudFormation StackSetsを利用してみました。

CloudFormation StackSetsについては下記記事をご参照ください。

https://dev.classmethod.jp/cloud/aws/introducing-cloudformation-stacksets/

公式ドキュメントは下記です。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html

幸い、StackSetsではAWS Configを有効化するテンプレートがサンプルとして用意されているので、テンプレートの作成も必要ありません。

ただし事前準備として、前掲の記事にあるように、StackSets用IAMロールとして以下の2つの用意が必要です。

  • AWSCloudFormationStackSetAdministrationRole(管理用)
  • AWSCloudFormationStackSetExecutionRole(実行用)

この際AWSCloudFormationStackSetExecutionRoleには、必要なサービスへのアクセス権限が必要となります(この場合はCloudFormation、Config、SNS、S3、IAMロールなどのサービスへのアクセス)。 私は以下のポリシーと、IAMFullAccessをこのロールにアタッチしました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:*",
                "s3:*",
                "sns:*",
                "config:*"
            ],
            "Resource": "*"
        }
    ]
}

また、AWSCloudFormationStackSetAdministrationRoleを信頼するよう信頼ポリシーを編集します。 ([アカウントID]はご自分のアカウントIDに置き換えてください)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::[アカウントID]:role/AWSCloudFormationStackSetAdministrationRole"
      },
      "Action": "sts:AssumeRole"
    }
  ]

あとはStackSetsで新しいスタックセットを作成します。以下のように設定しました。

  • 使用するテンプレート:サンプルテンプレート「AWS Configの有効化」
  • パラメータ:特に初期値から変更せずに通りました
  • 対象リージョン: 全リージョンを対象として選択
  • アクセス許可:IAM管理ロールにAWSCloudFormationStackSetAdministrationRole、実行ロールにAWSCloudFormationStackSetExecutionRoleを指定
  • デプロイオプション:初期値のままで通りました

問題

上記StackSetsで各リージョンでAWS Configが有効になりますが、2019年7月現在StackSetsではまだeu-north-1(ストックホルム)がサポートされていません。
(新しいリージョンにStackSetsが対応するのに多少時間を要するようです)

しかしinsightwatchではeu-north-1もチェック対象となっているため、eu-north-1に関しては別途設定を行う必要がありました。 今回は個人検証環境ですのでこうした暫定処置で良いですが、実際の運用を考えると、一つだけ設定の方法が異なるリージョンが存在するのは管理が煩雑になり好ましくない気はします。

その他ハマったところ

このAWS Config有効化を行うStackSetsが設定の不備などで失敗した場合、各リージョンでスタックを削除して再実行を行うことになりますが、 場合によっては「AWSConfigDeliveryChannel」、「AWSConfigRecorder」を手動で削除する必要があります。 これらはAWS Config有効かのタイミングで作成されますが、コンソール上でスタックを削除してもこれらは削除されないようです。そのためこれらの作成まで進んだ後の処理で失敗した際、スタックを削除しStackSetsの再実行を行なった場合、既に存在するためエラーが返ってきました。

本件については下記の過去の当社ブログ記事に詳しいのでご参照ください。 https://dev.classmethod.jp/cloud/aws/delete-awsconfig/

私は以下のようなシェルスクリプトを作成して一気に削除しました。 全リージョンで一気に削除を試みる割と乱暴なスクリプトなので、実環境で利用する場合はご注意ください。実際には削除を行う対象のリージョンをきちんと指定した方が良いと思います。

#!/bin/bash

REGIONS=$(aws ec2 describe-regions --query "Regions[].{Name:RegionName}" --output text)

for REGION in ${REGIONS}
do
    echo "Processing in region: ${REGION}"
    aws configservice delete-configuration-recorder --configuration-recorder-name default --region ${REGION}
    aws configservice delete-delivery-channel --delivery-channel-name default --region ${REGION}
done

CIS 2.6 CloudTrailログが格納されているS3バケットでログ記録が有効になっていること

CloudTrailログが格納されているS3バケットに対しても、アクセスのログを記録した方が良い、ということですね。 公式ドキュメントの手順は下記です。S3コンソールで対象のS3バケットを選択、ログの記録を有効化して、アクセスログを格納するS3バケットを指定します。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/user-guide/server-access-logging.html

CIS 2.7 CloudTrailログがSSE-KMSで暗号化設定されていること

CloudTrailのログをAWS KMSで暗号化するという要件。 公式ドキュメントの手順は下記です。CloudTrailコンソールから、AWS KMSで作成した鍵を利用した暗号化を有効化を行います。

https://docs.aws.amazon.com/ja_jp/awscloudtrail/latest/userguide/create-kms-key-policy-for-cloudtrail-update-trail.html

CIS 2.8 KMSマスターキーがローテーション設定されていること

CIS 2.7で設定したKMSキーが、AWS KMS上でローテーション設定されていること、という要件です。 insightwatchでのチェックのアラート基準は「CloudTrailログを暗号化しているKMSキーのローテーション設定がされていない場合」となっていますが、 実際にチェックしてみると、他の(CloudTrailで利用していない)KMSキーでローテーション設定が行われていない場合でもアラートが出てきました。 まあ鍵のローテーションは行うに越したことはないので、設定したKMSキーで全てローテーション設定を行なってこの要件をクリアしました。

公式ドキュメントの手順は下記となります。

https://docs.aws.amazon.com/ja_jp/kms/latest/developerguide/rotate-keys.html

CIS 2.9 利用可能な全てのリージョンにおいて、VPC Flow Logsが有効化されていること

CIS 2.5に続く「全リージョンで有効化する」シリーズです。VPCへの通信トラフィックを記録するVPC Flow Logsを全リージョンのVPCで有効化するという要件となります。 これもCloudFormation StackSetsで設定をしようかと思ったのですが、VPC Flow Logsの有効化にはVPC IDを渡す必要があり、既存のVPCのID情報を各リージョンで動的に取得して渡す、という点がCloudFormationでは難しいように思えたので、PythonでAWS SDK(boto3)を使って対応しました。

スクリプトの前に、まずVPC Flow Logsを利用するためのIAMロールが必要なので、先に定義します。 必要なIAMロールの定義については公式ドキュメントに説明があります。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/flow-logs-cwl.html

アタッチしたポリシーは以下の通りです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents",
        "logs:DescribeLogGroups",
        "logs:DescribeLogStreams"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}   

作成したPythonスクリプトは下記です。 VPC Flow Logsを配信するCloudWatchのロググループの作成も同時に行なっています。

#!/usr/local/bin/python3

import boto3
import json

log_group_name = 'vpc_flowlog_group'
arn = 'arn:aws:iam::[アカウントID]:role/[ロール名]' #VPC Flow Logs用ロールのARNを指定

def get_region_list():
    client = boto3.client('ec2')
    return [region['RegionName'] for region in client.describe_regions()['Regions']]

def enable_flow_logs(region):
    # VPC情報取得
    ec2 = boto3.client('ec2', region_name=region)
    vpcs = [vpc.get('VpcId') for vpc in ec2.describe_vpcs()['Vpcs']]

    # CloudWatch Logsのロググループ作成
    logs = boto3.client('logs', region_name=region)
    log_group = logs.create_log_group(logGroupName = log_group_name)

    # Flow Logsを有効化
    flow_logs = ec2.create_flow_logs(ResourceIds              = vpcs,
                                     ResourceType             = 'VPC',
                                     TrafficType              = 'ALL',
                                     LogGroupName             = log_group_name,
                                     DeliverLogsPermissionArn = arn)

# main
if __name__ == "__main__":
  regions = get_region_list()
  for region in regions:
      print(region)
      enable_flow_logs(region)

ここまでの結果

ここまでの対処で、「CIS 2. Logging」の結果はすべて「正常」となりました。

全体の指摘数は以下の通り。注意7・重要26、指摘の合計は33個です。

最初のチェックでは注意12・重要45の合計57個だったので、4割ほど減りました。 推移をグラフにすると以下のような感じです。

反省点ですが、設定をコンソール、AWS CLI、CloudFormation、Python(with AWS SDK)と、色々なやり方で行なっていますが、あまり美しくないなあと思います。Infrastracture as Codeの精神で、全てコード化するのが理想ですね・・・

とはいえこの試みの第一の目的はチェック結果をオールグリーンにすることですので、とりあえずこのまま進みたいと思います。

以上、「insightwatchのセキュリティチェックでオールグリーンを目指す」シリーズの第2回でした。