0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】AWSアカウントのセットアップをCloudFormationで爆速化しよう!

0
Last updated at Posted at 2026-06-21

cloudformation-setup-qiita-title.png

1. はじめに

本記事の前提条件

本記事は、個人の検証環境や小規模開発向けなど、スタンドアロン(単一)のAWSアカウントのセットアップを対象としています。
企業システムなどで複数アカウントを統合管理(Landing Zoneの構築など)する場合は、AWS Control TowerやIAM Identity Centerの利用を推奨します。

AWSアカウントのセットアップはAWSを安全に利用する上で重要な作業ですが、AWSマネジメントコンソールでの手動構築は必要な手順が多く、設定漏れや手順の前後によるミスを引き起こす可能性があります。

そこで、AWSアカウント作成後に必要なセットアップを可能な限りAWS CloudFormationで作成してみました。

本記事では、AWS CloudFormationでの設定ができないもしくは推奨されない、AWSマネジメントコンソールでの操作が必要なセットアップについても掲載しているため、

  • AWSを使ってみたいけど、アカウントを作成していない
  • AWSアカウントを作成したけど、何も設定していない

という方は、ぜひ本記事を参考にAWSアカウントをセットアップしてみてください!

本記事では、AWSアカウントのセットアップとして、

についてまとめています。

セットアップの種別について

セクションのタイトルに

  • マネジメントコンソール」と書かれているセットアップ
    AWSマネジメントコンソールでの操作が必要なセットアップ

  • CloudFormation」と書かれているセットアップ
    AWS CloudFormationでの設定が可能なセットアップ

本記事に掲載されているセットアップを全て完了させることで、AWSのベストプラクティスに則った安全な環境を構築することができます。安全で快適なAWSライフの最初の一歩を爆速で踏み出しましょう!

発言は個人の見解に基づくものであり、所属組織を代表するものではありません。

2. AWSマネジメントコンソールでのセットアップ

本セクションでは、

についてまとめています。

2.1 マネジメントコンソール: ルートユーザーのMFA有効化

2.1.1 目的

AWSアカウントのルートユーザーは、全ての操作が可能な最強の権限を保有しています。もし、ルートユーザーが乗っ取られた場合、アカウント内の全リソースが危険に晒され、多額の請求やデータ損失を引き起こす可能性があります。アカウント全体の乗っ取りリスクを最小化するためにも、必ずMFAを有効化しましょう。

MFA (Multi Factor Authentication) とは
Webサイトやアプリケーションなどにログインする時に、2つ以上の認証要素の提示を求める認証方法

2.1.2 手順

  1. ルートユーザーAWSマネジメントコンソールにサインイン
  2. 右上のアカウント名を展開し、「セキュリティ認証情報」をクリック
  3. 「多要素認証 (MFA)」の「MFAデバイスの割り当て」をクリック
  4. 案内に沿ってMFAデバイスを設定

MFAデバイスについては、個人の環境に合わせてお好きなものをご利用ください。
ちなみに、私はGoogle Authenticatorを利用しています。

2.1.3 確認

「多要素認証 (MFA)」に設定したMFAデバイスが登録されていれば、本設定は完了です。

2.2 マネジメントコンソール: IAMユーザーの請求情報へのアクセス有効化

2.2.1 目的

デフォルトの設定では、AWSの請求情報はルートユーザーしか閲覧することができません。しかし、ルートユーザーを日常的に使用することは、セキュリティ上のリスクが懸念されるため、AWSでは推奨されていません。

そこで、IAMユーザーの請求情報へのアクセスを有効化することで、ルートユーザーを封印したまま、IAMユーザーで請求情報を確認するという安全な運用が可能になります。

2.2.2 手順

  1. ルートユーザーAWSマネジメントコンソールにサインイン
  2. 右上のアカウント名を展開し、「アカウント」をクリック
  3. IAMユーザーおよびロールによる請求情報へのアクセス」の「編集」をクリック
  4. IAMアクセスをアクティブ化」を有効化し、「更新」をクリック

2.2.3 確認

「IAMユーザーおよびロールによる請求情報へのアクセス」が有効化されていれば、本設定は完了です。

2.3 マネジメントコンソール: 管理者権限を持ったIAMユーザーの作成

2.3.1 目的

AWSのベストプラクティスでは、ルートユーザーの認証情報が必要なタスクを除き、AWSアカウントのルートユーザーにはアクセスしないことが強く推奨されています。

そのため、管理者権限を持ったIAMユーザーを作成し、ルートユーザーは封印した状態で管理者ユーザーを軸として運用していきましょう。

2.3.2 手順

ログイン

  1. ルートユーザーAWSマネジメントコンソールにサインイン
  2. 上部の検索ボックスにIAMと入力し、IAMをクリック

ユーザーグループの作成

  1. 左のメニューから「ユーザーグループ」をクリック
  2. グループを作成」をクリック
  3. 任意のユーザーグループ名を入力
  4. 許可ポリシーを添付」の検索ボックスにAdministratorAccessと入力し、AdministratorAccessを選択
  5. ユーザーグループを作成」をクリック

AdministratorAccess とは
AWSサービスとリソースへのフルアクセスを提供するAWSマネージドポリシー

