既存 AWS IAM Identity Center ユーザーを Terraformにインポートする【import ブロックで超簡単】

シェルスクリプトと新しいコマンドオプションで必要なコードは自動生成
2023.07.18

どうも、ちゃだいん(@chazuke4649)です。

Terraform v1.5にて新たに import ブロックと既存リソースのHCL生成が追加され、config-driven import (手動ではなく設定ファイルが起点となるインポート) が可能となりました。

背景

今まで既存のAWSリソースをTerraformにインポートする方法といえば、

  • terraform import コマンドによる地道な作業
  • Terraformer ツール頼み

でどちらも厳しい状況でした。

そんな中、v1.5では救世主とも呼べる新たな選択肢が誕生しました。

今回は試しに、マネコン あるいは CLI で作成していた既存の AWS IAM Identity Center ユーザーの Terraform コードを自動生成し、Terraform にインポートしてみます。

前提

  • Terraform: v1.5.2 (v1.5の新機能が必須)
  • AWS Provider: v5.7.0

手順

手順は以下となります。

  1. importブロックを生成する (シェルスクリプト)
  2. resourceブロックを生成する (コマンドオプション)
  3. applyしてインポートする

※importブロック自体の使い方は、先述のブログをご覧ください。

対象リソース

今回はIdentity Centerユーザーのみインポートします。

Identity Center グループや、ユーザーとグループの紐付けなどは対象としていません。が、実際全ての管理をTerraform化したい場合は必要となりますのでご注意ください。

1.importブロックを生成する

現時点ではimportブロックは、for_eachcount などの機能をサポートしていません。 なので、importブロック自体はリソースの数だけ作成する必要があります。

Identity Center ユーザーが多い場合は、手動で全て記述するのは困難であるため、シェルスクリプトでimportブロックを生成してみます。

import_blocks_generator.sh

#!/bin/bash
STORE_ID=$(aws sso-admin list-instances --query "Instances[0].IdentityStoreId" --output text)
USER_NAME_AND_USER_ID=$(aws identitystore list-users --identity-store-id $STORE_ID --query "Users[*].[UserName,UserId]" --output text)

echo "$USER_NAME_AND_USER_ID" | while read -r line; do

  USER_NAME=$(echo $line | awk '{print $1}')
  # USER_NAMEに@が含まれている場合(主にメールアドレス)の場合は、@より前の部分をUSER_NAMEとする
  # いずれの場合でも、USER_NAMEに含まれる記号は_に置換する
  if [[ $USER_NAME == *"@"* ]]; then
    USER_NAME=$(echo $USER_NAME | awk -F'@' '{print $1}' | sed 's/[^_0-9a-zA-Z]/_/g')
  else
    USER_NAME=$(echo $USER_NAME | sed 's/[^_0-9a-zA-Z]/_/g')
  fi

  USER_ID=$(echo $line | awk '{print $2}')

  cat << EOF
import {
  to = aws_identitystore_user.$USER_NAME
  id = "${STORE_ID}/${USER_ID}"
}
EOF
done

補足

シェルスクリプトの補足をします。

1行目にて、IdentityStoreId を取得します。 2行目にて、Identityストアから、Identity Centerユーザーの、 UserNameUserId を取得します。

UserIdはインポート対象リソースの判定のために必要なので、そのまま importブロックの toIdentityStoreId と組み合わせてセットします。

UserNameは、resourceブロックのリソース名に使用します。 UserName は、自分の環境だと、主に2パターン存在しました。

  • いわゆる IAMユーザー名に設定するような一般的な文字列(例: chadain)のパターン
  • メールアドレス(例: chadain@example.com)のパターン

これらどちらでも対応できるように、IF文にて条件分岐を入れています。

条件分岐内容としては、@が含まれるメールアドレスの場合、@より前の部分のみを利用します。 さらに、いずれの場合も記号が含まれる場合は、すべて _ に置換します。 理由としては、利用先であるresourceブロックのリソース名の制約として -_ 以外の記号をサポートしていないためです。

ちなみに、置換は最小限にしておきたいため、アルファベットの大文字・小文字はそのままです。

実際にこのシェルスクリプトを実行すると 、importブロックが出力されます。

% ./import_blocks_generator.sh
import {
  to = aws_identitystore_user.TestAdminUser
  id = "d-9567example/95670080be-586dabeb-d327-4c15-a5a5-example1"
}
import {
  to = aws_identitystore_user.TestReadOnlyUser
  id = "d-9567example/95670080be-5e06c4ae-9465-4c64-a43d-example2"
}
import {
  to = aws_identitystore_user.kurameso_ichiro
  id = "d-9567example/87342ad8-30b1-xxxxxxx-example3"
}
import {
  to = aws_identitystore_user.kurameso_jiro
  id = "d-9567example/95670080be-60380f2a-066c-example4"
}

正常に出力されることが確認できたら、新しい構成ファイルに流し込みます。

% ./import_blocks_generator.sh > generated_imports.tf

2.resourceブロックを自動生成する

次に terraform plan-generate-config-out オプション を使用して、先ほど生成された4つの import ブロックの resource ブロックを生成します。

% terraform plan -generate-config-out=generated_sso_users.tf

上記コマンドをたたくと、以下ファイルが生成されます。これは便利。

generated_sso_users.tf

# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "d-d-9567example/87342ad8-30b1-xxxxxxx-example3"
resource "aws_identitystore_user" "kurameso_ichiro" {
  display_name       = ""
  identity_store_id  = "d-9567example"
  locale             = null
  nickname           = null
  preferred_language = null
  profile_url        = null
  timezone           = null
  title              = null
  user_name          = "kurameso-ichiro@example.com"
  user_type          = null
  addresses {
    country        = null
    formatted      = null
    locality       = null
    postal_code    = null
    primary        = false
    region         = null
    street_address = null
    type           = "work"
  }
  emails {
    primary = true
    type    = "work"
    value   = "kurameso-ichiro@example.com"
  }
  name {
    family_name      = "kurameso"
    formatted        = null
    given_name       = "ichiro"
    honorific_prefix = null
    honorific_suffix = null
    middle_name      = null
  }
}

## 以下省略
## 本来はこのようなリソースブロックがあと3つ生成されます

3.applyしてインポートする

最後は、terraform apply してインポートを完了させます。

% terraform apply -auto-approve
data.aws_ssoadmin_instances.main: Reading...

## 間省略...

Apply complete! Resources: 4 imported, 0 added, 0 changed, 0 destroyed.

これでインポート完了です。

超簡単でしたね?

新機能を活用して既存リソースのTerraformインポート、やっていきましょう!