🫵

もしあなたが1人っきりでSaaSのインフラを作ることになったら...

2023/12/07に公開

この記事は、クラウドワークス Advent Calendar 2023 シリーズ1の7日目の記事です。

はじめに

crowdworks.jpでSREをしていますciloholicです。

前職では、長らくバックエンド兼インフラエンジニアをしていたんですが、ある日突然SaaSを作るぞと言われて、SaaSのインフラを1人で作る羽目になったことがあります。
当時は、サービス自体の開発に追われていて、AWSのマルチアカウント管理やセキュリティサービスの導入(Config/CloudTrail/GuardDuty等)などがおざなりになっていました。
その時の戒めを込めて、再び「SaaSのインフラを作れ」と言われても大丈夫なように、TerraformでAWSのマルチアカウント管理とセキュリティサービスの導入を行なってみました。

タイトルでは SaaSのインフラ というように話題を大きめに書いてますが、本記事では AWSのマルチアカウント管理セキュリティサービスの導入 のみに焦点を当てています。
それ以外については、SaaSによって千差万別なので、本記事では割愛しています。

実際にTerraformで実装したコードは、GitHubに格納しています。
本記事では、Terraformのコードは載せず、実装の流れや実装時の注意点などを主に書き連ねていきます。

想定しているAWSアカウント構成

AWSでマルチアカウント管理を行なおうとした場合、AWS Organizationsを利用するのが一般的です。
AWS Organizationsでは、下記のような機能が提供されています。

AWS Organizations には、クラウド環境を一元管理および統制する機能があります。アカウントを 1 つの請求書で管理および整理したり、組織全体の中央ポリシーと設定要件を設定したり、組織内にカスタムのアクセス許可または機能を作成したり、他のアカウントに責任を委任して組織の代わりに管理できるようにしたりすることができます。
加えて、AWS Organizations は他の AWS のサービスと統合しているため、中央での設定、セキュリティメカニズム、監査要件、組織内のアカウント間でのリソース共有を定義できます。

本記事でも例に漏れず、AWS Organizationsを利用してマルチアカウント管理を行なっていきます。

便利なもので、安全なマルチアカウントAWS環境のセットアップと管理できるAWS Control Towerが提供されており、AWS Organizationsの設定やセキュリティサービスの導入を自動でセットアップしてくれます。
しかし、自主練にならないため、AWS Control Towerの構成を参考にOU構成をカスタマイズして自作していきたいと思います。

小規模なSaaSであったとしても、本番・開発・ステージングぐらいはAWSアカウントを分けたいところです。
また、ワークロード環境に加えて、セキュリティ用やログ集積用のAWSアカウントも欲しいです。
本来なら、Log-Archive用やAudit用のAWSアカウントも作成したいところですが、自主練のために何個もAWSアカウントを作成したくないので、Security用に統合しています。

  • Root
    • [Account]Management
    • [OU]Core
      • [Account]Jump
      • [Account]Security( + Log-Archive + Audit)
    • [OU]Workloads
      • [Account]Production
      • [Account]Development
      • [Account]Staging

Terraform周りのバージョン

Terraform周りのバージョンについては、下記の通りです。

  • Terraform: v1.6.4
  • terraform-provider-aws: v5.26.0

Terraformのディレクトリ構成

Terraformで実装する際は、下記のようなディレクトリ構成にしています。
各種AWSアカウントごとにtfstateファイルを分けて管理します。

.
└── accounts
    ├── management
    │   └── .terraform-version
    ├── core
    │   ├── jump
    │   │   └── .terraform-version
    │   └── security
    │       └── .terraform-version
    └── workloads
        ├── production
        │   └── .terraform-version
        ├── development
        │   └── .terraform-version
        └── staging
            └── .terraform-version

AWSのマルチアカウント管理

AWS Organizations

初めにOrganizationとOU、各種AWSアカウントを作成していきます。

OrganizationとOUの作成

各種AWSアカウントの作成

AWS OrganizationsでAWSアカウントを作成すると、ルートユーザーに加えて OrganizationAccountAccessRole というIAMロールが自動的に作成されます。
今後はスイッチロールを実装するまで、このIAMロールにスイッチしてAWSアカウントにアクセスすることになります。

[小ネタ]AWSアカウントの削除