ユーザーの作成

  1. 左のメニューから「ユーザー」をクリック
  2. ユーザーの作成」をクリック
  3. 任意のユーザー名を入力
  4. AWSマネジメントコンソールへのユーザーアクセスを提供する」を有効化
  5. 「人にコンソールアクセスを提供していますか?」の「IAMユーザーを作成します」を有効化
  6. 「コンソールパスワード」の「カスタムパスワード」を有効化し、任意のパスワードを入力
  7. ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります」を無効化し、「次へ」をクリック
  8. 「許可のオプション」の「ユーザーをグループに追加」を選択
  9. 先ほど作成したユーザーグループを選択し、「次へ」をクリック
  10. 作成するユーザーの詳細を確認し、「ユーザーの作成」をクリック

コンソールパスワードについて
自動生成されたパスワード」を利用する場合は、ユーザー作成後に表示されるパスワードを記録するか、「ユーザーは次回のサインイン時に新しいパスワードを作成する必要があります」を有効化し、サインイン時に任意のパスワードを設定するようにしてください。

2.3.3 確認

「ユーザー」に作成した管理者ユーザーが表示されているかつ、ユーザー名をクリックした先で許可ポリシーにAdministratorAccessが表示されていれば、本設定は完了です。

2.4 マネジメントコンソール: 管理者ユーザーのMFA有効化

2.4.1 目的

管理者ユーザーは、ルートユーザーに次ぐ強力な権限を持ちます。そのため、管理者ユーザーにもMFAを有効化し、不正ログインを防止しましょう。

2.4.2 手順

  1. ルートユーザーからサインアウトする
  2. 先ほど作成した管理者ユーザーAWSマネジメントコンソールにサインイン
  3. 2.1 マネジメントコンソール: ルートユーザーのMFA有効化と同じ手順で、管理者ユーザーのMFAを有効化

2.4.3 確認

「多要素認証 (MFA) 」に設定したMFAデバイスが登録されていれば、本設定は完了です。

2.5 マネジメントコンソール: AWS Cost Explorerの有効化

2.5.1 目的

AWS Cost Explorerを有効化することで、AWSのコストと使用料を可視化し、効率的に管理することができるようになります。AWS Cost Explorer初回アクセスから24時間後に有効化されるため、セットアップ後すぐにアクセスし、できるだけ早く有効化しましょう。

2.5.2 手順

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 右上のアカウント名を展開し、「Billing and Cost Management」をクリック
  3. 左のメニューから「Cost Explorer」をクリック
  4. 「24時間後にもう一度確認してください。」というメッセージが表示されるため、案内に従って24時間後に再度AWS Cost Explorerを確認

2.5.3 確認

初回アクセスから24時間後にAWS Cost Explorerを確認し、AWS Cost Explorerが有効化されていれば、本設定は完了です。

2.6 マネジメントコンソール: ローカリゼーションとデフォルトのリージョンを編集

2.6.1 目的

AWSはリージョン単位でリソースが分離されているため、意図しないリージョンでのリソース作成は、管理漏れや不要な課金を招く要因となります。

そのため、デフォルトを物理的に近い東京リージョン (ap-northeast-1)に固定することは、設定ミスの防止だけでなく、マネジメントコンソールやCLIのレスポンス性能を最大化し、ストレスのない運用環境を構築する上で非常に有効です。

2.6.2 手順

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 右上の歯車マークをクリック
  3. ローカリゼーションとデフォルトのリージョン」の「編集」をクリック
  4. 言語」に「日本語」、「デフォルトのリージョン」に「アジアパシフィック (東京) ap-northeast-1」を選択
  5. 設定を保存」をクリック

2.6.3 確認

右上の歯車マークをクリックし、「ローカリゼーションとデフォルトのリージョン」の「言語」が「日本語」、「デフォルトのリージョン」が「アジアパシフィック (東京) ap-northeast-1」と表示されていれば、本設定は完了です。

3. AWS CloudFormationでのセットアップ

本セクションでは、

についてまとめています。

AWSマネジメントコンソールでのセットアップについても記載しておりますので、コンソール画面での設定がお好みの方はぜひご活用ください。

3.1 AWS CloudFormationとは

yamljsonのテンプレートファイルを利用して、AWSのリソースをプロビジョニングし、管理することができるIaC (Infrastructure as Code) サービス

IaC (Infrastructure as Code) とは
コードを使用してインフラストラクチャの構築・管理を行うこと

3.1.1 メリット

構築の再現性と一貫性を担保できる

  • 手動構築では避けられない設定漏れや手順の前後によるミスを排除できる
  • 開発・テスト・本番など、同一構成の環境を即座かつ寸分違わず複製できる

リソースのライフサイクルを一括管理できる

  • 複数のリソースをスタックという一つの単位で扱うため、プロジェクトの終了時に、不要になったリソースを一つずつ消して回る必要がない
  • スタックを削除するだけで、依存関係を考慮しながら安全に全リソースをクリーンアップできる

ドリフト検出により設定の乖離を把握できる

  • マネジメントコンソールから変えてしまった設定をドリフト検出で検出できる
  • コードで定義したあるべき姿と現在の実際の設定の差分を瞬時に特定できる

3.1.2 デメリット

初期の学習コストと独自記法への慣れが必要

  • プログラミング言語とは異なる独自の関数や、リソースごとの詳細なプロパティ定義を覚える必要がある
  • 最初はドキュメントの理解に時間を要するため、手動構築よりも時間がかかる

エラー発生時のロールバックとデバッグの難しさ

  • スタックの作成や更新に失敗した際のロールバックの待ち時間が長い
  • エラーログからエラー箇所を特定するのが難しい

