🐕

よくある「IAMロール=ヘルメット」の例えは微妙だった話

に公開

はじめに

アクセスキー前提の講座に違和感を覚えたので整理しました。

今回は、とあるオンライン講座で教えられていた IAM の権限まわりの扱いに違和感を覚えたので、
自分なりに調べて整理した内容をまとめます。

テーマはざっくり言うと、

・IAMユーザー+アクセスキー前提のやり方って、今のAWSのベストプラクティスと合ってるの?

・よくある『IAMロール=ヘルメット』の例え、厳密にはズレてない?

以下で詳しく解説します。

前提

受講した講座の前提はこんな感じでした。

ローカルのマシンで Terraform を使って AWS リソースを作成する。
そのために「IAMユーザーのアクセスキーを発行して、環境変数に認証情報を登録しましょう」。

つまり、
1. IAMユーザーを作る
2. アクセスキー / シークレットアクセスキーを発行する
3. ローカルのシェルで

bash
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...

4. Terraform はこの環境変数からアクセスキーを読み取り、その権限の範囲内でリソース操作を行う

という流れです。

一見「まあ、そういうものかな」と思いがちですが、
今のベストプラクティスから見ると、かなり大きなセキュリティ的な問題を含んでいます。

アクセスキー方式のどこが危ないのか

1. アクセスキーは基本「無期限」

IAMユーザーのアクセスキーは 削除・ローテーションするまで有効 です。
つまり、基本的に有効期限がありません。

・一度流出したら、そのキーを消すまで攻撃者がずっと使える

・ローテーション(作り直し)も手作業になりがちで、「面倒だから放置」が起きやすい

一方、今のAWSが推している考え方は

・一時クレデンシャル(セッション)で短時間だけ使う

・期限が切れたら STS / SSO 経由で取り直す

というものです。

なので、「長生きする固定キー」を前提にする時点で、その鍵そのものがリスクになりやすい構成になっています。

2. キーが漏れやすい(人間の運用で事故る)

アクセスキーを 環境変数で持つ やり方には、実は落とし穴がいっぱいあります。

・.zshrc / .bashrc / .profile に書いて Git にコミットしてしまう

・.env ファイルに書いて、そのままリポジトリに上げてしまう

・env / printenv の出力をログやQiita記事にコピペしてしまう

・シェルの履歴に export AWS_SECRET_ACCESS_KEY=... が残る

・スクリーン共有中にターミナルをそのまま見せてしまう

・一度 GitHub に上がると、GitHub の Secret Scanning より先に攻撃者のスクレイパーに拾われる

「環境変数だから安全」というわけではなく、人間のちょっとした運用ミスで普通に漏れます。

じゃあ、今のベストプラクティスは何?

ざっくりまとめると、AWSが公式ドキュメントなどで言っているのはこういう方針です:

・人間ユーザー・ワークロードともに
→ IAMロール+一時クレデンシャルでアクセスする

・組織的に管理するなら
→ IAM Identity Center(旧SSO)でアカウントと権限を一元管理する

・IAMユーザーは
→ ルート・レガシー・どうしてもロールにできない特殊ケースだけに限る(それ以外は Identity Center や外部IdP+ロールを使う)

ローカルから Terraform を叩くときの「今っぽい構成」

典型的なパターンはこんな感じ:

・人間は Identity Center(SSO)+ロール

・IAM Identity Center でユーザー & Permission Set(開発者ロール)を作る

・ローカルで AWS CLI を SSO モードで設定する

bash
aws configure sso
# 対話形式で SSO start URL, SSO region, アカウント、ロールを選ぶ

・Terraform では、その SSO プロファイルを使って
さらに Terraform 専用ロールを AssumeRole する

hcl
provider "aws" {
  region  = "ap-northeast-1"
  profile = "dev-sso"  # aws configure sso で作ったプロファイル名

  assume_role {
    role_arn     = "arn:aws:iam::123456789012:role/TerraformRole"
    session_name = "terraform-session"
  }
}

こうしておけば、

・ローカルには 長期アクセスキーを保存しない

・人間は Identity Center ログイン時に認証+MFA

・Terraform は TerraformRole に定義した最小限の権限でだけ動く

という構成にできます。

ここから本題:「IAMロール=ヘルメット」比喩の違和感

「ロールとかポリシーとか色々わからん!なんかいい例えないのか?」

と思って調べてみると
よくある説明で、IAMロールはこう例えられます。

ロール = ヘルメット
ポリシー = ヘルメットに貼ってあるバッジ
ユーザー = そのヘルメットをかぶる人

この比喩で IAM を説明する記事がいっぱい出てきました。
雰囲気を掴むには悪くないんですが、微妙に誤解を生みやすいと感じています。

なぜかというと、この例えだと:

・「ヘルメット(ロール)を誰かに貸している」

・「ロールの持ち主が移動している」

ようなイメージになりがちだからです。

ロールとポリシーの関係を理解するには便利なのですが、実際の IAM の世界では、

・ロールは誰かの「所有物」ではなく、できること(許可ポリシー)をまとめた定義

・誰かがロールを「借りたり返したり」しているわけでもない

・そのロールとして振る舞う『一時的な状態(セッション)』 が発行されるだけ

という構造になっています。

ここが 「ヘルメット=ロール」だけの例えだと抜け落ちてしまうポイントです。


