はじめに
アクセスキー前提の講座に違和感を覚えたので整理しました。
今回は、とあるオンライン講座で教えられていた IAM の権限まわりの扱いに違和感を覚えたので、
自分なりに調べて整理した内容をまとめます。
テーマはざっくり言うと、
・IAMユーザー+アクセスキー前提のやり方って、今のAWSのベストプラクティスと合ってるの?
・よくある『IAMロール=ヘルメット』の例え、厳密にはズレてない?
以下で詳しく解説します。
前提
受講した講座の前提はこんな感じでした。
ローカルのマシンで Terraform を使って AWS リソースを作成する。
そのために「IAMユーザーのアクセスキーを発行して、環境変数に認証情報を登録しましょう」。
つまり、
1. IAMユーザーを作る
2. アクセスキー / シークレットアクセスキーを発行する
3. ローカルのシェルで
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 モードで設定する
aws configure sso
# 対話形式で SSO start URL, SSO region, アカウント、ロールを選ぶ
・Terraform では、その SSO プロファイルを使って
さらに Terraform 専用ロールを AssumeRole する
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 の設定にはこう書いてある:
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用 / 本番用)がしやすい
・長期アクセスキーを前提にせず、一時クレデンシャル+ロール前提で設計する
という現代のベストプラクティスに沿った設計ができます。