最新機能や特定リソースへの対応にラグがある

  • AWSの全リソースが、発表と同時にAWS CloudFormationでサポートされるわけではない
  • 最新の機能や設定項目をすぐに使いたい場合は、AWS CloudFormation側が対応するまで待つか、カスタムリソースを自作して対応するといった回避策が必要になる

3.1.3 本記事での使い方

  1. 各セクションに掲載されているCloudFormationテンプレートを任意のファイル名.yamlとして自身の環境に保存
  2. 管理者ユーザーAWSマネジメントコンソールにサインイン
  3. 上部の検索ボックスにCloudFormationと入力し、CloudFormationをクリック
  4. 左のメニューから「スタック」をクリック
  5. スタックの作成」を選択し、「新しいリソースを使用 (標準)」をクリック
  6. テンプレートの準備」の「既存のテンプレートを選択」を選択
  7. テンプレートの指定」の「テンプレートファイルのアップロード」を選択
  8. テンプレートファイルのアップロード」の「ファイルの選択」をクリック
  9. 先ほど保存した任意のファイル名.yamlをアップロードし、「次へ」をクリック
  10. 任意のスタック名とパラメータを入力し、「次へ」をクリック
  11. そのまま「次へ」をクリック
  12. 詳細を確認し、「送信」をクリック

3.2 CloudFormation: AWS Budgetsの予算作成

3.2.1 目的

AWSは従量課金制のため、気づかないうちに請求が膨れ上がってしまったというケースがあります。そういった場合に備えて、AWS Budgetsを設定しておくことで、現在の利用料と月額の予測料金を把握し、予算を超えそうもしくは超えたときに通知を受け取ることができます。

本記事で掲載しているテンプレートでは、月末に予算の超過が予測された時と、実際に予算を超過した時にメールとしてユーザーに通知するよう、リソースを定義しています。

                                       
Budgets.png
CloudFormationテンプレートで作成されるアーキテクチャ

3.2.2 CloudFormationで実施する場合

  1. 下記のCloudFormationテンプレートを任意のファイル名.yaml (例: Budget.yaml)として自身の環境に保存
  2. 3.1.3 使い方の2から8まで実施
  3. 先ほど保存したBudget.yamlをアップロードし、「次へ」をクリック
  4. 任意のスタック名 (例: Budget)と、MonthlyBudgetLimitNotificationEmailのパラメータを入力
  5. 3.1.3 使い方の11から12まで実施
  6. スタックのステータスがCREATE_COMPLETEとなれば、スタックの作成は成功

各パラメータの説明

MonthlyBudgetLimit

  • 月の予算 (注意: JPYではなくUSD)
  • 本テンプレートでは、月末に予算の超過が予測された時と、実際に予算を超過した時に通知

NotificationEmail

  • 通知を受け取るメールアドレス
Budget.yaml
# Template description
AWSTemplateFormatVersion: "2010-09-09"
Description: Budget with email notification


# Parameters
Parameters:
  # Monthly budget limit (USD)
  MonthlyBudgetLimit:
    Type: Number
    Description: Monthly budget limit (USD)
    MinValue: 1
  
  # Email address to receive budget alerts
  NotificationEmail:
    Type: String
    Description: Email address to receive budget alerts
    AllowedPattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"


# Resources
Resources:
  # Monthly cost budget
  MonthlyCostBudget:
    Type: AWS::Budgets::Budget
    Properties:
      Budget:
        BudgetName: MonthlyCostBudget
        BudgetLimit:
          Amount: !Ref MonthlyBudgetLimit
          Unit: USD
        BudgetType: COST
        TimeUnit: MONTHLY
      NotificationsWithSubscribers:
        - Notification:
            NotificationType: FORECASTED
            ComparisonOperator: GREATER_THAN
            Threshold: 100
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: EMAIL
              Address: !Ref NotificationEmail
        - Notification:
            NotificationType: ACTUAL
            ComparisonOperator: GREATER_THAN
            Threshold: 100
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: EMAIL
              Address: !Ref NotificationEmail


# Outputs
Outputs:
  # Monthly cost budget
  MonthlyCostBudgetOutput:
    Description: Budget name
    Value: !Ref MonthlyCostBudget

  # Monthly budget limit (USD)
  MonthlyBudgetLimitOutput:
    Description: Monthly budget limit (USD)
    Value: !Ref MonthlyBudgetLimit

  # Email address to receive budget alerts
  NotificationEmailOutput:
    Description: Email address to receive budget alerts
    Value: !Ref NotificationEmail

3.2.3 マネジメントコンソールで実施する場合

手順 (クリックすると展開されます)
  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 右上のアカウント名を展開し、「Billing and Cost Management」をクリック
  3. 左のメニューから「予算」をクリック
  4. 予算を作成」をクリック
  5. 「予算の設定」の「カスタマイズ (アドバンスド)」を選択
  6. 「予算タイプ」の「コスト予算 - 推奨」を選択し、「次へ」をクリック
  7. 「詳細」の「予算名」に任意の予算名を入力
  8. 「予算額を設定」の「予算額 ($) を入力してください」に任意の予算額 (例: MonthlyCostBudget)を入力し、「次へ」をクリック
  9. アラートのしきい値を追加」をクリック
  10. 「しきい値」を100予算額の%とし、「トリガー」を実際、「Eメールの受信者」に通知を受け取るメールアドレスを入力
  11. アラートのしきい値を追加」を再度クリック
  12. 「しきい値」を100予算額の%とし、「トリガー」を予測、「Eメールの受信者」に通知を受け取るメールアドレスを入力し、「次へ」をクリック
  13. 再度「次へ」をクリック
  14. 詳細を確認し、「予算の作成」をクリック

