150超のAWSマルチアカウント環境における「AWS SSO」の設定をTerraform管理に移行した話

こんにちは。マネーフォワードのgotoken(@kennygt51)です。

突然ですが、マルチアカウントAWS環境の管理業務をおこなっている皆さん、AWS SSOやってますか??
当社のAWS環境の改善活動に取り組む中で、AWS SSOの便利さにすっかり虜になってしまいました。
今回の記事では僕が業務で取り組んだ『150超のAWSマルチアカウント環境における「AWS SSO」の設定をTerraform管理に移行した話』について紹介します

AWSアカウントへのアクセスコントロールの歴史

AWS SSOやTerraform管理の話をする前に、当社のAWSアカウントへのアクセスコントロールの歴史を紐解いてみましょう。
 

はじめてのAWS SSO

2020年の初め頃、当社のAWS環境にAWS SSOがはじめて導入されました。それ以前は、踏み台用のAWSアカウントにのみIAMユーザを作成し、アクセスしたいAWSアカウントのIAMロールにスイッチする方式を採用していました。

そんな中、少しずつAWSを利用する開発エンジニアが増えてきました。前述したIAMユーザを作成する方式だと、利用者が増えるにつれてユーザ管理の運用コストがどんどん高くなる(退職時にIAMユーザを削除する必要があるなど)という懸念がありました。そこで、当社で既に利用していたAzure Active Directory(以下、Azure AD)とAWS SSOを連携させる(アイデンティティストアとしてAzure ADを指定し、ユーザ・グループの管理をAzure ADに寄せる)ことで、運用コストを下げつつAWSを利用する開発エンジニアにとってより便利な仕組みを作りたい、という機運が高まっていました。しかしアクセス権限セットの設計や利用手順などの知見がなく、いきなりの全社展開は難しいと判断したため、SANDBOX用のアカウントや特定のチームのみ利用するといった形で小さく運用を始めることにしました。

そんな中、2020年中旬頃に本番環境でマルチテナント&マルチアカウントアーキテクチャを採用したことを契機として、新規で作成するAWSアカウントについては従来のIAMロールにスイッチする方式ではなくAWS SSOを使ってもらう方針に舵を切りました。これによりAWS SSOを利用する流れは加速し、2021年3月現在では社内の大多数のエンジニアがAWS SSOを使ってAWSアカウントにアクセスするようになりました。

ここまでの流れを読んでいただければわかるとおり、AWS SSOの導入は、特定の環境やチームにおいてスモールスタートしその後大きく広げていくというやり方で進めてきました。導入はうまく進みましたが、弊害としてAWS SSOそのものの運用負荷が無視できないレベルになってきました。

中央集権運用の限界

少し話は逸れますが、当社が最初にAWS SSO導入した時点ではAWS SSOにAPIが提供されていませんでした。 そのためAWS SSO管理者のような役割を持ったエンジニアにマネージドアカウントのを操作する権限を付与した上で、マネジメントコンソールから手作業で設定を変更する必要がありました。

その当時は、Googleフォームを使って作成した依頼フォームに開発エンジニアから権限付与依頼を出してもらいその内容に応じて管理者がマネジメントコンソールをポチポチ触って変更する、という運用をおこなっていました。この運用はAWSアカウントが10程度であれば回りそうではありますが、AWSアカウントの数が増えれば増えるほど管理者の運用コストが増えてしまうので好ましくありません。
具体的には「新しいAWSアカウントが増えるタイミング」「特定のエンジニアに対して特別な権限を付与したい場合」「テンプレートで用意していたアクセス権限セット以外のアクセス権限セットが作りたくなったタイミング」などで変更作業をおこなう必要があります。加えて依頼のレビューフローが確立されていないので変更作業はAWS SSO管理者任せになってしまいます。
このような運用を1年弱続けた結果「特定のユーザに不要な強権限が割り当てられている」「何に使っているかわからないアクセス権限セットが存在する」「アクセス権限セットの割当が可視化されていない」など、運用上の課題が多く発生してしまい、管理者による中央集中運用は限界に達しました。

