TerraformとAWS SSOでマルチアカウント管理

6 min read読了の目安(約6000字

概要

最近はちょくちょく時間をみつけて
Landing Zoneの最小構成Starting Frameworkを作ってみてる

前回はOrganizational unit(OU)をterraformで作ってみたので
今回はAWS SSOを使って各OU配下のアカウントへのアクセスを簡便にしてみた

基本的にはこのベスプラ記事みながらやってみる

https://aws.amazon.com/jp/builders-flash/202009/multi-accounts-best-practice-2/?awsf.filter-name=*all

整理した図

実際に作ってみたものを絵にするとこんな感じ(多分

やったこと

毎度お馴染みClassmethod様の素敵記事があったので、基本これに準じてる感じ

https://dev.classmethod.jp/articles/terraform-supports-aws-sso/

SSOのユーザー、グループ作成とかはTerraformではまだ管理できないみたいで
一部コンソールから、一部terraformからって感じ。

コンソールでSSO有効化

SSOの有効化

ユーザー、グループを作成

正直自分はプライベートの勉強で作ってるので、そんなグループ分けする必要ないですが、
まぁ権限付与したグループを作成して、そこに人をくっつけていく感じ。

今回は練習程度に以下2グループ作成

  1. Landing Zone Admin Group
    1. 全アカウントを操作できるグループ
  2. Application Developer Group
    1. アプリケーション開発のworkloadアカウントにはAdminポリシー
    2. ログ貯めとくLog ArchiveアカウントにはReadポリシー

terraform管理部分の記載

sso permission setの作成

有効化したSSOをdataで読み込み
AdministratorAccessReadOnlyAccessというpermission setを作成
permission setにadminとreadのpolicyをセットする

main.tf
# read sso instance
data "aws_ssoadmin_instances" "main" {}

# create sso permission set
locals {
  administrator_access = "AdministratorAccess"
  read_only_access = "ReadOnlyAccess"
}
resource "aws_ssoadmin_permission_set" "main" {
  for_each = toset([
    local.administrator_access,
    local.read_only_access
  ])
  name         = each.value
  instance_arn = tolist(data.aws_ssoadmin_instances.main.arns)[0]
}

# set policy to sso permission set
resource "aws_ssoadmin_managed_policy_attachment" "main" {
  for_each = aws_ssoadmin_permission_set.main
  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  managed_policy_arn = "arn:aws:iam::aws:policy/${each.key}"
  permission_set_arn = each.value.arn
}

landing zone admin groupの関連ずけ

DisplayNameでFilterして作成したGroupを読み込み
後は全AWSアカウントにadminのpermissionを紐づける
これでlanding zone admin groupに属するuserは全アカウントにadminでアクセスできるはず

main.tf
// landing zone admin group
# find sso landing zone admin group
data "aws_identitystore_group" "admin" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]
  filter {
    attribute_path  = "DisplayName"
    attribute_value = "landing-zone-admin"
  }
}

# set admin permission to admin group and link to all aws account
resource "aws_ssoadmin_account_assignment" "admin" {
  for_each = toset(aws_organizations_organization.org.accounts[*].id)

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  permission_set_arn = aws_ssoadmin_permission_set.main[local.administrator_access].arn

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

  target_id   = each.value
  target_type = "AWS_ACCOUNT"
}

application developer groupの関連ずけ

DisplayNameでFilterして作成したapplication developer groupを読み込み
アプリケーション開発用のworkload AWSアカウントにadminのpermissionを紐づける
ConfigLogやCloudTrailのログがたまるLog Archive AWSアカウントにはreadのpermissionを紐付ける

main.tf
// application developer group
# find application developer group
data "aws_identitystore_group" "application_developer" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]
  filter {
    attribute_path  = "DisplayName"
    attribute_value = "application-developer"
  }
}

# set admin permission to admin group and link to all aws account
resource "aws_ssoadmin_account_assignment" "application_developer" {
  for_each = { for ap in [
    {
      account_id = aws_organizations_account.ucwork_production_account.id,
      permission_set = local.administrator_access
    },
    {
      account_id = aws_organizations_account.log_archive_production_account.id,
      permission_set = local.read_only_access
    }
  ] : ap.account_id => ap }

  instance_arn       = tolist(data.aws_ssoadmin_instances.main.arns)[0]
  permission_set_arn = aws_ssoadmin_permission_set.main[each.value.permission_set].arn

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

  target_id   = each.value.account_id
  target_type = "AWS_ACCOUNT"
}

(terraform初心者すぎて、ループの書きっぷりが合ってるかわからん

後はお馴染みの
terraform planterraform planでAWSに適用する

検証

それでは実際のログインして検証してみまっす

SSOでサインインしてみる

SSOページにログインのURLはってあるのでアクセス

SSOユーザーで登録したアカウントとパスワードでログイン

landing zone admin groupに属したユーザーは全AWSアカウントにアクセスできそう

application developer groupに属したユーザーでログインすると
workload用のucwork productionアカウントにadmin権限、ログはread権限になってました

実際にManagement Consoleからログインしてみると
なんか専用のAWSReservedSSO_xxxっていうアカウントでサインインできた

terraformのprofileもSSOのユーザーに切り替える

ここまできたら、manegement accountのIAMユーザーcredentialで操作してた
TerraformもSSOのlanding zone admin userのcredentialで操作したい
(基本ユーザー管理はSSOのものだけでやりたい

$ # sso使ってprofileファイルの生成
$ aws configure sso
$
$ # profile指定すると対象のアカウントを操作できる 
$ aws s3 ls --profile AdministratorAccess-xxx
$
$ # SSO経由でログインする
$ aws sso login --profile AdministratorAccess-xxx
$
$ # 環境変数セットしとくとこのProfile見てくれるようになる
$ echo "export AWS_PROFILE=AdministratorAccess-xxx" >> ~/.zshenv

後はterraform init, terraform plan, terraform applyで使えるようになるさ

まとめ

AWSを使う側はログインさえしてしまえば
権限が付与されたアカウントの操作ができるのでとっても便利すね。アカウントの管理1箇所で済むし😎

そして、OU, AWS Accountのterraform管理は気軽にdestroyできないので
ディレクトリ単位で区切った方が良さそう・・・

とにかく長くなった。先は長い。
そろそろコード書きたいけど。インフラ強い男になりたいので頑張って続ける🤹‍♂️