3.2.4 確認

予算の一覧に作成した予算が表示されていれば、本設定は完了です。

3.3 CloudFormation: Amazon GuardDutyの有効化

3.3.1 目的

Amazon GuardDutyは、AWSの脅威検知サービスであり、Amazon GuardDutyを有効にしておくことで、アカウント侵害の早期発見が可能になります。

本記事で掲載しているテンプレートでは、Amazon GuardDutyの有効化に加えて、

についても定義しています。

そのため、Amazon GuardDutyのイベントをAmazon EventBridgeで検知し、Amazon Simple Notification Serviceのメールとしてユーザーに通知することができます。

                                       
GuardDuty.png
CloudFormationテンプレートで作成されるアーキテクチャ

3.3.2 CloudFormationで実施する場合

  1. 下記のCloudFormationテンプレートを任意のファイル名.yaml (例: GuardDuty.yaml)として自身の環境に保存
  2. 3.1.3 使い方の2から8まで実施
  3. 先ほど保存したGuardDuty.yamlをアップロードし、「次へ」をクリック
  4. 任意のスタック名 (例: GuardDuty)と、NotificationEmailのパラメータを入力
  5. 3.1.3 使い方の11から12まで実施
  6. スタックのステータスがCREATE_COMPLETEとなれば、スタックの作成は成功
  7. NotificationEmailとして設定したメールアドレスに「AWS Notification - Subscription Confirmation」というタイトルのメールが届くため、メール本文にある「Confirm subscription」のリンクをクリック
  8. リンク先で「Subscription confirmed!」と表示されることを確認

既にAmazon GuardDutyを有効化している場合、スタックの作成前にAmazon GuardDutyを無効化する必要があります。

手順と確認 (クリックすると展開されます)

手順

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 上部の検索ボックスにGuardDutyと入力し、GuardDutyをクリック
  3. 左のメニューから「設定」をクリック
  4. GuardDutyを無効にする」の「無効にする」をクリック
  5. 確認画面にて再度「無効にする」をクリック

確認
Amazon GuardDutyの設定画面を表示した時に、初期状態の画面が表示されれば、Amazon GuardDutyの無効化は完了です。

各パラメータの説明

NotificationEmail

  • 通知を受け取るメールアドレス
GuardDuty.yaml
# Template description
AWSTemplateFormatVersion: "2010-09-09"
Description: Enable GuardDuty and notify via EventBridge and SNS


# Parameters
Parameters:
  NotificationEmail:
    Type: String
    Description: Email address to receive GuardDuty alerts
    AllowedPattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"


# Resources
Resources:
  # GuardDuty Detector
  GuardDutyDetector:
    Type: AWS::GuardDuty::Detector
    Properties:
      Enable: true

  # GuardDuty SNS Topic
  GuardDutySNSTopic:
    Type: AWS::SNS::Topic
    DependsOn: GuardDutyDetector
    Properties:
      DisplayName: GuardDuty alerts SNS Topic

  # GuardDuty SNS Subscription
  GuardDutySNSSubscription:
    Type: AWS::SNS::Subscription
    DependsOn: GuardDutySNSTopic
    Properties:
      Protocol: email
      Endpoint: !Ref NotificationEmail
      TopicArn: !Ref GuardDutySNSTopic

  # GuardDuty Event Rule
  GuardDutyEventRule:
    Type: AWS::Events::Rule
    DependsOn: GuardDutySNSSubscription
    Properties:
      Description: Trigger SNS when GuardDuty finds a threat
      EventPattern:
        source:
          - aws.guardduty
        detail-type:
          - GuardDuty Finding
      State: ENABLED
      Targets:
        - Arn: !Ref GuardDutySNSTopic
          Id: GuardDutySNSTarget
          InputTransformer:
            InputPathsMap:
              severity: "$.detail.severity"
              title: "$.detail.title"
              type: "$.detail.type"
              time: "$.time"
              region: "$.region"
              accountId: "$.detail.accountId"
              description: "$.detail.description"
              id: "$.detail.id"
            InputTemplate: |
              "【GuardDuty alert detected】"
              "--------------------------------------------------"
              "【Overviews】"
              "Severity: <severity>"
              "Title: <title>"
              "Type: <type>"
              "--------------------------------------------------"
              "【Details】"
              "Time: <time>"
              "Region: <region>"
              "Account ID: <accountId>"
              "Description: <description>"
              "--------------------------------------------------"
              "Please check the details in the Management Console."
              "https://console.aws.amazon.com/guardduty/home?region=<region>#/findings?macros=current&fId=<id>"

  # Allow EventBridge to publish to SNS
  AllowEventBridgeToPublishToSNS:
    Type: AWS::SNS::TopicPolicy
    DependsOn: GuardDutyEventRule
    Properties:
      Topics:
        - !Ref GuardDutySNSTopic
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: AllowEventBridgePublish
            Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sns:Publish
            Resource: !Ref GuardDutySNSTopic


# Outputs
Outputs:
  # GuardDuty Detector
  GuardDutyDetectorOutput:
    Description: GuardDuty Detector
    Value: !Ref GuardDutyDetector

  # SNS Topic
  GuardDutySNSTopicOutput:
    Description: SNS topic for GuardDuty alerts
    Value: !Ref GuardDutySNSTopic

3.3.3 マネジメントコンソールで実施する場合

