開発環境と本番環境でAWSアカウントを分けたはいいものの、「どうやってアカウントをまたいでリソースにアクセスするのか」で詰まったことはないでしょうか。CI/CDパイプラインが本番アカウントのS3にデプロイできない、セキュリティ監査チームが全アカウントのCloudTrailログを一箇所で見たい——そういった状況です。
オンプレミスの現場では、各サーバーにSSH鍵やサービスアカウントのパスワードを配置するのが当たり前でした。クラウドに移行した際にその発想のまま「各アカウントにIAMユーザーを作ってアクセスキーを発行」という運用に落ち着きがちですが、これは管理コスト・漏洩リスクともに最悪です。
AWSにはSTS(Security Token Service)のAssumeRoleという仕組みがあります。これを使えば、長期的なアクセスキーを一切使わずに、別アカウントのリソースへ安全にアクセスできます。本記事では、クロスアカウントアクセスの基本原理から、IAMロールの設定手順、実務での設計パターンまで解説します。

なぜクロスアカウントアクセスが必要なのか
マルチアカウント構成が標準になった背景
AWSの設計ベストプラクティスでは、環境(開発・ステージング・本番)やチーム、システムごとにAWSアカウントを分割することが推奨されています。AWS OrganizationsやControl Towerで複数アカウントを統制するアプローチは、大規模なクラウド利用ではもはや標準です。
アカウントを分割するメリットは明確です。
・爆発半径(Blast Radius)の限定: あるアカウントで誤操作やセキュリティ事故が起きても、他アカウントへの影響を遮断できる
・コスト可視化: アカウント単位で請求が分かれるため、どのシステムにいくらかかっているかが明確になる
・権限管理の明確化: アカウント境界がセキュリティ境界になるため、「誰がどのシステムにアクセスできるか」が整理しやすい
一方で、アカウントを分割すると「アカウント間でどうリソースをやり取りするか」という問題が生まれます。開発アカウントのCI/CDパイプラインが本番アカウントにデプロイしたい、ログ収集用の中央アカウントが各アカウントのCloudTrailログを集約したい——そういったシナリオです。
長期アクセスキー方式の問題点
「各アカウントにIAMユーザーを作り、アクセスキーを発行してCI/CDツールに設定する」方法は一見シンプルですが、次の問題があります。
・アクセスキーの漏洩リスク: GitHubのコードに誤ってコミットされた事例は枚挙にいとまがない
・ローテーション負荷: アクセスキーは定期的にローテーションが必要だが、複数アカウントにまたがると管理が複雑になる
・長期有効な認証情報: 万が一漏洩した場合、無効化するまでの間は悪用し続けられる
AWSはこの問題を解決するためにSTS(Security Token Service)を提供しています。
AWS STSとAssumeRoleの仕組み
STSとは何か
AWS STS(Security Token Service)は、一時的なセキュリティ認証情報を発行するサービスです。発行される認証情報(アクセスキーID+シークレットアクセスキー+セッショントークン)には有効期限があり、失効したら自動的に使えなくなります。
STS自体はリージョンに依存しないグローバルサービスで、API呼び出しに対する追加料金は発生しません(2026年8月時点)。
AssumeRoleの流れ
クロスアカウントアクセスでは `sts:AssumeRole` というAPIが中心になります。
| ステップ | 操作 | 説明 |
|---|---|---|
| ① 信頼関係の設定 | ターゲットアカウントでIAMロールを作成 | 「Aアカウントからの引き受けを許可する」という信頼ポリシーを設定 |
| ② AssumeRole呼び出し | ソースアカウントのエンティティがSTS APIを呼び出す | ターゲットアカウントのロールARNを指定してSTSに一時的な認証情報を要求 |
| ③ 一時認証情報の取得 | STSが認証情報を返す | 有効期限付きのアクセスキー・シークレット・トークンを受け取る |
| ④ ターゲットアカウントで操作 | 取得した認証情報を使ってAPIを呼び出す | ロールに付与された権限の範囲内でターゲットアカウントのリソースを操作できる |
ここで重要なのは、ソースアカウント側とターゲットアカウント側の両方で設定が必要という点です。これを片方だけ設定して「なぜ動かないのか」と悩むケースが現場では非常に多いです。
クロスアカウントIAMロールの設定手順
1. ターゲットアカウントでIAMロールを作成する
まず、アクセスされる側(ターゲットアカウント)でIAMロールを作成します。マネジメントコンソールの場合は、IAMサービス → ロール → ロールを作成 → 「AWSアカウント」を選択し、ソースアカウントのIDを入力します。
CLIで設定する場合は、信頼ポリシーをJSONで用意します。
# trust-policy.json(ターゲットアカウント側の信頼ポリシー) { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:role/CIDeployRole" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "your-unique-external-id" } } } ] }
`123456789012` はソースアカウントIDに置き換えます。`ExternalId` はサードパーティツールがロールを引き受ける際のなりすまし攻撃(Confused Deputy問題)を防ぐためのオプション条件で、社外ベンダーへのロール委任時は設定必須です。
# AWS CLI(ターゲットアカウントの認証情報で実行) aws iam create-role \ --role-name CrossAccountDeployRole \ --assume-role-policy-document file://trust-policy.json # 許可ポリシーをアタッチ(必要な権限のみを最小限に) aws iam put-role-policy \ --role-name CrossAccountDeployRole \ --policy-name S3DeployBucketAccess \ --policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["s3:PutObject","s3:GetObject"], "Resource": "arn:aws:s3:::prod-deploy-bucket/*" }] }'
2. ソースアカウントでAssumeRoleの許可を付与する
次に、ソースアカウントのIAMエンティティ(ユーザー・ロール)に対して、ターゲットアカウントのロールを引き受ける権限を付与します。
# ソースアカウントのIAMポリシー(CI/CDサービスロールにアタッチ) { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::987654321098:role/CrossAccountDeployRole" } ] }
`987654321098` はターゲットアカウントIDに置き換えます。
3. AssumeRoleを実行して一時認証情報を取得する
設定が完了したら、ソースアカウントから実際にAssumeRoleを実行します。
# AWS CLI: AssumeRoleで一時認証情報を取得 aws sts assume-role \ --role-arn "arn:aws:iam::987654321098:role/CrossAccountDeployRole" \ --role-session-name "deploy-session-$(date +%Y%m%d%H%M%S)" # レスポンス例 # { # "Credentials": { # "AccessKeyId": "ASIA...", # "SecretAccessKey": "...", # "SessionToken": "...", # "Expiration": "2026-08-10T10:00:00Z" ← 有効期限あり # } # } # 取得した認証情報を環境変数にセット export AWS_ACCESS_KEY_ID="ASIA..." export AWS_SECRET_ACCESS_KEY="..." export AWS_SESSION_TOKEN="..." # これ以降のAWS CLIコマンドはターゲットアカウントのロール権限で動作する aws s3 cp ./artifact.zip s3://prod-deploy-bucket/
`AWS_SESSION_TOKEN` を渡し忘れると認証が失敗します。アクセスキーとシークレットだけでなく、セッショントークンも必ずセットしてください。これは現場でよく起きるミスです。
リソースポリシーによるクロスアカウントアクセス
IAMロールのAssumeRole以外にも、リソースポリシーを使ってクロスアカウントアクセスを直接制御する方法があります。S3バケットポリシー、KMSキーポリシー、SQSポリシーなどがその代表例です。
IAMポリシーとリソースポリシーの評価ロジック
クロスアカウントでリソースにアクセスする際、AWSは両方をチェックします。
| チェック箇所 | 何をチェックするか | どちらのアカウントの設定か |
|---|---|---|
| IDベースのポリシー | アクセスする側のIAMエンティティに権限があるか | ソースアカウント |
| リソースベースのポリシー | アクセスされる側のリソースが許可しているか | ターゲットアカウント |
同一アカウント内の場合は、IDベースのポリシーかリソースポリシーどちらかが「Allow」であればアクセスできます。しかしクロスアカウントの場合は、両方がAllowでなければアクセスできません。
「IAMポリシーで許可しているのになぜかS3にアクセスできない」というトラブルの大半は、このクロスアカウント評価ロジックを理解していないことが原因です。
S3バケットポリシーでのクロスアカウント設定例
# S3バケットポリシー(ターゲットアカウントのバケットに設定) { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:role/CIDeployRole" }, "Action": ["s3:PutObject","s3:GetObject"], "Resource": "arn:aws:s3:::prod-deploy-bucket/*" } ] }
このバケットポリシーと、ソースアカウントのIAMロールの両方でS3操作を許可することで、クロスアカウントアクセスが成立します。
実務でよく使う設計パターン
パターン1: CI/CDパイプラインからの本番デプロイ
開発アカウントのCI/CDツール(CodePipeline、GitHub Actionsなど)が、本番アカウントにアプリをデプロイするパターンです。
・ソースアカウント: CI/CDサービスロールにAssumeRoleの許可を付与
・ターゲットアカウント: デプロイ用ロール(本番S3/ECSへの書き込み権限)を作成し、信頼ポリシーでCI/CDロールからの引き受けを許可
・ポイント: 本番アカウントにはアクセスキーを一切持ち込まない。一時的なセッションで操作し、失効後は自動的に使えなくなるため、漏洩リスクを大幅に下げられる
パターン2: セキュリティ監査アカウントによるログ集約
複数アカウントのCloudTrailログやConfig記録を、専用のセキュリティ監査アカウントのS3に集約するパターンです。大規模なマルチアカウント環境では必須の構成です。
・各アカウント: CloudTrail/Configのログ送信先として監査アカウントのS3バケットARNを指定
・監査アカウント: S3バケットポリシーで各アカウントからのPutObjectを許可
・ポイント: ログを各アカウントに分散させると、インシデント発生時に攻撃者に改ざん・削除されるリスクがある。一元集約により証拠保全を強化できる
パターン3: 共有サービスアカウントの活用
Route 53(DNS)、共通のECRリポジトリ、共有KMSキーなど、複数アカウントで横断利用するリソースを「共有サービスアカウント」に集約するパターンです。
・各アカウント: 共有サービスアカウントのロールをAssumeRoleして共有リソースにアクセス
・共有サービスアカウント: KMSキーポリシー・ECRリポジトリポリシーなどで各アカウントからのアクセスを許可
・ポイント: AWS RAM(Resource Access Manager)と組み合わせると、サブネットやAWS License Managerライセンスなどのリソースもアカウント間で共有できる
【重要】設計時のセキュリティポイント
セッション時間は用途に合わせて最小限に
デフォルトのセッション有効期限は1時間(3,600秒)です。CI/CDのデプロイなら15分(900秒)、インタラクティブな作業でも1時間程度が目安です。最長12時間まで設定できますが、長くすればするほど漏洩した場合のリスクが上がります。
# セッション時間を900秒(15分)に短縮してAssumeRole aws sts assume-role \ --role-arn "arn:aws:iam::987654321098:role/CrossAccountDeployRole" \ --role-session-name "deploy-session" \ --duration-seconds 900
Principalはできる限り絞る
信頼ポリシーのPrincipalに `”AWS”: “arn:aws:iam::123456789012:root”` と書くと、そのアカウント内の全エンティティからの引き受けを許可してしまいます。特定のロールに限定する場合は `arn:aws:iam::123456789012:role/SpecificRole` のようにロールARNで指定しましょう。
IAM Access Analyzerで設定ミスを検出する
意図せず外部アカウントに公開されているリソースポリシーを検出するには、AWS IAM Access Analyzerが有効です。設定後は「外部アクセス」の検出結果を定期的に確認する習慣を持ちましょう。
Permission Boundariesでロール作成権限を委任する
マルチアカウント環境では、各チームに「自分たちのロールは自分たちで作らせたい」というニーズが出てきます。しかし無制限にIAMロール作成を許可すると権限昇格のリスクがあります。AWS IAM Permission Boundariesを使えば、委任できる権限の上限を設定したうえでロール作成権限を安全に委任できます。
よくあるトラブルと対処法
① AssumeRoleは成功するが操作がAccessDeniedになる
クロスアカウントではIDベースポリシーとリソースポリシーの両方が必要です。AssumeRoleは成功しても、ターゲットリソース(S3バケット等)のリソースポリシーで許可されていなければDeniedになります。まずリソースポリシーの有無と内容を確認してください。
② 信頼ポリシーのARNが見つからないとエラーが出る
信頼ポリシーのPrincipalに指定したARNが存在しない場合、ロール作成時にエラーになります。ソースアカウントのロールが先に作成されている必要があります。一般的にはソースアカウントのロールを先に作成してからターゲットの信頼ポリシーにそのARNを設定します。
③ セッショントークンを渡し忘れる
一時認証情報を使う際、`AWS_SESSION_TOKEN` 環境変数(またはSDKの `session_token` パラメータ)を渡し忘れると認証が失敗します。アクセスキーとシークレットだけでなく、セッショントークンも必ずセットしてください。
④ MFA必須の信頼ポリシーで自動化が止まる
セキュリティ強化のため信頼ポリシーに `”Condition”: {“Bool”: {“aws:MultiFactorAuthPresent”: “true”}}` を設定しているケースがあります。CI/CDなどの自動化処理とは相性が悪いため、機械的なAssumeRoleにはMFA条件を付けないようにし、代わりにIPアドレス条件やソースロールのARN絞り込みで保護するのが現場での定石です。

本記事のまとめ
AWSクロスアカウントアクセスの要点をまとめます。
| 項目 | 内容 |
|---|---|
| 基本方式 | STS AssumeRole + IAMロール(長期アクセスキーは廃止する) |
| 設定が必要な箇所 | ①ターゲットアカウントの信頼ポリシー ②ソースアカウントのAssumeRole許可 |
| クロスアカウントのアクセス判定 | IDベースポリシー AND リソースポリシーの両方がAllow必要 |
| セキュリティ強化のポイント | ExternalId設定・最小セッション時間・Principalの絞り込み |
| 主な実務パターン | CI/CDデプロイ・ログ集約・共有サービスアカウント |
マルチアカウント設計全体についてはAWS開発・ステージング・本番の環境分離設計も合わせてご覧ください。アカウント分割の統制についてはAWS Organizations入門とAWS Control Tower入門が参考になります。
PR
AWSではじめるクラウドセキュリティ(松本照吾ほか/日経BP)
IAM・VPC・暗号化など、AWSセキュリティの実務設計を体系的に学べる一冊。クロスアカウント設計やOrganizations連携を実装する前に読んでおくと、設計判断の根拠が格段に固まります。