terraform-provider-aws v4.9.0では、aws_organizations_accountclose_on_deletionが追加されました。
close_on_deletiontrueにすると、AWSアカウントが閉鎖できるようになりました。
以前は、OraganizationからAWSアカウントが除外されるだけで、AWSアカウントを閉鎖できませんでした。
ちゃんと閉鎖したい場合は、close_on_deletiontrueにしておくと良いです。
AWSアカウント閉鎖後はログインができなくなり、90日経過すると完全に削除されます。

各種AWSアカウント作成後の対応

セキュリティ強化の為、各種AWSアカウントのMFA有効化だけは必須で対応しておきましょう。

  • [必須]ルートアカウントのMFA有効化
    • 初期パスワードが発行されてないため、パスワードをリセットしてからMFAを有効化する必要があります
  • [任意]不要なリソースの削除

Service Control Policy(SCP)の作成

Service Control Policy(SCP)でリージョン単位のAWSへのアクセスを制限しています。
基本的に ap-northeast-1us-east-1 しか利用しない想定ですが、AWS Chatbotが us-east-2 で動作しているため、us-east-2 も利用できるようにしています。
AWS Chatbotのような例もあるので、リージョン単位のアクセス制限には注意が必要です。

  • accounts/management/organization.tf
    • aws_organizations_policy.region_restriction
    • aws_organizations_policy.core_region_restriction
    • aws_organizations_policy.workloads_region_restriction
    • aws_organizations_policy_attachment.core_region_restriction
    • aws_organizations_policy_attachment.workloads_region_restriction

[小ネタ]AWS Chatbotのリージョン

AWS Chatbotのトラブルシューティングにリージョンの記載があります。
https://docs.aws.amazon.com/chatbot/latest/adminguide/chatbot-troubleshooting.html#chatbot-troubleshooting-regions

tfstate用S3バケットの作成

各種AWSアカウントのS3にtfstate用のS3バケットを用意します。
S3バケット名の末尾にランダム文字列を付与して重複しないようにしています。
必要であれば、バージョニングも有効にしておきます。

tfstate用S3バケット
$ aws-vault exec *** -- aws s3api create-bucket \
  --bucket tfstate-me8aelie \
  --region ap-northeast-1 \
  --create-bucket-configuration \
  LocationConstraint=ap-northeast-1

S3バケットが作成できたら、Terraformにインポートしておきます。

この作業を各種AWSアカウントにも同様に行ないます。

  • accounts/management/s3.tf
    • aws_s3_bucket.tfstate_me8aelie
    • aws_s3_bucket_ownership_controls.tfstate_me8aelie
    • aws_s3_bucket_server_side_encryption_configuration.tfstate_me8aelie

IAMのスイッチロールの設定

各種AWSアカウントに対して、IAMのスイッチロールを設定を行ないます。

Jumpアカウント

管理者権限付きのIAMユーザーを用意します。
必要であれば、自身のパスワード変更権限やMFA変更権限を付与した一般ユーザー用のIAMユーザーも作成してみてください。

Jumpアカウント以外

Jumpアカウント経由のMFA有効済みユーザーのみがスイッチロールできる、管理者権限付きのIAMロールを作成します。
必要であれば、権限を制限した一般ユーザー用のIAMロールも作成してみてください。

この作業を各種AWSアカウントにも同様に行ないます。

スイッチロールの動作確認

ここまでできていれば、各種AWSアカウントにスイッチロールできるようになっているはずです。


セキュリティサービスの導入

Audit用S3バケットの作成

SecurityアカウントにAWS ConfigとAWS CloudTrailのログを格納するS3バケットを作成します。
各種AWSアカウントのAWS ConfigとAWS CloudTrailのログは、このS3バケットに集約されます。

  • accounts/core/security/s3.tf
    • aws_s3_bucket.aws_config
    • aws_s3_bucket_server_side_encryption_configuration.aws_config
    • aws_s3_bucket_policy.aws_config
    • aws_s3_bucket.aws_cloudtrail
    • aws_s3_bucket_server_side_encryption_configuration.aws_cloudtrail
    • aws_s3_bucket_policy.aws_cloudtrail

AWS Config

各種AWSアカウントにAWS Configを導入します。

AWS Configは、リージョン単位に有効化する必要があるため、利用可能なすべてのリージョンで有効化するのが推奨されています。
本記事では、AWS OrganizationsのSCPで不要なリージョンのアクセス制限をしているので、利用しているリージョンのみを有効化するだけで済ませています。

また、aws_config_configuration_recorderで作成するとグローバルリソースの記録も含まれてしまうため、東京リージョンのみでグローバルリソースを記録し、他のリージョンでは記録しないように設定しています。