手順 (クリックすると展開されます)

Amazon GuardDutyの有効化

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 上部の検索ボックスにGuardDutyと入力し、GuardDutyをクリック
  3. 「Try GuardDuty for free」の「Enable all GuardDuty features」を選択し、「今すぐ始める」をクリック
  4. GuardDutyを有効にする」をクリック

Amazon Simple Notification Serviceトピックの作成

  1. 上部の検索ボックスにSNSもしくはSimple Notification Serviceと入力し、Simple Notification Serviceをクリック
  2. 左のメニューから「トピック」をクリック
  3. トピックの作成」をクリック
  4. 「詳細」の「タイプ」は「スタンダード」を選択し、任意の名前 (例: GuardDutySNSTopic)と表示名 (例: GuardDuty alerts SNS Topic)を入力
  5. 「アクセスポリシー」を展開し、「アドバンスド」を選択
  6. JSONエディタ内のStatement配下に下記のJSONを追加
  7. トピックの作成」をクリック
AllowEventBridgePublish.json
{
  "Sid": "AllowEventBridgePublish",
  "Effect": "Allow",
  "Principal": {
    "Service": "events.amazonaws.com"
  },
  "Action": "sns:Publish",
  "Resource": "YOUR_SNS_TOPIC_ARN"
}

Amazon Simple Notification Serviceサブスクリプションの作成

  1. 左のメニューから「サブスクリプション」をクリック
  2. サブスクリプションの作成」をクリック
  3. 「トピックARN」に先ほど作成したトピックを選択し、「プロトコル」にEメールを選択
  4. 「エンドポイント」に通知を受け取るメールアドレスを入力し、「サブスクリプションの作成」をクリック
  5. 「エンドポイント」に入力したメールアドレスに「AWS Notification - Subscription Confirmation」というタイトルのメールが届くため、メール本文にある「Confirm subscription」のリンクをクリック
  6. リンク先で「Subscription confirmed!」と表示されることを確認

Amazon EventBridgeルールの作成

  1. 上部の検索ボックスにEventBridgeもしくはAmazon EventBridgeと入力し、Amazon EventBridgeをクリック
  2. 左のメニューから「ルール」をクリック
  3. ルールを作成」をクリック
  4. 「名前」に任意の名前 (例: GuardDutyEventRule)、「説明」に任意の説明 (例: Trigger SNS when GuardDuty finds a threat)を入力
  5. 「イベントバス」はdefaultを選択し、「選択したイベントバスでルールを有効にする」を有効化した状態で「次へ」をクリック
  6. 「イベントパターン」の「AWSのサービス」にGuardDutyを選択
  7. イベントタイプ」にGuardDuty Findingを選択し、「次へ」をクリック
  8. 「ターゲット1」の「ターゲットを選択」でSNSトピックを選択
  9. 「トピック」は先ほど作成したトピックを選択
  10. 「追加設定」を開き、「ターゲット入力を設定」で入力トランスフォーマーを選択
  11. 入力トランスフォーマーを設定」をクリック
  12. 「ターゲット入力トランスフォーマー」の入力パステンプレートにそれぞれ下記のInputPathsMap.jsonInputTemplate.txtを入力し、確認をクリック
  13. 「次へ」をクリック
  14. 再度「次へ」をクリック
  15. 詳細を確認し、「ルールの作成」をクリック
InputPathsMap.json
{
  "severity": "$.detail.severity",
  "title": "$.detail.title",
  "type": "$.detail.type",
  "time": "$.time",
  "region": "$.region",
  "accountId": "$.detail.accountId",
  "description": "$.detail.description",
  "id": "$.detail.id"
}
InputTemplate.txt
"【GuardDuty alert detected】"
"--------------------------------------------------"
"【Overviews】"
"Severity: <severity>"
"Title: <title>"
"Type: <type>"
"--------------------------------------------------"
"【Details】"
"Time: <time>"
"Region: <region>"
"Account ID: <accountId>"
"Description: <description>"
"--------------------------------------------------"
"Please check the details in the Management Console."
"https://console.aws.amazon.com/guardduty/home?region=<region>#/findings?search=id=<id>"

3.3.4 確認

AWSマネジメントコンソールの左下にあるAWS CloudShellにて、Amazon GuardDutyのサンプルイベント発生用の下記コマンドを実行し、設定したメールアドレスにメールが届いていれば、本設定は完了です。

GuardDuty.sh
aws guardduty create-sample-findings \
  --detector-id $(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) \
  --finding-types "Backdoor:EC2/DenialOfService.Dns"

引用: https://dev.classmethod.jp/articles/create-a-single-sample-findings-in-guardduty/

3.4 CloudFormation: AWS CloudTrailの証跡作成

3.4.1 目的

AWS CloudTrailは、AWSのAPI操作ログを記録するサービスです。AWS CloudTrailを有効化することによって、「誰が」「いつ」「どのリソースに」「どんな操作をしたか」を把握することができます。セキュリティ事故や誤操作の調査に必須であり、AWSのセキュリティ基盤の中核となるサービスです。

本記事で掲載しているテンプレートでは、AWS CloudTrailの証跡作成とログ保存用のAmazon S3バケットの作成について定義しています。なお、Amazon S3バケットには、1年でオブジェクトを削除するライフサイクルルールを設定しています。

スタック削除時にAmazon S3バケットが空でないことによるDELETE_FAILEDを防止するために、バケットを空にするAWS Lambdaをカスタムリソースとして作成しています。

                                       
CloudTrail.png
CloudFormationテンプレートで作成されるアーキテクチャ