コード化したかった。。

これらの課題を解決するためにも、AWS SSOの設定をコード管理したい機運が高まっていました。 コード化することで不要なアクセス権限セットや不必要な強権限の割当が可視化されます。またデプロイを自動化することでPullRequestベースで設定作業が完結します。AWS SSO管理者の負荷を減らすとともに、権限設定を他のインフラメンバーや開発エンジニアにも理解してもらうことも容易です。
当社のAWSインフラの大部分はTerraformを用いてコード化されているので、AWS SSOの設定についてもTerraformを使ってコード化したいと考えていました。しかし、先程述べたとおり最近までAWS SSOにはAPIが提供されておらず、当然Terraformのサポートもありませんでした。

夢にまで見たAPIサポート

しかし!2020年9月にAPIが提供されたことでTerraformでもAWS SSOのリソースがサポートされました!

そこで、今までマネジメントコンソールから手動で作成したAWS SSOのリソースをコード管理することにしました。

AWS SSOをTerraform管理にするために必要なこと 

ではここから、AWS SSOの設定をTerraform管理に移行する為のステップと具体的におこなった作業について紹介します。

terraform import

今まで手動で登録していたクラウドのリソース(今回はアクセス権限セットや、アカウント・ユーザ・グループへの紐付けなど)をTerraformでコード管理するためにはterraform importコマンドを使います。terraform importとは、既存のAWSリソースをTerraform管理下に取り込む為のコマンドです。

terraform importを使ったおおまかな作業の流れは次のとおりです。

  • importしたいリソースについて空の定義を用意する
  • リソースをimportする
    • stateファイルにimportしたリソースの情報が書き込まれる
  • importしたリソースに合わせてTerraformのコードを修正する
  • terraform planを実行して差分がなくれば完了

ResourceData

AWS SSOの設定をTerraform管理化に移行する為には、次のリソースがコード管理の対象になります。

また次に挙げるデータソースもあわせて使用します。

  • aws_identitystore_group:アイデンティティストアにおけるグループを取得するData Sourceです。Azure ADなどの外部IdPによってプロビジョニングされたグループも取得可能です。
  • aws_identitystore_user:AWSのIdentity Storeにおけるユーザを取得するData Sourceです。Azure ADなどの外部IdPによってプロビジョニングされたユーザも取得可能です。

これらのリソースを使って、アクセス権限セット・AWS管理ポリシーのアタッチ、AWSアカウント・ユーザ/グループ・アクセス権限セットの紐付けをterraform importしていきます。

terraform import作業の流れ

ここからは実際に取り組んだimport作業について紹介します。

まずは棚卸しから

実際にimport作業をおこなう前に、少しでも見通しのよい状態にするために既存のAWS SSO設定の整理からはじめました。

まず不要なアクセス権限セットを削除しました。マネジメントコンソールからアクセス権限セットを表示してAWSアカウントタブを選択すると、そのアクセス権限セットが紐付いたAWSアカウントの一覧が表示されます。

この表示をもとに、AWSアカウントに紐付いていない場合や、紐付いていても既に利用されていなさそうなものをリストアップし、関係者にヒアリングした上で不要なアクセス権限セットを削除しました。また明らかに冗長なアクセス権限セット(似たようなIAMポリシーが付与されているもの)についても、片方のアクセス権限セットに寄せることで冗長なリソースを整理しました。

次にアカウントに対するユーザ/グループ・アクセス権限セットの紐付けの棚卸しをおこないました。明らかに不要であったり冗長なアクセス権限セットの割当がおこなわれているものを洗い出し、関係者にヒアリングした上で不要な割当を削除しました。

アクセス権限セットのimport

全体の見通しがよくなったら、アクセス権限セットのimport作業を進めていきます。
AdministratorAccessという名前のアクセス権限セットをimportする場合を例として紹介します。

まずは空の定義をTerraformのコードとして用意します。

