
TerraformでControlTower管理下のネストされたOU内にアカウントを作成する際に躓いた話
はじめに
TerraformでAWS Service Catalog(以降Service Catalog)を使ってAWS Control Tower(以下Control Tower)管理下のネストされたOUにアカウントを作成する際に躓くことがあったので、どこで躓いたのか、またどうやって解決したのか記事にします。
上記の説明だとちょっとわかりづらいので、説明を分解します。
- Control Tower管理下にネストされたOUを追加する
- Control Tower管理下のネストされたOUにアカウントを追加する
- アカウント作成にはService Catalogを使う
- Service CatalogはTerraformで定義する
ということがやりたいことです。
さらに図にするとこんな感じです。
この実装を行う際に2点ほど躓いたので、時系列でアカウントを登録するまでの流れを書いていきます。
ネストされたOUがControl Tower管理下になっていなかった
まず1つ目は、ネストされたOUがControl Tower管理下になっていなかったことです。
当然ですが、Control Tower管理のアカウントを追加しようとしているのに、OU自体がControl Tower管理下になければアカウントの追加に失敗します。
実際にエラーが出るまでの流れを見てみます。
OU作成
アカウントを追加するためのOUをTerraformで作成します。
前提として、TopLevelOUという既にControl Tower管理下として存在しているOUを事前にインポートしています。
今回はそこにSecondLevelOUを追加します。
#############################################
# Organizational Units
#############################################
# 既に存在する
resource "aws_organizations_organizational_unit" "toplevel" {
name = "TopLevelOU"
parent_id = "r-xxxx"
}
# 新規作成
resource "aws_organizations_organizational_unit" "secondlevel" {
name = "SecondLevelOU"
parent_id = aws_organizations_organizational_unit.toplevel.id
}
作成したSecondLevelOUにアカウントを追加します。
以下のブログを参考にアカウントをService Catalogでアカウントを作成します。
data "aws_servicecatalog_provisioning_artifacts" "ct" {
product_id = local.ct_product_id
}
locals {
ct_product_id = "prod-xxxxxxxxxx" # AWS > ServiceCatalog > ポートフォリオ > AWS Control Tower Account Factory Portfolio > 製品IDを参照(ポートフォリオのID)
provisioning_params = {
account-01 = {
AccountEmail = "example@example.com"
AccountName = "Demo_Account"
ManagedOrganizationalUnit = "SecondLevelOU"
SSOUserEmail = "example@example.com"
SSOUserFirstName = "User"
SSOUserLastName = "Demo"
}
}
active_pa = [
for artifact in data.aws_servicecatalog_provisioning_artifacts.ct.provisioning_artifact_details :
artifact if artifact.active == true
]
}
resource "aws_servicecatalog_provisioned_product" "account-01" {
name = local.provisioning_params.account-01.AccountName
product_id = local.ct_product_id
provisioning_artifact_id = local.active_pa[0].id
dynamic "provisioning_parameters" {
for_each = local.provisioning_params.account-01
content {
key = provisioning_parameters.key
value = provisioning_parameters.value
}
}
tags = {
"created-by" = "terraform"
}
}
terraform planではエラーは出ませんが、applyを実行するとエラーになります。
$ terraform apply
│ Error: waiting for Service Catalog Provisioned Product (pp-xxxxxxxxxxxxx) create: InvalidParametersException The parent organizational unit 'SecondLevelOU' is not enrolled in AWS Control Tower.
│
│ with aws_servicecatalog_provisioned_product.account-01,
│ on servicecatalog.tf line 24, in resource "aws_servicecatalog_provisioned_product" "account-01":
│ 24: resource "aws_servicecatalog_provisioned_product" "account-01" { │
SecondLevelOUはAWS Control Towerに登録されていません。と言われています。
Control Towerのコンソール画面を確認してみましょう。
確かにSecondLevelOUはControl Towerで管理されていない(ベースラインが有効になっていない)ですね。
なぜこのようなことが起きたのか?
今回、アカウントを登録するSecondLevelOUはTerraformで作成していました。
OU作成時に私が勘違いしていたのは、Control Tower管理下のTopLevelOUの下にSecondLevelOUを作成すれば、SecondLevelOUも自動的にControl Tower管理になると思っていました。
実際に操作すると分かるのですが、TerraformからOUを作成すると以下の動きになります。
- Control Tower管理下のTopLevelOUがある
- TopLevelOUの配下にTerraformでSecondLevelOUを作成する
- Terraformで作成したSecondLevelOUはControl Towerで管理されていない
これはTerraformというより、Control Tower自体の仕様を勘違いしていました。
Control Tower管理下にOUを追加するには以下のどちらかが必要です。
- Control Towerの機能でOUを作成する
- Organizations配下のOUにベースラインを適用する
ただし、執筆時点ではTerraformのaws providerではどちらもサポートされていません。
そのため、Terraformで作成したOUをControl Tower管理下にするためには、、手動でベースラインを適用する必要があります。
ということで、登録しましょう。
Control Towerのコンソール画面よりSecondLevelOUを選択して
アクション > 組織単位を登録 を選択します。
少し待つとベースラインの状態が成功
というステータスに変わります。
これでOUの準備は整いました。
OUの指定方法のミス
では、SecondLevelOUがControl Tower管理下に登録されたので、再度アカウントをデプロイします。
│ Error: waiting for Service Catalog Provisioned Product (pp-xxxxxxxxxxxxx) create: InvalidParametersException The parent organizational unit 'SecondLevelOU' is not enrolled in AWS Control Tower.
│
│ with aws_servicecatalog_provisioned_product.account-01,
│ on servicecatalog.tf line 24, in resource "aws_servicecatalog_provisioned_product" "account-01":
│ 24: resource "aws_servicecatalog_provisioned_product" "account-01" {
そんなバカな!?
SecondLevelOUはControl Tower管理下に登録したはずなのに同じエラーが出ています。
原因は?
ネストされたOUへアカウントを作成するためのservicecatalog.tfの親OUの指定方法が間違えていました。
正しい指定方法に修正します。
data "aws_servicecatalog_provisioning_artifacts" "ct" {
product_id = local.ct_product_id
}
locals {
ct_product_id = "prod-xxxxxxxxxx" # AWS > ServiceCatalog > ポートフォリオ > AWS Control Tower Account Factory Portfolio > 製品IDを参照(ポートフォリオのID)
provisioning_params = {
account-01 = {
AccountEmail = "example@example.com"
AccountName = "Demo_Account"
- ManagedOrganizationalUnit = "SecondLevelOU"
+ ManagedOrganizationalUnit = "SecondLevelOU (ou-xxxxxxxxxxxxx)"
SSOUserEmail = "example@example.com"
SSOUserFirstName = "User"
SSOUserLastName = "Demo"
}
}
active_pa = [
for artifact in data.aws_servicecatalog_provisioning_artifacts.ct.provisioning_artifact_details :
artifact if artifact.active == true
]
}
resource "aws_servicecatalog_provisioned_product" "account-01" {
name = local.provisioning_params.account-01.AccountName
product_id = local.ct_product_id
provisioning_artifact_id = local.active_pa[0].id
dynamic "provisioning_parameters" {
content {
key = provisioning_parameters.key
value = provisioning_parameters.value
}
}
tags = {
"created-by" = "terraform"
}
}
ネストされたOUへアカウントを登録する際はManagedOrganizationalUnitに"<OU名> (OU id)"
という形で記載する必要がありました。
(root直下のOUへアカウントを追加する場合はOU idは不要です)
では再度terraform applyを実行します。
SecondLevelOUの配下にアカウントが登録されていることが確認できます。
留意点
以前の記事でも書きましたが、Control Towerの利用ガイダンスとしてControl Towerで作成されるリソースについては変更・削除しないことが推奨されています。
今回は作成だけですが、作成したアカウントをTerraform経由で変更等の操作を行う場合は自己責任で実施するようにしましょう。
まとめ
今回はTerraformでネストされたOUに対してアカウントを追加してみました。
root直下のOUにアカウントを追加する場合と定義方法が違うため、少し戸惑いました。
普段Service Catalogをあまり触らないという点と、エラーメッセージから原因の特定が難しいという点から今回は解決までに時間がかかってしまいました。