3.4.2 CloudFormationで実施する場合

  1. 下記のCloudFormationテンプレートを任意のファイル名.yaml (例: CloudTrail.yaml)として自身の環境に保存
  2. 3.1.3 使い方の2から8まで実施
  3. 先ほど保存したCloudTrail.yamlをアップロードし、「次へ」をクリック
  4. 任意のスタック名 (例: CloudTrail)を入力
  5. 3.1.3 使い方の11から12まで実施
  6. スタックのステータスがCREATE_COMPLETEとなれば、スタックの作成は成功
CloudTrail.yaml
# Template description
AWSTemplateFormatVersion: "2010-09-09"
Description: Create S3 bucket for CloudTrail and enable CloudTrail


# Resources
Resources:
  # S3 bucket for CloudTrail
  CloudTrailBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "cloudtrail-bucket-${AWS::AccountId}-${AWS::Region}"
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - Id: DeleteCloudTrailLogs
            Status: Enabled
            ExpirationInDays: 365
            Prefix: "AWSLogs/"

  # S3 bucket policy for CloudTrail
  CloudTrailBucketPolicy:
    Type: AWS::S3::BucketPolicy
    DependsOn: CloudTrailBucket
    Properties:
      Bucket: !Ref CloudTrailBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: CloudTrailAclCheck
            Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: s3:GetBucketAcl
            Resource: !Sub arn:aws:s3:::${CloudTrailBucket}

          - Sid: CloudTrailWrite
            Effect: Allow
            Principal:
              Service: cloudtrail.amazonaws.com
            Action: s3:PutObject
            Resource: !Sub arn:aws:s3:::${CloudTrailBucket}/AWSLogs/${AWS::AccountId}/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control

  # CloudTrail
  CloudTrail:
    Type: AWS::CloudTrail::Trail
    DependsOn: CloudTrailBucketPolicy
    Properties:
      TrailName: ManagementEvent
      S3BucketName: !Sub "cloudtrail-bucket-${AWS::AccountId}-${AWS::Region}"
      IsLogging: true
      IsMultiRegionTrail: false
      IncludeGlobalServiceEvents: false
      EnableLogFileValidation: true
      EventSelectors:
        - ReadWriteType: All
          IncludeManagementEvents: true
          DataResources: []

  # Custom resource for Lambda
  S3BucketCleaner:
    Type: Custom::S3BucketCleaner
    Properties:
      ServiceToken: !GetAtt S3CleanerFunction.Arn
      BucketName: !Ref CloudTrailBucket

  # Lambda to delete to clear S3 bucket
  S3CleanerFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt S3CleanerRole.Arn
      Runtime: python3.11
      Timeout: 300
      Code:
        ZipFile: |
          import boto3
          import cfnresponse

          def handler(event, context):
              s3 = boto3.resource('s3')
              bucket_name = event['ResourceProperties']['BucketName']
              
              try:
                  if event['RequestType'] == 'Delete':
                      bucket = s3.Bucket(bucket_name)
                      bucket.object_versions.delete()
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
              except Exception as e:
                  print(e)
                  cfnresponse.send(event, context, cfnresponse.FAILED, {"Message": str(e)})

  # IAM role for Lambda
  S3CleanerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: S3DeletePolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:ListBucketVersions
                  - s3:DeleteObject
                  - s3:DeleteObjectVersion
                Resource:
                  - !Sub "arn:aws:s3:::${CloudTrailBucket}"
                  - !Sub "arn:aws:s3:::${CloudTrailBucket}/*"


# Outputs
Outputs:
  # S3 bucket for CloudTrail
  CloudTrailBucketOutput:
    Description: S3 bucket for CloudTrail
    Value: !Ref CloudTrailBucket

  # CloudTrail
  CloudTrailOutput:
    Description: CloudTrail trail name
    Value: !Ref CloudTrail

3.4.3 マネジメントコンソールで実施する場合

手順 (クリックすると展開されます)

Amazon S3バケットの作成

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 上部の検索ボックスにS3と入力し、S3をクリック
  3. 左のメニューから「汎用バケット」をクリック
  4. 「バケットタイプ」は「汎用」を選択
  5. 「バケット名前空間」は「グローバル名前空間」を選択した場合、グローバル名前空間内で一意な名称 (例: cloudtrail-bucket-アカウントID-リージョン名)を入力し、「アカウントのリージョナル名前空間」を選択した場合は任意の名称を入力
  6. バケットを作成」をクリック

ライフサイクルルールの作成

  1. 管理」タブを表示し、「ライフサイクルルールを作成する」をクリック
  2. ライフサイクルルール名」に任意のルール名 (例: DeleteCloudTrailLogs)を入力
  3. プレフィックス」にAWSLogs/を入力
  4. ライフサイクルルールのアクション」は「オブジェクトの現行バージョンを有効期限切れにする」を選択
  5. ルールの作成」をクリック

バケットポリシーの作成

  1. アクセス許可」タブを表示し、「バケットポリシー」の「編集」をクリック
  2. 下記のバケットポリシーの「作成したバケット名」と「アカウントID」を自身の環境に合わせて変更し、「ポリシー」に入力
  3. 変更の保存」をクリック