resource "aws_ssoadmin_permission_set" "administratoraccess" {
}

terraform importコマンドを使ってaws_ssoadmin_permission_setリソースをimportします。
第一引数にはアクセス権限セットのARN、第二引数にSSOインスタンスのARNを指定します。

terraform import aws_ssoadmin_permission_set.administratoraccess arn:aws:sso:::permissionSet/ssoins-XXXXXXXXXXXX/ps-XXXXXXXXXXXX,arn:aws:sso:::instance/ssoins-XXXXXXXXXXX

次にIAMポリシーをアクセス権限セットに紐付けるリソースであるaws_ssoadmin_managed_policy_attachmentをimportするために空のコードを用意します。

resource "aws_ssoadmin_managed_policy_attachment" "administratoraccess_policy_to_administratoraccess_permission_set" {
}

terraform importコマンドを使ってaws_ssoadmin_managed_policy_attachmentリソースをimportします。
第一引数には紐付けるポリシーのARN、第二引数にはアクセス権限セットのARN、第三引数にはSSOインスタンスのARNを指定します。

terraform import aws_ssoadmin_managed_policy_attachment.administratoraccess_policy_to_administratoraccess_permission_set arn:aws:iam::aws:policy/AdministratorAccess,arn:aws:sso:::permissionSet/ssoins-XXXXXXXXXXXX/ps-XXXXXXXXXXXX,arn:aws:sso:::instance/ssoins-XXXXXXXXXXXX

ここまでできたらアクセス権限セットのimportは完了です。あとはTerraformのコードを修正します。

resource "aws_ssoadmin_permission_set" "administratoraccess" {
  name             = "AdministratorAccess"
  instance_arn     = tolist(data.aws_ssoadmin_instances.main.arns)[0]
}

resource "aws_ssoadmin_managed_policy_attachment" "administratoraccess_policy_to_administratoraccess_permission_set" {
  instance_arn       = aws_ssoadmin_permission_set.administratoraccess.instance_arn
  managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
  permission_set_arn = aws_ssoadmin_permission_set.administratoraccess.arn
}

terraform planを実行して、差分がなければimport完了です。
もしアクセス権限セットにアクセス権限ポリシーが定義されている場合はaws_ssoadmin_permission_set_inline_policyをimportする必要があるので、同じような流れでimport作業をおこなう必要があります。

紐付けのimport

次に、アクセス権限セット・ユーザ/グループ・AWSアカウントを紐付けるリソースであるaws_ssoadmin_account_assignmentをimportします。
SANDBOXアカウントに、インフラチームを管理者権限(先程作成したAdministratorAccessというアクセス権限セット)で紐付ける場合を例として紹介します。

まずは空のリリースを用意します。
また今回はリソースそのものに加えて紐付けるユーザ/グループをdataで参照しています。当社のAWS SSOではアイデンティティストアとしてAzure ADを指定していますが、それによりAzure ADのユーザ/グループがAWS SSOにプロビジョニングされています。これらのユーザ/グループはTerraformで管理する必要がありませんがaws_ssoadmin_account_assignmentリソースを作成する上でユーザ/グループをパラメータとして指定する必要があるため、データソースとして参照する必要があります。

resource "aws_ssoadmin_account_assignment" "sandbox_infra_administratoraccess" {
}

data "aws_identitystore_group" "infra" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]

  filter {
    attribute_path  = "DisplayName"
    attribute_value = "Infra"
  }
}

その後にterraform importを実行します。第一引数にマネジメントコンソール上から確認できるユーザID/グループID、第二引数にユーザの場合はUSER、グループの場合はGROUP、第三引数に紐付けるAWSアカウントのアカウントID、第四引数に紐付けるアクセス権限セットのARN、第五引数にSSOインスタンスのARNを指定します。

terraform import aws_ssoadmin_account_assignment.sandbox_infra_administratoraccess XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX,GROUP,0000111122223333,AWS_ACCOUNT,arn:aws:sso:::permissionSet/ssoins-XXXXXX/ps-XXXXXX,arn:aws:sso:::instance/ssoins-XXXXXX