この作業を各種AWSアカウントにも同様に行ないます。

  • accounts/management/config.tf
    • aws_config_configuration_recorder.config_recorder
    • aws_config_delivery_channel.default
    • aws_config_configuration_recorder_status.default
    • aws_config_configuration_recorder.config_recorder_us_east_1
    • aws_config_delivery_channel.default_us_east_1
    • aws_config_configuration_recorder_status.default_us_east_1

AWS Configの委任

AWS Configは、Securityアカウントに委任できます。

ただし、AWS Configの委任は、Terraform経由では行なえないため、AWS CLIで対応します。

$ aws-vault exec management -- aws organizations register-delegated-administrator --account-id 222222222222 --service-principal config.amazonaws.com
$ aws-vault exec management -- aws organizations register-delegated-administrator --account-id 222222222222 --service-principal config-multiaccountsetup.amazonaws.com

AWS Config Aggregator

上記でAWS Configの委任が完了したら、Aggregatorを導入します。

AWS Config Aggregatorという機能を利用すると、AWS Configで収集しているリソースやAWS Config Ruleのチェック結果をマルチアカウント/マルチリージョンより集約してレポーティングできます。
AggregatorをSecurityアカウントに委任することで、SecurityアカウントからAWS Configのレポートを確認できるようになります。

AWS CloudTrail

各種AWSアカウントにAWS CloudTrailを導入します。

AWS CloudTrailは、Organizationに紐づくメンバーアカウントに対して、マルチリージョンよりログを集約できます。
is_organization_trailtrueにすれば、各種AWSアカウントでAWS CloudTrailが有効化されます。

AWS CloudTrailの委任

AWS CloudTrailは、Securityアカウントに委任できます。

ただし、AWS CloudTrailの委任は、Terraform経由では行なえないため、AWS CLIで対応します。

$ aws-vault exec management -- aws organizations register-delegated-administrator --account-id 222222222222 --service-principal cloudtrail.amazonaws.com

AWS GuardDuty

各種AWSアカウントにAWS GuardDutyを導入します。

AWS GuardDutyは、リージョン単位に有効化する必要があるため、利用可能なすべてのリージョンで有効化するのが推奨されています。

この作業を各種AWSアカウントにも同様に行ないます。

AWS GuardDutyの委任

AWS GuardDutyは、Securityアカウントに委任できます。

AWS Security Hub

各種AWSアカウントにAWS Security Hubを導入します。

AWS Security Hubは、リージョン単位に有効化する必要があるため、利用可能なすべてのリージョンで有効化するのが推奨されています。
本記事では、セキュリティコントロールの適用まで行なっていないので、必要な方は別途対応をしてください。

この作業を各種AWSアカウントにも同様に行ないます。

AWS Security Hubの委任

AWS Security Hubは、Securityアカウントに委任できます。

AWS Security Hubの有効化

Organizationに紐づくメンバーアカウントに対して、AWS Security Hubを有効化します。

ただし、メンバーアカウントのSecurity Hub有効化は、Terraform経由では行なえないため、AWS CLIで対応します。

$ aws-vault exec security -- aws securityhub create-members --account-details '[{"AccountId":"<accountId>"}]'

AWS Security Hub Finding Aggregator

上記でAWS Security Hubの委任が完了したら、Finding Aggregatorを導入します。

AWS Security Hub Finding Aggregatorという機能を利用すると、AWS Security Hubで収集しているコントロールコンプライアンスのステータス、セキュリティスコアをマルチアカウント/マルチリージョンより集約できます。
Finding AggregatorをSecurityアカウントに委任することで、SecurityアカウントからAWS Security Hubのイベント結果を確認できるようになります。

AWS Security Hubの通知

AWS Security Hubは、他のセキュリティサービスと統合することで、セキュリティインシデントの通知を一元管理できます。
本記事で言うと、AWS ConfigやAWS GuardDutyのイベントをAWS Security Hubに集約し、AWS EventBridgeで検知してAWS ChatbotでSlackに通知できます。

本来なら通知まで実装したかったんですが、AWS Security Hubの導入までで力尽きました。

さいごに

今回は、AWSのマルチアカウント管理とセキュリティサービスの導入を雑にTerraformで実装しました。
委任周りの対応がTerraformでできなかったり、セキュリティサービスの導入に四苦八苦する部分もありましたが、良い自主練になりました。
これで、突然SaaSのインフラを作れと言われても大丈夫そうです。

GitHubで編集を提案

Discussion