正しいイメージ:Principal / Role / Session の3つ

自分の中でしっくり来た整理は、次の3つに分けて考えることでした。

1. Principal(プリンシパル)
→ AWS に対して「私はこれです」と名乗っている実体

例:
・Identity Center 経由でログインした人間

・GitHub Actions のジョブ

・EC2 / ECS / Lambda などのAWSリソース

2. Role(ロール)
→ 「どういう権限で振る舞うか」の役割テンプレ

・DeveloperRole

・TerraformRole

・GitHubActionsRole

など。

ロール自体には期限はなく、削除しない限り存在し続けます。

3. Session(セッション)=一時パスポート
→ Principal が「特定の Role として振る舞うための、一時的なクレデンシャル」

・STS AssumeRole や SSO ログインの結果として発行される

・AccessKeyId / SecretAccessKey / SessionToken / 有効期限 がセット

・時間が来たら失効するので、また取り直し必要

この3つで見ると、

「ロールを貸し借りしている」のではなく、

「プリンシパルが、そのロールとして振る舞う“セッション”を持っている」

という状態であることが分かります。

入国管理官の例えで整理してみる

ここで、さっきの話を「入国管理」のストーリーとして並べ替えてみます。

登場人物

・🧑 太郎:ローカルで Terraform を叩くエンジニア(Principal)

・🤖 Terraform ロボ:太郎の指示通りに AWS リソースを作るツール(Principalではない)

・🏢 ロールたち:

・DeveloperRole:開発者用のロール

・TerraformRole:インフラ構築専用のロール

・🛂 AWS STS 入国管理官さん:AssumeRole を審査して一時パスポートを発行するサービス

・🎫 セッション:ロールとして振る舞うための一時パスポート

ストーリー
1. 太郎が aws sso login でログインする
→ Identity Center から STS 入国管理官さんに依頼が行く
→ 「この人を DeveloperRole として AWS に入れてください」
→ 入国管理官さんが DeveloperRole セッション(一時パスポート)を発行

この時点での Principal は:
「DeveloperRole のセッションを持った太郎」

2. 太郎が terraform apply を実行する
Terraform の設定にはこう書いてある:

hcl
provider "aws" {
  region  = "ap-northeast-1"
  profile = "dev-sso"

  assume_role {
    role_arn     = "arn:aws:iam::123456789012:role/TerraformRole"
    session_name = "terraform-session"
  }
}

Terraform ロボ:
「今ぼくは DeveloperRole の一時パスポートを使ってる。
でも設定を見ると『TerraformRole として作業しろ』と書いてある。
じゃあ入国管理官さんに、TerraformRole のパスポートをお願いしよう。」

3. Terraform ロボが AssumeRole(TerraformRole) を実行する
入国管理官さんが2つチェックする:

・DeveloperRole に「TerraformRole を Assume してよい」権限があるか

・TerraformRole の trust policy に「DeveloperRole からの AssumeRole を許可する」と書いてあるか

両方OKなら、入国管理官さん:
「はい、TerraformRole として振る舞える一時パスポートを発行します。」

ここで TerraformRole セッション が発行されます。

4. Terraform ロボは以降、TerraformRole セッションで AWS にアクセスする
→ VPC/ECS などの作成・更新は TerraformRole のポリシーの範囲内だけ で実行される。

ここでポイントなのは:
・ロールそのもの(DeveloperRole / TerraformRole)はできることを定義した 「役職テンプレ」 でしかない

・誰かに「貸されて」移動するわけではない

・実際に動いているのは
「特定のロールとして振る舞うセッションを持った Principal」

ということです。


ここまでを踏まえて、ヘルメット比喩を少しだけ修正すると、かなりしっくり来ます。
・ロール = 会社ので決められている 「役職ヘルメットをかぶっている人の役割」

・現場作業員ヘルメット

・現場監督ヘルメット

・管理者ヘルメット

・Principal = それをかぶる可能性のある人・ジョブ・リソース

・セッション =
「誰かがそのヘルメットをかぶって、決められた時間だけ働いている状態」
ヘルメットを取ったら仕事はできない

つまり、
・❌ ロール(ヘルメット)を貸す / 持ち主が変わる

・✅ Principal が、一定時間だけそのロールをかぶって振る舞う(セッションを持つ)

というのが、IAMの実際のモデルに近いイメージです。

まとめ:講座の構成を「今風の話」にアップデートするなら

オンライン講座が教えていたのは:

IAMユーザーを作って、アクセスキーを環境変数に入れて、Terraform から直接使う

という「昔ながらの」やり方でした。

それを、今のAWSの考え方・IAMのモデルに合わせて言い換えると、
こんな風にアップデートできます。

・人間は Identity Center でログインし、DeveloperRole のセッション をもらう

・Terraform はそのセッションを使って、TerraformRole を AssumeRole する

・実際に動いているのは 「ロールを振る舞うことのできるセッションを持った Principal」

・長期アクセスキーを前提にせず、一時クレデンシャル+ロール前提で設計する

こうしておくと、

・セキュリティ的にも安心(キーが長生きしない)

・権限分離(人間用 / Terraform用 / 本番用)がしやすい

・長期アクセスキーを前提にせず、一時クレデンシャル+ロール前提で設計する

という現代のベストプラクティスに沿った設計ができます。

Discussion