Zenn
🎮

【学習メモ】Terraform×AWS SSOで安全にバックエンドを構築する方法と、AWSマルチアカウント運用のベストプラクティス

2025/02/19に公開

1. 背景:Terraform の tfstate を安全に管理したい

AWS でシステムを構築する際、Terraform を使ってコードベースでリソースを管理すると非常に便利です。しかし Terraform には、リソースの状態を記録する tfstate ファイルが必要です。この tfstate は、デフォルトだとローカルに保存されますが、チーム開発やセキュリティ・可用性の観点から、S3 バケットなどリモートの安全な場所に保管することが推奨されます。

多くの場合、terraform { backend "s3" { ... } } のように設定して tfstate を S3 に保存するのですが、そこで必要になるのが S3 へのアクセス権限 です。最小権限の考え方に基づき、「tfstate 置き場の S3 には必要最小限だけのアクセスを許可したい」という要望が生まれます。

さらに最近は、AWS Organizations で複数アカウントを管理し、IAM Identity Center(旧称:AWS SSO) を使って認証・認可を集中管理するケースが増えています。本記事は、「SSO を利用した AWS CLI プロファイルを使いながら、Terraform のバックエンドと実際のリソース作成に必要な権限をどう分けるか?」という疑問と、その解決策をまとめたものです。


2. 試した構成:バックエンド用の IAM ロールを最小権限で作り、SSO プロファイルからアクセスする

当初の構成例は以下のようなイメージでした。

  1. AWS アカウント構成

    • 管理用アカウント (Organizations 管理アカウント)
    • 開発用アカウント
  2. Terraform の backend 設定

    terraform {
      backend "s3" {
        bucket  = "manntera-terraform-backend-root"
        key     = "terraform.tfstate"
        region  = "ap-northeast-1"
        profile = "terraform-backend-root-admin"
      }
    }
    

    ここで profile = "terraform-backend-root-admin" は “tfstate を保存する S3” へのアクセス権限を持つプロファイルとして設定。

  3. IAM ロール
    開発用アカウント内にロール manntera-terraform-backend-root-admin を手動で作成し、下記のように最小限の S3 権限を付与。

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Action": [
                    "s3:GetObject",
                    "s3:PutObject",
                    "s3:DeleteObject",
                    "s3:ListBucket"
                ],
                "Resource": [
                    "arn:aws:s3:::manntera-terraform-backend-root",
                    "arn:aws:s3:::manntera-terraform-backend-root/*"
                ]
            }
        ]
    }
    
  4. AWS CLI のプロファイル設定 (~/.aws/config など)

    [profile terraform-backend-root-admin]
    sso_session = manntera
    sso_account_id = 266735820843
    sso_role_name = manntera-terraform-backend-root-admin
    region = ap-northeast-1
    output = json
    
    [profile test-vpc-full-access]
    sso_session = manntera
    sso_account_id = 266735820843
    sso_role_name = vpc-full-access
    region = ap-northeast-1
    output = json
    
  5. Terraform の実行

    • terraform init を実行したところ、以下のようなエラーが発生
      Error: No valid credential sources found
      ...
      ForbiddenException: No access
      

CLI で aws sts get-caller-identity --profile terraform-backend-root-admin を実行しても「No access」と返ってきます。これはSSO 経由で手動作成したロールを Assume できていない状況でした。


3. なぜ「No access」エラーになるのか?

AWS IAM Identity Center(SSO) を使う場合、アカウント側の IAM ロールを手動で作ってそれを直接 Assume しようとしても、ロールのトラストポリシーが SSO のフェデレーションを受け付けていないなど、SSO とロール間の設定が合わないとアクセスできません。

AWS 公式の推奨方法は、SSO 側(管理アカウント)で “Permission Set” を作成 → 開発用アカウントにアサインするというやり方です。こうすると、AWS が自動的に “AWSReservedSSO_...” という名前のロールを各アカウントに生成し、ユーザーは SSO ログインするだけで、そのロールをスムーズに Assume できます。

3-1. SSO と手動ロール紐付けの難しさ

「手動で作ったロール(例:manntera-terraform-backend-root-admin)を使いたい」という場合は、トラストポリシーを SSO 用に書き換えたり、SSO 側でカスタムロールを設定したりする必要があります。標準 UI ではあまりサポートされておらず、手間が大きいです。
結果として、No access (ForbiddenException) が起こるのは「SSO 側がそのロールを Assume する権利を持っていない」からだと考えられます。