ここまででterraform importは完了です。あとはTerraformのコードを修正します。

resource "aws_ssoadmin_account_assignment" "sandbox_infra_administratoraccess" {
  instance_arn       = aws_ssoadmin_permission_set.administratoraccess.instance_arn
  permission_set_arn = aws_ssoadmin_permission_set.administratoraccess.arn

  principal_id   = data.aws_identitystore_group.infra.group_id
  principal_type = "GROUP"

  target_id   = local.aws_account_ids["sandbox"]
  target_type = "AWS_ACCOUNT"
}

再びterraform planを実行し、差分がなければimport完了です。

コード化によって得られた恩恵

ある程度のコストを割いて既存の設定を全てコード化した結果、次に挙げるような恩恵が得られました。

インフラチームの運用負荷を削減した

Terraform管理下においたことで、コードをGitHubリポジトリで管理することができるようになりました。 それにより、開発エンジニアからの権限設定依頼はGoogleフォームからPull Requestに移行しました。GitHubという普段の業務で使い慣れているツール上でレビューが可能になったことと、デプロイも管理者による手作業からterraform applyに変更されたことで、依頼から対応完了までのリードタイムが削減されました。

オペミスのリスクを軽減した

今まではマネジメントコンソールを手でポチポチして設定変更作業をおこなっていました。AWS SSO管理者による手作業に依存する運用だったのでオペミスのリスクがありましたが、コード化することでオペミスのリスクを軽減することができました。

付与されている権限が可視化された

今までは実際にAWS SSOでどんな権限が設定されているのかを見ることができるのは、マネージドアカウントへのアクセス権限をもった一部のエンジニアに限られていました。そのため権限設定はブラックボックスになっており、権限割当のトラブルが発生したときの調査及び即時対応がしづらい状態でした。今回のコード化によってGitHubリポジトリへのアクセス権限さえ持っていれば誰でもコードを見ることができる状態になりました。「今現在、どういう権限設定がされているのか」という情報が可視化された ことにより、AWSアカウントに対するアクセスのトラブルシュートがスムーズにおこなえるようになりました。

(おまけ)SSO インスタンスを東京リージョンに移設できた

AWS SSOは2020年9月に東京リージョンで利用できるようになっています。当社では東京リージョン対応以前からAWS SSOを利用していたのでオレゴンリージョンにインスタンスを作成していました。
東京リージョンがサポートされたのでSSOインスタンスを移したかったのですが、移行作業時には、既存の設定を削除して再登録する必要がありました。 コード化されていない状態では既存の設定を手作業で全て再登録するのが現実的ではなかったため、躊躇していました。
今回のコード化にともないterraform applyコマンドを実行するだけで移行作業ができるようになったので、併せて東京リージョンへの移設作業をおこないました。結果、AWS SSOを使ったマネジメントコンソールへのログインが若干早くなったようです。

おわりに

既存のリソースをTerraformのコード管理に置く対応は、泥臭い調整や作業をおこなう必要がある場合もあります。AWS SSOについてはコード管理することで享受できるメリットも大きいので挑戦する価値はあると考えています。

マネーフォワードでは、150を超えるマルチアカウントAWS環境の運用に興味のあるエンジニアを募集しています。
ご応募お待ちしています。


【サイトのご案内】
マネーフォワード採用サイト
Wantedly
京都開発拠点

【プロダクトのご紹介】
お金の見える化サービス 『マネーフォワード ME』 iPhone,iPad Android

ビジネス向けバックオフィス向け業務効率化ソリューション 『マネーフォワード クラウド』

おつり貯金アプリ 『しらたま』

お金の悩みを無料で相談 『マネーフォワード お金の相談』

だれでも貯まって増える お金の体質改善サービス 『マネーフォワード おかねせんせい』

金融商品の比較・申し込みサイト 『Money Forward Mall』

くらしの経済メディア 『MONEY PLUS』

Pocket