EC2 はパスワードを一度も入力していないのに、なぜ S3 にアクセスできるのか?
EC2 や Lambda に「IAM ロール」をアタッチして S3 や DynamoDB を叩くコードを書いたことがあるはずだ。アクセスキーもシークレットキーも一度もコードに書いていないのに、なぜそれで認証が通るのか説明できるだろうか。答えは「鍵を渡していない」からで、渡しているのはもっと別のものだ。
- IAM ロールは「誰が借りられるか」を決める信頼ポリシーと「借りた後に何ができるか」を決める許可ポリシーの二階建てで、固定のパスワードの代わりに期限付きの一時クレデンシャルを発行する仕組みだ。
AssumeRoleが発行する一時クレデンシャルは既定で 1 時間、ロール側の設定次第で最大 12 時間しか有効でないため、EC2 上では AWS SDK が失効前に自動で取得し直しており、人がキーを管理する場面自体が消える。- ロールをインスタンスから外しても最大 1 時間反映が遅れることがあるなど、「すぐ切り替わる」という直感が外れる挙動が公式ドキュメントに明記されている。
長期のアクセスキーは何に困るのか
IAM ユーザーに発行するアクセスキーは、失効させない限りずっと有効な「長期クレデンシャル」だ。アプリケーションのコードや環境変数に埋め込んで使うが、そのキーをどう安全に配布するか、漏えいしたときにどう検知して失効させるか、定期的にどうローテーションするかは、すべて運用側が自分で設計しなければならない。EC2 や Lambda のように AWS が勝手に増減させるリソースの一つひとつに、このキーを配って回るのは現実的ではない。
IAM ロールはこの配布問題そのものを消す発想で作られている。ロールには固定のパスワードが最初から存在せず、必要になった瞬間に AWS STS(Security Token Service、一時クレデンシャルを発行する AWS のサービス)へ「このロールを借りたい」と申請して、有効期限付きの鍵を都度受け取る。
ロールは二階建て — 信頼ポリシーと許可ポリシー
IAM ロールを作ると、性質の異なる 2 つのポリシーが同時にできる。信頼ポリシー(trust policy)は「誰がこのロールを借りてよいか」を決め、許可ポリシー(permissions policy)は「借りた後に何ができるか」を決める。この 2 つが両方そろって初めてロールは機能する。信頼ポリシーだけ通っても、許可ポリシーが S3 への権限を含んでいなければ S3 は触れない。
一見、ロールを付ければアクセスキーの管理からまるごと解放されるように思える。しかし実際に免除されているのはキーの配布と保管だけで、「誰にどこまで貸すか」を設計する責任はそのまま残る。ロールを借りる操作は STS の AssumeRole という API 呼び出しで、呼び出し元は借りたいロールの ARN(RoleArn)とセッション名(RoleSessionName)を指定する。有効期間は DurationSeconds で指定でき、省略すると既定で 3600 秒(1 時間)になる。指定できる上限はロール側に設定された「最大セッション時間」で決まり、これも既定は 1 時間だが管理者が 1〜12 時間の範囲で伸ばせる。短く設定すれば漏えい時の被害時間は短くなるが、その分アプリケーション側は頻繁にクレデンシャルを取り直す必要が出てくる。
長期のアクセスキーは「合鍵を作って渡す」ことに近い。合鍵は複製もできるし、返してもらわない限りいつまでも開く。IAM ロールはホテルのカードキーに近い。フロント(STS)は宿泊者名簿(信頼ポリシー)に載っている相手にだけカードキー(一時クレデンシャル)を発行し、そのカードで開けられる部屋は許可ポリシーであらかじめ決まっており、チェックアウト時刻を過ぎれば回収しなくても自動的にただの磁気片になる。
EC2 の中で誰もキーを打っていない理由
EC2 にロールをアタッチすると、そのロールは「インスタンスプロファイル」というコンテナ経由でインスタンスに結び付く。起動したインスタンスの内部からは、リンクローカルアドレス 169.254.169.254 にある IMDS(Instance Metadata Service)に問い合わせるだけで、そのロールの一時クレデンシャルを取得できる。
EC2 に IAM ロールをアタッチ
│
▼ IMDS に自動アクセス
.../iam/security-credentials/{role}
│
▼ 一時クレデンシャルを返す
AccessKeyId / SecretAccessKey /
SessionToken (既定1h・最大12h)
│
▼ 失効5分前に自動更新
SDK / CLI がそのまま署名に使う
現行の IMDSv2 では、まず PUT /latest/api/token でトークンを取得し、そのトークンをヘッダーに付けて GET /latest/meta-data/iam/security-credentials/{role-name} を叩く 2 段階になっている(素通しの GET だけで取れる IMDSv1 はサーバー側の SSRF 脆弱性に弱いため、この一手間が防御として挟まっている)。AWS はこの一時クレデンシャルを自動でローテーションし、古いクレデンシャルが失効する少なくとも 5 分前には新しいものを用意すると公式ドキュメントで明言している。AWS SDK や CLI はこの取得と更新を内部で肩代わりしているため、アプリケーションのコードは一度もキーを意識しない。ただし EC2 にアタッチしたロール自体のセッションは、ロールに設定した最大セッション時間の制限を受けない特別扱いになっている点は覚えておいてよい。
権限の切り替えは「即座」とは限らない
ロールの許可ポリシーを書き換えれば、通常は新しいクレデンシャルを取得した瞬間から新しい権限が効く。しかし「インスタンスプロファイルからロールを外す」という操作は挙動が違い、AWS の公式ドキュメントは反映まで最大 1 時間の遅延が起こりうると明記している。緊急でロールの権限を止めたいときに、この操作だけで即座に遮断できると思い込むと痛い目を見る。止めるべきは許可ポリシー側を空にするか、ロール自体を削除する方が確実だ。
もう一つ、AssumeRole にはセッションポリシーというオプションの JSON ポリシーを追加で渡せる仕組みがある。渡した場合、実際に有効になる権限はロール本来の許可ポリシーとセッションポリシーの積集合になり、セッションポリシー側でロール本来の権限を超えて権限を広げることはできない。借りるたびにさらに絞り込むことはできても、借りた側が権限を盛ることはできない設計だ。
EC2 のインスタンスプロファイル、Lambda の実行ロール、ECS のタスクロールはいずれも同じ「一時クレデンシャルを自動で借りる」仕組みの上に乗っている。GitHub Actions から AWS リソースを操作するときも、長期のアクセスキーを secrets に置く代わりに OIDC 連携でその場限りのロールセッションを借りる構成が広く使われており、根っこの仕組みは今日の内容と同じだ。
AWS CLI がすでに設定されていれば、いま使っている認証情報が長期の IAM ユーザーなのか一時的なロールセッションなのかをその場で確認できる。
# 1. いま使っている認証情報の正体を確認する aws sts get-caller-identity # 2. 自分に AssumeRole 権限のあるロールがあれば、その場で一時クレデンシャルを発行してみる aws sts assume-role \ --role-arn arn:aws:iam::<account-id>:role/<role-name> \ --role-session-name manual-test
get-caller-identity の Arn が arn:aws:iam::...:user/... なら長期の IAM ユーザー、arn:aws:sts::...:assumed-role/... ならすでに一時クレデンシャルで動いている。assume-role の出力にある Credentials は呼び出し元とは別の AccessKeyId・SecretAccessKey・SessionToken を持ち、Expiration は既定では実行時刻のちょうど 1 時間後になっているはずだ。
- ロールをアタッチすれば何でも権限が使える — ロールが機能するには「誰が借りられるか」を決める信頼ポリシーと「何ができるか」を決める許可ポリシーの両方が必要で、後者が空なら何も操作できない。
- ロールの一時クレデンシャルはロールである限り失効しない — 実際には既定 1 時間、最長でもロール設定の範囲(最大 12 時間)で失効する。SDK が裏で自動的に取り直しているから気づかないだけだ。
- インスタンスからロールを外せば権限は即座に消える — インスタンスプロファイルからロールを外す変更は、反映まで最大 1 時間の遅延がありうると AWS の公式ドキュメントに明記されている。
- IAM ロール
- 固定パスワードを持たず、借用の都度 STS が一時クレデンシャルを発行する AWS の権限単位。
- 信頼ポリシー(trust policy)
- そのロールを誰(どのアカウント・サービス)が借りられるかを定めるポリシー。
- 許可ポリシー(permissions policy)
- 借りたロールで実際に何ができるかを定めるポリシー。
- AssumeRole
- STS に対してロールを借り、一時クレデンシャルの発行を要求する API 操作。
- STS(Security Token Service)
- 一時セキュリティ認証情報を発行する AWS のサービス。
- IMDS(Instance Metadata Service)
- EC2 インスタンス内部から
169.254.169.254経由でロールの一時クレデンシャルなどを取得できるサービス。
- Temporary security credentials in IAM | AWS 公式ドキュメント — 一時クレデンシャルが長期クレデンシャルと何が違うか、ロールとの関係を整理した一次情報。
- AssumeRole | AWS STS API Reference — 信頼ポリシーと許可ポリシーの役割分担、DurationSeconds の既定値・上限の一次情報。
- Retrieve security credentials from instance metadata | Amazon EC2 User Guide — IMDSv2 での取得手順と、失効5分前の自動ローテーションについての一次情報。