4. 推奨アプローチ:SSO の Permission Set を活用しよう

4-1. Permission Set の作り方

  1. AWS IAM Identity Center (管理アカウント) のコンソールへ移動
  2. Permission Set を作成(例:TerraformBackendMinimal
  3. 必要な最小権限のポリシー(S3: GetObject / PutObject / DeleteObject / ListBucket)などを付与
  4. 開発用アカウントに対して、その Permission Set をアサイン
  5. ユーザーやグループを割り当てる

すると、開発用アカウント側に自動的に AWSReservedSSO_TerraformBackendMinimal_xxxxxx といったロールが作られます。

4-2. CLI プロファイルでの設定

~/.aws/config などで、Permission Set 名を指定して以下のように書きます。

[profile terraform-backend-minimal]
sso_session = manntera
sso_account_id = 266735820843
sso_role_name = TerraformBackendMinimal   # Permission Set 名
region = ap-northeast-1
output = json

これで aws sso login --profile terraform-backend-minimal しておけば、aws sts get-caller-identity --profile terraform-backend-minimal で開発用アカウントのロールを Assume した一時キーが使われます。
Terraform の backend にはこう書けばOKです。

terraform {
  backend "s3" {
    bucket  = "manntera-terraform-backend-root"
    key     = "terraform.tfstate"
    region  = "ap-northeast-1"
    profile = "terraform-backend-minimal"
  }
}

5. 管理アカウントに権限を集約することへの疑問

5-1. 「管理アカウントが肥大化しないか?」

大規模・複数アカウント運用の世界では、AWS が以下のような設計方針を提示しています。

  • IAM Identity Center (SSO) による集中管理

    • 各アカウントに IAM ユーザーをバラバラ作るより、一元的にユーザーや権限を管理したほうがセキュリティリスクを下げ、運用コストを削減できる。
    • 退職・異動・チーム増減があっても、管理アカウントの設定を変更するだけで済む。
  • Control Tower や Organizations を活用

    • 組織全体のガバナンスを管理アカウント(オーガナイゼーション管理)で担い、実際のリソース作成は各アカウントが行う構成がベストプラクティス。
    • 新しい開発用アカウントが必要なときは、Control Tower の “Account Factory” でボタンを押すだけで標準ポリシーやログ集約の設定が自動適用される。

管理アカウントが「全部を肩代わり」しているわけではなく、あくまで認証基盤や課金管理などの横断的領域を集中管理していると考えると分かりやすいです。実際の API コールは「STS 一時トークンを使って、各アカウントのリソースに直接アクセス」します。
結果的に「管理アカウントにいろいろ集まる」形に見えますが、それは ベストプラクティス であり、セキュリティと運用効率を高めるための設計 でもあります。


6. まとめ

  1. Terraform の tfstate を S3 に保存する際、最小権限でアクセスしたい場合は、SSO の Permission Set を使うのが簡単・安全
  2. 手動で作成した IAM ロールを SSO で使おうとすると、トラストポリシーや SAML/OIDC フェデレーションの高度な設定が必要 になり、設定ミスで「No access」となることが多い。
  3. AWS Organizations + IAM Identity Center(SSO) でアカウントをまたいだ管理を一元化するのが、AWS のベストプラクティス
    • 開発用アカウントごとにローカル IAM ユーザーを作るより、安全かつ運用しやすい。
    • Control Tower を使えば新しいアカウントや Permission Set の導入がよりスムーズになる。
  4. 「管理アカウントが肥大化して大変では?」という懸念に対しては、むしろ大規模運用では認証基盤を一元管理するほうがガバナンスを効かせやすいという考え方が主流。

参考リンク


最後に

複数アカウント運用や SSO を導入すると一見複雑に見えますが、大規模になるほど中央管理が便利であり、各アカウントに分散した IAM ユーザーやロールを個別対応するよりリスクや工数が大幅に減るメリットがあります。Terraform でリソースを管理する場合も、バックエンド(tfstate)とリソース作成用プロバイダを分けて認証しながら、SSO の一時トークンを使う形が理想的です。

こうした仕組みを理解しておくと、将来的にアカウントが増えても安全かつ効率的に運用ができるはずです。ぜひ活用してみてください。

Discussion

ログインするとコメントできます