継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

GuardDuty のマルチアカウント管理機能有効化を省力化する

タダです.

先日, GuardDuty のマルチアカウント管理機能を紹介した記事を書きました.マルチアカウントで GuardDuty を運用するなら有効化すべき機能ですが,多数のアカウントを AWS マネジメントコンソールの操作で有効化するのは煩雑なため, CloudFormation と AWS CLI を使って省力化してみます. sadayoshi-tada.hatenablog.com

省力化できる箇所

今回,省力化できる箇所は以下のものと考えました.

  1. メンバーアカウントに対してマスターアカウントからアカウント管理機能の招待を送る処理
  2. メンバーアカウントでマスターアカウントからの招待を受ける処理
  3. GuardDuty の DetectorID を取得する処理

それぞれの処理ごとで省力化した箇所とコード例を記載していきます.

1. メンバーアカウントに対してマスターアカウントからアカウント管理機能の招待を送る処理

マスターアカウントがメンバーアカウントのイベントを管理するためには, メンバーアカウントにマスターアカウントに統合するための招待を送る必要があります.なお, AWS では利用可能なリージョン全てで GuardDuty を有効化することが推奨されておりますので本記事では,マスターアカウントの全リージョンからメンバーアカウントに招待通知を出す処理を CloudFormation で省力化するコードを紹介します.

GuardDuty は、サポートされているすべての AWS リージョンで有効にすることが強く推奨されています。このように設定することで、お客様が能動的に使用していないリージョンでも、許可されていないアクティビティや異常なアクティビティに関する検索結果を GuardDuty で生成できます。

docs.aws.amazon.com

CloudFormation テンプレート例

CloudFormation の StackSets 機能を使ってマスターアカウントの全リージョンに対して下記のテンプレートを実行することで指定のメンバーアカウントに対して招待通知を出せます.AWS::GuardDuty::MemberStatus: "Invited"で設定するとメンバーアカウントに招待通知を出す処理まで一気に設定可能ですので,この設定は定義しておくと良いでしょう.

AWSTemplateFormatVersion: 2010-09-09
Description: Send Invitation to GuardDuty Member Account.

Mappings:
  GuardDutyMember:
    us-east-1: 
      DetectorId: xxxx
    us-east-2:
      DetectorId: xxxx
    us-west-1:
      DetectorId: xxxx
    us-west-2:
      DetectorId: xxxx
    ca-central-1:
      DetectorId: xxxx
    eu-central-1:
      DetectorId: xxxx
    eu-west-1:
      DetectorId: xxxx
    eu-west-2:
      DetectorId: xxxx
    eu-west-3:
      DetectorId: xxxx
    ap-northeast-1:
      DetectorId: xxxx
    ap-northeast-2:
      DetectorId: xxxx
    ap-southeast-1: 
      DetectorId: xxxx
    ap-southeast-2: 
      DetectorId: xxxx
    ap-south-1:
      DetectorId: xxxx
    sa-east-1:
      DetectorId: xxxx

Prameter:
  MemberAccountId:
    Description: Type Member Account Number.
    Type: String
  MemberAccountEmail:
    Description: Type Member Account Email.
    Type: String  


Resources:
  Member:
    Type: AWS::GuardDuty::Member
    Properties: 
      Status: "Invited"    
      MemberId: !Ref MemberAccountId
      Email: !Ref MemberAccountEmail
      DetectorId: !FindInMap [GuardDutyMember,!Ref "AWS::Region", DetectorId]
      DisableEmailNotification: True

なお,CloudFormation の StackSets 機能が使えないリージョンでは手動でメンバーアカウントの招待を行う必要があります.多数のアカウントに対して招待を出す場合,CSVファイルに次のようにメンバーアカウントの AWS アカウント番号とメールアドレスを記載したものを読み込ませるとスムーズです。

Account ID,Email
111111111111,user@example.com

CloudFormation ドキュメント

docs.aws.amazon.com

2. メンバーアカウントでマスターアカウントからの招待を受ける処理

マスターアカウントからメンバーアカウントへアカウント統合の招待を出した後は,メンバーアカウントでその招待を承認しなければなりません.その承認処理を CloudFormation で省力化します.マスターアカウントからの招待通知同様に全リージョンで承認処理を行うためのテンプレート例を紹介します.

CloudFormation テンプレート例

このテンプレートもメンバーアカウントで StackSets 機能を使って全リージョンの招待通知を一度に承認する処理を省力化しています.

AWSTemplateFormatVersion: 2010-09-09
Description: Approve Invitation From GuardDuty Master Account.

Mappings:
  GuardDutyMaster:
    us-east-1: 
      DetectorId: xxxx
    us-east-2:
      DetectorId: xxxx
    us-west-1:
      DetectorId: xxxx
    us-west-2:
      DetectorId: xxxx
    ca-central-1:
      DetectorId: xxxx
    eu-central-1:
      DetectorId: xxxx
    eu-west-1:
      DetectorId: xxxx
    eu-west-2:
      DetectorId: xxxx
    eu-west-3:
      DetectorId: xxxx
    ap-northeast-1:
      DetectorId: xxxx
    ap-northeast-2:
      DetectorId: xxxx
    ap-southeast-1: 
      DetectorId: xxxx
    ap-southeast-2: 
      DetectorId: xxxx
    ap-south-1:
      DetectorId: xxxx
    sa-east-1:
      DetectorId: xxxx

Parameters:
  MasterAccountNumber:
    Type: String

Resources:
  Master:
    Type: AWS::GuardDuty::Master
    Properties:
      DetectorId: !FindInMap [GuardDutyMaster,!Ref "AWS::Region", DetectorId]
      MasterId: !Ref MasterAccountNumber

CloudFormation ドキュメント

docs.aws.amazon.com

3. GuardDuty の DetectorID を取得する処理

最後に, 1,2 のCloudFormation テンプレートの定義で必ず必要な GuardDuty の DetectorID 取得を AWS CLI で全リージョン分取得する処理を紹介します.マスターアカウントでもメンバーアカウントでも必ず必要なため同様の処理を検討している方の参考になれば嬉しいです.

AWS CLI コード例

以下の2行で取得可能です.最初にリージョンのエンドポイントをソートして取得し,次に GuardDuty の DetectorID をリージョンごとに取得している感じです.

# リージョン全取得して配列に格納(-r をつけるとダブルクオーテーションを削除可能)
declare -a REGIONS=( $(aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | sort) )

# GuardDutyのDetectorIDをリージョンごとに表示する
for i in ${REGIONS[@]}; do echo "$i = $( aws guardduty list-detectors --region $i | jq -r '.DetectorIds[]')";done

AWS CLI ドキュメント

docs.aws.amazon.com

docs.aws.amazon.com

シェルスクリプト化してこんな感じに一気に取得するなどできます.

f:id:sadayoshi_tada:20190817160352p:plain

まとめ

僕が GuardDuty のマルチアカウント管理機能有効化を省力化するために行った CloudFormation と AWS CLI の意図とコードを紹介しました.他にもいろんな方法があるかと思いますが,僕は次は AWS CDK でも同様のことを実現できないかをトライしてみたいと思います.