アソビュー Advent Calendar 2019の6日目。
こんにちは。アソビューで SRE チームを担当している秋元です。
アソビューのシステムやサービス運用をする上での取り組みを紹介していきたいと思います。 今回は、CloudFormation の StackSets を利用した GuardDuty の有効化について書きたいと思います。
弊社ではインフラのプロビジョニングツールとして Terraform を使用することが多いですが、GuardDuty の場合、複数の AWS アカウント、リージョンで有効化する必要があり Terraform で作成すると面倒だったので、CloudFormation の StackSets を利用してみました。
GuardDuty
脅威の検出
GuardDuty は、CloudTrail、VPC フローログ、DNS ログなどを解析して悪意のある操作や不正な動作をモニタリングする脅威検出サービスです。
IAM ユーザーのアクセスキーが不正に利用されていないかや、EC2 上で起動しているプログラムが不正な通信を行なっていないかなども検知してくれます。
普段使用しているリージョン、アカウントはもちろんですが、普段使用していないリージョン、アカウントでも有効化することが推奨されています。
通知
脅威が検知されると、CloudWatch イベントが作成されます。
弊社では、検出されたイベントを Datadog に送り、通知するようにしています。
また、GuardDuty では、他のアカウントと関連づけることができます。
弊社では、特定のアカウントをマスターアカウント、その他をメンバーアカウントとし、発生した GuardDuty のイベントをマスターアカウントに集約、Datadog に送信しています。
CloudFormation StackSets
非常に簡単にセキュリティの脅威を検知できる GuardDuty ですが、有効化を行うにあたりリージョンごとに設定する必要があります。
そのため、例えば Terraform で設定を管理しようとすると、(アカウント数)×(リージョン数)だけ provider を作成する必要があり面倒という問題があります。
そこで弊社では CloudFormation の StackSets という機能を使って設定を行なっています。
CloudFormation StackSets は、一つの CloudFormation のテンプレートを使って、複数の AWS アカウント、リージョンにスタックを作成できる機能です。
スタックの作成は StackSet を作成するアカウントでも別のアカウントでも行えます。
イメージとしてはこんな感じです。
StackSets でスタックを作成するにあたり、事前に IAM ロールを作成する必要があります。
- AdministrationRole
- StackSets を作成するアカウントに作成
- ExecutionRole に AssumeRole できる必要がある。
- ExecutionRole
- スタックを作成するアカウントに作成
- スタックを作成するのに必要なポリシーが付与されている必要がある。
- AdministrationRole から AssumeRole されることができる必要がある。
Terraform で記載すると下記のようになります。
(マスターアカウントのアカウント ID=012345678901
)
- AdministrationRole
resource "aws_iam_role" "cloudformation_admin_role" { name = "StackSetAdministrationRole" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "cloudformation.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": {} } ] } EOF } resource "aws_iam_policy" "cloudformation_admin_policy" { name = "cloudformation_admin_policy" description = "cloudformation_admin_policy" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "1", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::*:role/StackSetExecutionRole" } ] } EOF } resource "aws_iam_role_policy_attachment" "cloudformation_admin_attach" { role = "${aws_iam_role.cloudformation_admin_role.name}" policy_arn = "${aws_iam_policy.cloudformation_admin_policy.arn}" } resource "aws_iam_role" "cloudformation_execute_role" { name = "StackSetExecutionRole" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "012345678901" }, "Action": "sts:AssumeRole", "Condition": {} } ] } EOF } resource "aws_iam_role_policy_attachment" "cloudformation_execute_attach" { role = "${aws_iam_role.cloudformation_execute_role.name}" policy_arn = "[スタックを作成するのに必要な IAM ポリシーの ARN]" }
- ExecutionRole
resource "aws_iam_role" "cloudformation_execute_role" { name = "StackSetExecutionRole" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "012345678901" }, "Action": "sts:AssumeRole", "Condition": {} } ] } EOF } resource "aws_iam_role_policy_attachment" "cloudformation_execute_attach" { role = "${aws_iam_role.cloudformation_execute_role.name}" policy_arn = "[スタックを作成するのに必要な IAM ポリシーの ARN]" }
少しわかりにくい点としては、マスターアカウントでも ExecutionRole でスタックを作成するので作成する必要があります。
ここで一点注意があります。 StackSets に対応していないリージョンもあるので、その場合は別途 GuardDuty の設定をする必要があります。
StackSets を利用した GuardDuty の有効化
マスターアカウント、メンバーアカウントのテンプレートは下記の通りです。
- マスターアカウント
AWSTemplateFormatVersion: 2010-09-09 Description: Creates an AWS::GuardDuty::Detector resource and optionally an AWS::GuardDuty::Master resource in a set of accounts and regions. Resources: Detector: Type: AWS::GuardDuty::Detector Properties: Enable: True MemberA: Type: AWS::GuardDuty::Member Properties: Status: Invited MemberId: 23456789012 Email: xxxx@hoge.com DetectorId: !Ref Detector DisableEmailNotification: True MemberB: Type: AWS::GuardDuty::Member Properties: Status: Invited MemberId: 34567890123 Email: yyyy@hoge.com DetectorId: !Ref Detector DisableEmailNotification: True
- メンバーアカウント
AWSTemplateFormatVersion: 2010-09-09 Description: Creates an AWS::GuardDuty::Detector resource and optionally an AWS::GuardDuty::Master resource in a set of accounts and regions. Resources: Detector: Type: AWS::GuardDuty::Detector Properties: Enable: True Master: Type: AWS::GuardDuty::Master Properties: DetectorId: !Ref Detector MasterId: "012345678901"
上記では、
- マスターアカウントのアカウント ID:
012345678901
- メンバーアカウントのアカウント ID:
23456789012
,34567890123
という構成です。
作成している内容は下記の通りです。
- マスターアカウント
- GuardDuty の有効化
- メンバーアカウントを招待
- メンバーアカウント
- GuardDuty の有効化
- マスターアカウントからの招待を承認
このテンプレートを使用して、全リージョン、全メンバーアカウントを指定してスタックを作成しています。
感想
やってみた感想は下記の通りです。
- よかった点
- Terraform で書くよりもすっきり書くことができた。
- よくなかった点
- StackSets に対応していないリージョンもあるので、その場合は別途 GuardDuty の設定をする必要があるのが面倒。
- 実行する部分はマネージメントコンソールから実行するか、何かしらのスクリプトを書く必要がある。
- Terraform など、CloudFormation 以外のプロビジョニングツールを使っている場合はメンテナンスコストが上がってしまう。
すでに Terraform など別のプロビジョニングツールを使用している場合、メンテナンスコストが上がってしまうのであまり好ましくないかもしれませんが、GuardDuty のアカウント連携の記載方法あたりが個人的にはわかりづらかったので参考になればと思います。