Terraform を用いて Identity Center などを用いて、アカウント設定を完了させる サンプルコード を作成しました。バグや改善点などがあれば、教えてください。コメントでも PR でも大歓迎です。
概要
このTerraform構成は、AWS Organizations配下のすべてのアカウントに対して、一括でSSOのadmin権限を割り当てるベース構成です。
⚠️ 使用前の重要な注意事項 (README に書いてあります)
このTerraform構成を使用する前に、AWSマネジメントコンソールで以下の設定を手動で完了しておく必要があります。
- AWS Organizations をルートアカウントから有効化しておくこと
- AWS Identity Center を同様にルートアカウントから有効化しておくこと
- これらのサービスは Terraform で有効化しないでください(不可逆であり自動化は非推奨)
- 本構成は 既にOrganizationsとIdentity Centerが有効化された状態 を前提としています
工夫
- アカウントを追加した後も
terraform applyを再び行うことで、そのアカウントに admin グループは AdministratorAccess でログインできる。 - 削除をしてはならないものは基本的に Terraform リソースとして管理しない。
- 初期 admin ユーザーを指定できる。
アカウントを追加した後も terraform apply を再び行うことで、そのアカウントに admin グループは AdministratorAccess でログインできる。
アカウント追加は手動で行うべきです(理由は後述)。しかし、それらに対して admin グループは AdministratorAccess をもってアクセスしたいです。
Terraform の差分検出の仕組みを利用して、この点をカバーしています。
削除をしてはならないものは基本的に Terraform リソースとして管理しない。
削除しづらいものとして、
- AWS Organizations の組織
- AWS アカウント
があります。これらは terraform destroy コマンドによって削除することは基本的に控えるべきです。そこで、割り切って Terraform 管理から外し、マネジメントコンソールから行うようにしました。
初期 admin ユーザーを指定できる
意外と便利です。
Terraform コードに関する解説
Terraform コードを書いていて、ポイントだと思った点を解説します。
Identity Store の仕組み
resource "aws_ssoadmin_permission_set" "admin" {
name = "admin"
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
session_duration = "PT8H"
tags = var.tags
}
resource "aws_ssoadmin_managed_policy_attachment" "admin" {
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
permission_set_arn = aws_ssoadmin_permission_set.admin.arn
}
resource "aws_ssoadmin_account_assignment" "admin" {
count = length(data.aws_organizations_organization.this.accounts)
instance_arn = tolist(data.aws_ssoadmin_instances.this.arns)[0]
permission_set_arn = aws_ssoadmin_permission_set.admin.arn
principal_id = aws_identitystore_group.admin.group_id
principal_type = "GROUP"
target_id = data.aws_organizations_organization.this.accounts[count.index].id
target_type = "AWS_ACCOUNT"
}
このようなときは、許可セットを用いるようです。初めて知りました。
aws_ssoadmin_account_assignment で count = length(data.aws_organizations_organization.this.accounts) としています。これによって、新しく Organizations 配下にアカウントが作成されていた場合、これを参照して許可セットに組み込みます。それ以外の部分に変更が反映されないので、そのほかのリソースも維持されたままです。
メールアドレスを必須にする
resource "aws_identitystore_user" "admin" {
for_each = var.admin_users
identity_store_id = tolist(data.aws_ssoadmin_instances.this.identity_store_ids)[0]
user_name = each.key
display_name = each.value.display_name
name {
given_name = each.value.given_name
family_name = each.value.family_name
}
emails {
value = each.value.email
}
}
メールアドレスは本来はオプション設定です。optional(string) にして dynamic 構文を使用する手もありました。
しかし、今回のユーザーの目的はマネジメントコンソールへの SSO ログインです。これをするときにメールアドレス認証が必須となるので、今回は必須にしました。
var.admin_user のタイプ
variable "admin_users" {
type = map(
object({
given_name = string
family_name = string
display_name = string
email = string
})
)
}
マップの値を object として定義することで、引数が足りないなどの対策になります。
使い方
module "account_settings" {
source = ...
}
とできます。main.tf とバージョン指定がしてあります。これ以外のバージョンでも大体動くと思いますが、動かないかもしれません。
変数指定の例は、 terraform.tfvars.tmpl にしてあります。これを terraform.tfvars とリネームして使用すると簡単かもしれません。