CloudTrailBucketPolicy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "CloudTrailAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::作成したバケット名"
    },
    {
      "Sid": "CloudTrailWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudtrail.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::作成したバケット名/AWSLogs/アカウントID/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

CloudTrailの有効化

  1. 上部の検索ボックスにCloudTrailと入力し、CloudTrailをクリック
  2. 左のメニューから「証跡」をクリック
  3. 証跡の作成」をクリック
  4. 証跡名」に任意の証跡名 (例: default)を入力
  5. 既存のS3バケットを使用する」を選択し、「証跡ログバケット名」に先ほど作成したAmazon S3バケット名を選択
  6. ログファイルのSSE-KMS暗号化」を無効化
  7. 「次へ」をクリック
  8. 再度「次へ」をクリック
  9. 詳細を確認し、「証跡の作成」をクリック

3.4.4 確認

AWSマネジメントコンソールの左下にあるAWS CloudShellにて、AWS CloudTrailのログを確認する下記コマンドを実行し、ログファイルが表示されれば、本設定は完了です。

CloudTrail.sh
aws s3 ls s3://作成したバケット名 --recursive | sort | tail -n 1

AWS CloudTrailはイベント発生からAmazon S3出力までタイムラグがあります。

3.5 CloudFormation: AWS Configの有効化

3.5.1 目的

AWS Configは、AWSリソースの構成変更を記録するサービスです。AWS CloudTrailがAPI操作ログを記録するのに対し、AWS Configは構成変更を記録します。AWS Configを有効化することによって、AWSリソースの構成を容易に管理することができるようになります。

本記事で掲載しているテンプレートでは、AWS Configの有効化とログ保存用のAmazon S3バケットの作成について定義しています。なお、Amazon S3バケットには、1年でオブジェクトを削除するライフサイクルルールを設定しています。

スタック削除時にAmazon S3バケットが空でないことによるDELETE_FAILEDを防止するために、バケットを空にするAWS Lambdaをカスタムリソースとして作成しています。

                                       
Config.png
CloudFormationテンプレートで作成されるアーキテクチャ

3.5.2 CloudFormationで実施する場合

  1. 下記のCloudFormationテンプレートを任意のファイル名.yaml (例: Config.yaml)として自身の環境に保存
  2. 3.1.3 使い方の2から8まで実施
  3. 先ほど保存したConfig.yamlをアップロードし、「次へ」をクリック
  4. 任意のスタック名 (例: Config)を入力
  5. 3.1.3 使い方の11から12まで実施
  6. スタックのステータスがCREATE_COMPLETEとなれば、スタックの作成は成功

既にAWS Configを有効化している場合、スタックの作成前にAWS Configを無効化する必要があります。

手順と確認 (クリックすると展開されます)

手順
AWSマネジメントコンソールの左下にあるAWS CloudShellにて、AWS Configを無効化する下記コマンドを実行してください。

DisableConfig.sh
for r in `aws ec2 describe-regions --query Regions[*].RegionName --output text`
do
    for channel_name in `aws configservice describe-delivery-channels --region $r --query DeliveryChannels[*].name --output text`
    do 
        recorder_name=`aws configservice describe-configuration-recorders --region $r --query ConfigurationRecorders[*].name --output text`
        aws configservice delete-configuration-recorder --configuration-recorder-name $recorder_name --region $r
        aws configservice delete-delivery-channel --delivery-channel-name $channel_name --region $r
    done
done

引用: https://dev.classmethod.jp/articles/disable-config-all-region-cli/

確認
下記コマンドを実行し、DeliveryChannelsが空であることが表示されれば、AWS Configの無効化は完了です。

ConfirmConfig.sh
aws configservice describe-delivery-channels
Config.yaml
# Template description
AWSTemplateFormatVersion: "2010-09-09"
Description: Create S3 bucket for Config and enable Config


# Resources
Resources:
  # S3 bucket for Config
  ConfigBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "config-bucket-${AWS::AccountId}-${AWS::Region}"
      VersioningConfiguration:
        Status: Enabled
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - Id: DeleteConfigLogs
            Status: Enabled
            ExpirationInDays: 365
            Prefix: "AWSLogs/"

  # S3 bucket policy for Config
  ConfigBucketPolicy:
    Type: AWS::S3::BucketPolicy
    DependsOn: ConfigBucket
    Properties:
      Bucket: !Ref ConfigBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: ConfigBucketAclCheck
            Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: s3:GetBucketAcl
            Resource: !Sub arn:aws:s3:::${ConfigBucket}
          - Sid: ConfigBucketWrite
            Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: s3:PutObject
            Resource: !Sub arn:aws:s3:::${ConfigBucket}/AWSLogs/${AWS::AccountId}/Config/*
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control

  # AWSServiceRoleForConfig
  ConfigServiceLinkedRole:
    Type: AWS::IAM::ServiceLinkedRole
    DependsOn: ConfigBucketPolicy
    Properties:
      AWSServiceName: config.amazonaws.com

  # Config Recorder
  ConfigRecorder:
    Type: AWS::Config::ConfigurationRecorder
    DependsOn: ConfigServiceLinkedRole
    Properties:
      Name: default
      RoleARN: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"
      RecordingGroup:
        AllSupported: true
        IncludeGlobalResourceTypes: false

  # Config Delivery Channel
  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    DependsOn: ConfigServiceLinkedRole
    Properties:
      S3BucketName: !Ref ConfigBucket

  # Custom resource for Lambda
  S3BucketCleaner:
    Type: Custom::S3BucketCleaner
    Properties:
      ServiceToken: !GetAtt S3CleanerFunction.Arn
      BucketName: !Ref ConfigBucket

  # Lambda to delete to clear S3 bucket
  S3CleanerFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt S3CleanerRole.Arn
      Runtime: python3.11
      Timeout: 300
      Code:
        ZipFile: |
          import boto3
          import cfnresponse

          def handler(event, context):
              s3 = boto3.resource('s3')
              bucket_name = event['ResourceProperties']['BucketName']
              
              try:
                  if event['RequestType'] == 'Delete':
                      bucket = s3.Bucket(bucket_name)
                      bucket.object_versions.delete()
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
              except Exception as e:
                  print(e)
                  cfnresponse.send(event, context, cfnresponse.FAILED, {"Message": str(e)})

  # IAM role for Lambda
  S3CleanerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: S3DeletePolicy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:ListBucketVersions
                  - s3:DeleteObject
                  - s3:DeleteObjectVersion
                Resource:
                  - !Sub "arn:aws:s3:::${ConfigBucket}"
                  - !Sub "arn:aws:s3:::${ConfigBucket}/*"


# Outputs
Outputs:
  # Config Recorder
  ConfigRecorderOutput:
    Description: Config Recorder name
    Value: !Ref ConfigRecorder

  # S3 bucket for Config
  ConfigBucketOutput:
    Description: S3 bucket for Config
    Value: !Ref ConfigBucket

3.5.3 マネジメントコンソールで実施する場合

手順 (クリックすると展開されます)

Amazon S3バケットの作成

  1. 管理者ユーザーAWSマネジメントコンソールにサインイン
  2. 上部の検索ボックスにS3と入力し、S3をクリック
  3. 左のメニューから「汎用バケット」をクリック
  4. 「バケットタイプ」は「汎用」を選択
  5. 「バケット名前空間」は「グローバル名前空間」を選択した場合、グローバル名前空間内で一意な名称 (例: config-bucket-アカウントID-リージョン名)を入力し、「アカウントのリージョナル名前空間」を選択した場合は任意の名称を入力
  6. バケットを作成」をクリック

ライフサイクルルールの作成

  1. 管理」タブを表示し、「ライフサイクルルールを作成する」をクリック
  2. ライフサイクルルール名」に任意のルール名 (例: DeleteConfigLogs)を入力
  3. プレフィックス」にAWSLogs/を入力
  4. ライフサイクルルールのアクション」は「オブジェクトの現行バージョンを有効期限切れにする」を選択
  5. ルールの作成」をクリック

バケットポリシーの作成

  1. アクセス許可」タブを表示し、「バケットポリシー」の「編集」をクリック
  2. 下記のバケットポリシーの「作成したバケット名」と「アカウントID」を自身の環境に合わせて変更し、「ポリシー」に入力
  3. 変更の保存」をクリック
ConfigBucketPolicy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ConfigBucketAclCheck",
      "Effect": "Allow",
      "Principal": {
        "Service": "config.amazonaws.com"
      },
      "Action": "s3:GetBucketAcl",
      "Resource": "arn:aws:s3:::作成したバケット名"
    },
    {
      "Sid": "ConfigBucketWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "config.amazonaws.com"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::作成したバケット名/AWSLogs/アカウントID/Config/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    }
  ]
}

AWS Configの有効化

  1. 上部の検索ボックスにConfigもしくはAWS Configと入力し、AWS Configをクリック
  2. AWS Configのセットアップ」の「今すぐ始める」をクリック
  3. 配信チャネル」の「Amazon S3バケット」にて、「アカウントからバケットを選択」を選択し、先ほど作成したAmazon S3バケットを選択
  4. 「次へ」をクリック
  5. 再度「次へ」をクリック
  6. 詳細を確認し、「確認」をクリック

3.5.4 確認

AWSマネジメントコンソールの左下にあるAWS CloudShellにて、AWS Configのログを確認する下記コマンドを実行し、ログファイルが表示されれば、本設定は完了です。

Config.sh
aws s3 ls s3://作成したバケット名 --recursive | sort | tail -n 1

AWS Configはリソースに変更がない限り、ログが出ない設定もあります。

4. おわりに

これにてAWSのベストプラクティスに則った安全な環境の構築は完了です。最後まで読んでいただき、ありがとうございました。

3.1.1 メリットで述べたように、AWS CloudFormationを利用することで、設定漏れや手順の前後によるミスなく、AWSアカウントのセットアップを迅速に実施することができます。

本記事では、マネジメントコンソールで実施する場合についても記載していますが、CloudFormationで実施する場合と比較して、必要な手順が多く感じたと思います。必要な手順が多くなると、それに伴って操作ミスの可能性も増加するため、AWS CloudFormationの恩恵をより多く享受することができます。

一方、3.1.2 デメリットで述べたように、AWS CloudFormationには初期の学習コストと独自記法への慣れという壁があります。しかし、一度テンプレート化してしまえば、そのテンプレートは必ず大きな資産になると私は考えています。今はまだコードの内容が完全に理解できなくても、まずは「動かしてみる」ことから始め、徐々に中身の理解を深めていきましょう!

本記事が、安全で快適なAWSライフの一助となるだけでなく、AWS CloudFormationでのインフラ構築の第一歩を後押しするきっかけになれば幸いです。

なお、本記事に掲載しているCloudFormationテンプレートについては全て検証し、スタックの作成まで確認していますが、スタックの作成に失敗した場合は別途お知らせください。

AWS は、米国その他の諸国における Amazon.com, Inc. またはその関連会社の商標です。
その他、記載されている会社名および商品・製品・サービス名は、各社の商標または登録商標です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?