iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0
IT Operation

AWS 架構為什麼這樣選?30 天拆解服務選型與設計取捨系列 第 9 篇

Day 9|跨帳號存取實作:用 Bucket Policy、AssumeRole 讀取 S3(下)

  • 分享至 

  • xImage
  •  

上一篇透過 IAM Policy 與 Bucket Policy,讓 Account A 的 OrderApiRole 直接讀取 Account B 的 S3 Bucket,並測試了 SSE-S3 與 SSE-KMS 加密物件的存取差異。

今天改用第二種跨帳號存取方式:讓 Account A 的 OrderApiRole 先透過 STS AssumeRole,取得 Account B 的 ProductDataReadRole 暫時性憑證,再使用這個身分讀取相同的 S3 Bucket。

這次會沿用前兩篇建立的 S3 Bucket 與 EC2,主要調整 IAM Role 與 Policy,最後透過 AWS CLI,觀察 AssumeRole 前後的身分及存取結果有什麼不同。

準備實作環境

本篇沿用前兩篇的測試環境:

項目 Account A:存取方 Account B:資源擁有方
Account ID 111122223333 444455556666
來源 Role OrderApiRole —
目標 Role — ProductDataReadRole
S3 Bucket — shared-product-data-prod
EC2 order-api-cross-account-test —
Region ap-northeast-1 ap-northeast-1

帳號 ID 與 Bucket 名稱都是範例,實作時需要換成自己的值。


移除上一篇的直接跨帳號授權

上一篇已經透過兩側的 IAM Policy 與 Bucket Policy,讓 OrderApiRole 可以直接存取 Account B 的 S3。

但這次要測試的是 AssumeRole,因此先移除上一篇的直接存取權限,避免兩種授權方式互相影響。

在 Account A 移除 S3 IAM Policy

登入 Account A,進入 IAM → Roles → OrderApiRole → Permissions。

找到上一篇建立的 Inline policy,將這份 Policy 刪除。

請保留 AmazonSSMManagedInstanceCore,因為目前仍然需要透過 Session Manager 連線至 EC2。

如果上一篇有加入授予來源 Role 的跨帳號 KMS 解密政策,也可以先移除這份 Policy,後續再由 Account B 的目標 Role 取得所需的 KMS 權限。

在 Account B 移除 Bucket Policy

接著登入 Account B,進入 S3 → General purpose buckets → shared-product-data-prod → Permissions → Bucket policy → Edit。

移除上一篇新增的兩個 Statement:

  • AllowOrderApiRoleListBucket
  • AllowOrderApiRoleReadObjects

如果 Bucket Policy 只有這兩個 Statement,可以刪除整份 Policy;如果還有其他授權設定,請保留原有內容。

本次使用 Account B 自己的 IAM Role 存取同帳號的 Bucket,在沒有其他政策限制的情況下,可以透過 Role 的 IAM Policy 授權,不需要額外在 Bucket Policy 中授權 Account A 的 OrderApiRole。

驗證目前無法直接存取 S3

回到 Account A,透過 Session Manager 連線至 EC2:

EC2 → Instances → 選擇 order-api-cross-account-test → Connect → Session Manager → Connect

執行:

aws sts get-caller-identity

確認目前使用的仍然是:

arn:aws:sts::111122223333:assumed-role/OrderApiRole/i-0123456789abcdef0

接著嘗試列出 Account B 的 S3 Bucket:

aws s3 ls s3://shared-product-data-prod/

在沒有其他政策額外授權的情況下,預期會收到:

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

https://ithelp.ithome.com.tw/upload/images/20260923/20183052Tia0I61RfF.png

確認直接存取已經失敗後,就可以開始設定 AssumeRole。


在 Account B 建立 ProductDataReadRole

登入 Account B,進入 IAM → Roles → Create role。

這次建立的 Role 不會直接掛載到 EC2,而是讓 Account A 的 OrderApiRole 透過 STS AssumeRole 取得它的暫時性憑證。

建立時選擇:

  1. Trusted entity type:AWS account。
  2. AWS account:Another AWS account。
  3. Account ID:輸入 111122223333。
  4. Role name:ProductDataReadRole。

https://ithelp.ithome.com.tw/upload/images/20260923/20183052ulUjRan4JQ.png

https://ithelp.ithome.com.tw/upload/images/20260923/20183052IH5UZO1ZCu.png

建立完成後,進入 IAM → Roles → ProductDataReadRole → Trust relationships → Edit trust policy。

將 Trust Policy 修改為:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TrustOrderApiRole",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/OrderApiRole"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20260923/201830523dHen8FgmR.png

這份 Trust Policy 的 Principal 指定 Account A 的 OrderApiRole,表示 Account B 允許這個特定的 Role 切換至 ProductDataReadRole。

如果直接在建立 Role 時信任整個 Account A,則可能讓 Account A 中其他具有對應 AssumeRole 權限的身分也可以切換角色。因此,這裡進一步將信任對象限制為 OrderApiRole。

與上一篇不同的是,這次 Trust Policy 的 Principal 不再是 ec2.amazonaws.com,而是 Account A 的 IAM Role ARN。

ProductDataReadRole 的 Trust Policy 負責決定「誰可以使用這個 Role」,而實際取得 Role 後能操作哪些 AWS 資源,仍然需要透過 Permissions Policy 設定。


在 Account B 設定 ProductDataReadRole 的 IAM Policy

進入 IAM → Roles → ProductDataReadRole → Permissions → Add permissions → Create inline policy。

切換至 JSON 編輯器,貼上:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListProductDataBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::shared-product-data-prod"
    },
    {
      "Sid": "ReadProductDataObjects",
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::shared-product-data-prod/*"
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20260923/20183052UNmdKMXKOv.png

Policy name 可以自行輸入(這篇實作以 ProductDataReadRole 作為示範),最後點選 Create policy。

這份 Policy 允許 ProductDataReadRole 列出及讀取 Account B 的 S3 Bucket,但沒有授予上傳或刪除物件的權限。

到這裡,Account B 已經完成兩項設定:

  • Trust Policy:允許 Account A 的 OrderApiRole 切換至 ProductDataReadRole。
  • Permissions Policy:允許 ProductDataReadRole 讀取 Account B 的 S3 Bucket。

接下來還需要在 Account A 授予 OrderApiRole 執行 AssumeRole 的權限。


在 Account A 設定 AssumeRole 權限

登入 Account A,進入 IAM → Roles → OrderApiRole → Permissions → Add permissions → Create inline policy。

切換至 JSON 編輯器,貼上:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AssumeProductDataReadRole",
      "Effect": "Allow",
      "Action": "sts:AssumeRole",
      "Resource": "arn:aws:iam::444455556666:role/ProductDataReadRole"
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20260923/20183052QqS31xfWRU.png

Policy name 可以自行輸入(這篇實作以 AssumeProductDataReadRolePolicy 作為示範),最後點選 Create policy。

這份 IAM Policy 允許 Account A 的 OrderApiRole 呼叫 STS AssumeRole,切換至 Account B 的 ProductDataReadRole。

到這裡,兩側的權限設定已經完成:

帳號 Policy 用途
Account A OrderApiRole 的 IAM Policy 允許 AssumeRole 至 Account B
Account B ProductDataReadRole 的 Trust Policy 信任 Account A 的 OrderApiRole
Account B ProductDataReadRole 的 IAM Policy 允許讀取本帳號的 S3 Bucket

這次 Account A 不需要直接取得 Account B 的 S3 權限,而是先取得切換角色的權限,再使用 Account B 的 Role 讀取 S3。


透過 STS AssumeRole 取得暫時性憑證

回到 Account A 的 EC2,先確認目前的 IAM 身分:

aws sts get-caller-identity

預期 ARN 類似:

arn:aws:sts::111122223333:assumed-role/OrderApiRole/i-0123456789abcdef0

接著,使用 AWS CLI 呼叫 STS AssumeRole:

aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/ProductDataReadRole \
  --role-session-name ProductDataReadTest

這裡的兩個參數分別代表:

  • --role-arn:要切換至哪一個 IAM Role。
  • --role-session-name:這次 AssumeRole 工作階段的名稱,方便後續識別。

執行成功後,STS 會回傳類似以下資訊:

{
  "Credentials": {
    "AccessKeyId": "ASIA...",
    "SecretAccessKey": "...",
    "SessionToken": "...",
    "Expiration": "2026-09-22T08:00:00+00:00"
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "AROAXXXXXXXXX:ProductDataReadTest",
    "Arn": "arn:aws:sts::444455556666:assumed-role/ProductDataReadRole/ProductDataReadTest"
  }
}

這裡的 Credentials 就是 STS 核發的暫時性憑證,包含:

欄位 用途
AccessKeyId 暫時性 Access Key ID
SecretAccessKey 暫時性 Secret Access Key
SessionToken 暫時性工作階段 Token
Expiration 憑證到期時間

與長期 IAM User Access Key 不同,AssumeRole 取得的憑證具有有效期限,到期後需要重新取得。

將暫時性憑證套用至 AWS CLI

前面雖然已經成功呼叫 AssumeRole,但 AWS CLI 不會因為執行了 aws sts assume-role,就自動改用回傳的憑證。

因此,接下來需要將取得的暫時性憑證套用至目前的終端機,才能使用 Account B 的身分執行 S3 API。

為了避免手動複製憑證,可以在 EC2 終端機執行以下指令:

CREDS=$(aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/ProductDataReadRole \
  --role-session-name ProductDataReadTest \
  --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
  --output text) || exit 1

read -r AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN <<< "$CREDS"

export AWS_ACCESS_KEY_ID
export AWS_SECRET_ACCESS_KEY
export AWS_SESSION_TOKEN

unset CREDS

這裡會重新呼叫一次 AssumeRole,取得新的暫時性憑證,再將憑證設定到目前 Shell 的環境變數。

設定完成後,AWS CLI 就可以使用 Account B 的 ProductDataReadRole 暫時性憑證執行後續操作。

這些環境變數只會影響目前的 Shell 工作階段及其子程序,不會直接修改 EC2 原本掛載的 OrderApiRole。結束測試後,可以移除環境變數,恢復使用 EC2 原本的 IAM Role。


驗證 AssumeRole 後的 IAM 身分

完成憑證設定後,再次執行:

aws sts get-caller-identity

預期 ARN 類似:

arn:aws:sts::444455556666:assumed-role/ProductDataReadRole/ProductDataReadTest

https://ithelp.ithome.com.tw/upload/images/20260923/20183052cCZFRLfJEm.png

與前面相比,可以觀察到兩個差異:

項目 AssumeRole 前 AssumeRole 後
Account ID 111122223333 444455556666
IAM Role OrderApiRole ProductDataReadRole
Role session name EC2 Instance ID ProductDataReadTest

雖然目前操作的仍然是 Account A 的同一台 EC2,但 AWS CLI 已經改用 Account B 的 ProductDataReadRole 暫時性憑證。

這也是本次與上一篇最大的差異:上一篇是由 Account A 的 Role 直接存取 Account B 的資源;這次則是先切換至 Account B 的 Role,再以該 Role 的身分存取 S3。


使用 Account B 的 Role 讀取 S3

確認目前使用的是 ProductDataReadRole 後,先測試列出 Bucket 中的物件:

aws s3 ls s3://shared-product-data-prod/

如果權限設定正確,且沒有其他政策限制,預期可以成功列出 S3 Bucket 中的物件。

https://ithelp.ithome.com.tw/upload/images/20260923/20183052HsKqUVjXZp.png

接著,先下載上一篇使用 SSE-S3 加密的測試物件:

cd ~

aws s3 cp \
  s3://shared-product-data-prod/test.png \
  ./method2-test.png

這裡請使用上一篇已確認為 SSE-S3 加密的物件,並依照實際上傳的檔名修改指令。若上一篇的測試檔案名稱不同,請替換成自己的物件名稱。

如果下載成功,預期會看到類似:

download: s3://shared-product-data-prod/test.png to ./method2-test.png

接著執行:

ls method2-test.png

確認檔案已成功下載至 EC2。

https://ithelp.ithome.com.tw/upload/images/20260923/20183052Ib1v2dMXJE.png

最後,再次執行:

aws sts get-caller-identity

確認目前仍然使用 Account B 的 ProductDataReadRole。

https://ithelp.ithome.com.tw/upload/images/20260923/20183052D2qaByDInr.png

這代表 Account A 的 EC2 已經成功透過 AssumeRole,取得 Account B 的暫時性身分,並使用該身分讀取 Account B 的 S3 Bucket。

補充:如果讀取的是 SSE-KMS 加密物件呢?

上一篇已經測試過,當 S3 物件使用 SSE-KMS 加密時,除了 s3:GetObject,還需要具有使用對應 KMS Key 的權限。

上一篇使用 Account A 的 OrderApiRole 直接跨帳號存取時,無法讀取使用 Account B 的 AWS managed key aws/s3 加密的物件。

但這次已經透過 AssumeRole 切換至 Account B 的 ProductDataReadRole,實際讀取 S3 的身分與 KMS Key 位於同一個帳號,因此可以在取得適當的 KMS 權限後,讀取使用 aws/s3 加密的物件。

在 Account B 設定 KMS 解密權限

登入 Account B,進入 IAM → Roles → ProductDataReadRole → Permissions → Add permissions → Create inline policy。

切換至 JSON 編輯器,貼上以下內容:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DecryptProductData",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:ap-northeast-1:444455556666:alias/aws/s3"
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20260923/20183052ZTloFGOn3g.png

Policy name 可以自行輸入(這篇實作以 DecryptProductDataPolicy 作為示範),最後點選 Create policy。

這份 IAM Policy 允許 ProductDataReadRole 使用 Account B 的 AWS managed key aws/s3 執行解密操作。

由於本次只需要下載 S3 物件,因此先授予 kms:Decrypt 即可,不需要額外授予 kms:Encrypt 或 kms:GenerateDataKey。

aws/s3 是 AWS managed key,無法自行修改它的 Key Policy。不過,這次的 ProductDataReadRole 與 KMS Key 位於同一個 AWS 帳號,因此可以透過 IAM Policy 授予對應的解密權限,不需要像上一篇直接跨帳號存取時一樣,另外授權 Account A 的 Role 使用金鑰。

重新測試 SSE-KMS 物件的讀取權限

回到 Account A 的 EC2,確認目前已經透過 AssumeRole 切換至 Account B 的 ProductDataReadRole:

aws sts get-caller-identity

預期 ARN 類似:

arn:aws:sts::444455556666:assumed-role/ProductDataReadRole/ProductDataReadTest

接著,下載上一篇使用 aws/s3 加密的測試物件:

aws s3 cp \
  s3://shared-product-data-prod/test-aws-kms.png \
  ./method2-test-aws-kms.png

如果 S3 與 KMS 權限都設定正確,且沒有其他政策限制,預期可以成功下載物件。

https://ithelp.ithome.com.tw/upload/images/20260923/201830521mit14QkA7.png

這次與上一篇最大的差異在於:

  • Bucket Policy 直接授權: 實際使用的是 Account A 的 OrderApiRole,無法跨帳號使用 Account B 的 AWS managed key aws/s3 解密物件。
  • STS AssumeRole: 實際使用的是 Account B 的 ProductDataReadRole,與 aws/s3 位於同一帳號,因此可以在取得適當的 KMS 權限後讀取物件。

這也說明了,相同的 S3 物件,即使使用相同的加密方式,也可能因為實際存取的 IAM 身分不同,而有不同的授權結果。


還原 EC2 原本的 IAM 身分

完成測試後,可以移除剛才設定的 STS 暫時性憑證:

unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN

再次執行:

aws sts get-caller-identity

預期 ARN 會恢復為:

arn:aws:sts::111122223333:assumed-role/OrderApiRole/i-0123456789abcdef0

這代表 AWS CLI 已恢復使用 EC2 原本的 IAM Role。

此時,如果再次直接存取 Account B 的 S3:

aws s3 ls s3://shared-product-data-prod/

在沒有其他政策額外授權的情況下,預期會再次收到 AccessDenied。

因為目前使用的又是 Account A 的 OrderApiRole,而我們已經在本篇開始時移除上一篇的直接跨帳號 S3 授權。

https://ithelp.ithome.com.tw/upload/images/20260923/20183052MhF4rulEKM.png


整理測試結果

經過前面的操作,可以將兩種跨帳號存取方式整理如下:

比較項目 Bucket Policy 直接授權 STS AssumeRole
存取方 Account A Account A
實際讀取 S3 的 Role OrderApiRole ProductDataReadRole
讀取 S3 時的 Account ID 111122223333 444455556666
Account A 的 IAM Policy 允許讀取 Account B 的 S3 允許 AssumeRole 至 Account B
Account B 的 Bucket Policy 授權 Account A 的 Role 本次實作不需要額外授權
Account B 的 Role 不需要 設定 Trust Policy 與 S3 存取權限

兩種方式都能讓 Account A 的 EC2 讀取 Account B 的 S3 Bucket,但實際使用的 IAM 身分不同。

Bucket Policy 直接授權是讓 Account A 的 OrderApiRole 直接存取 Account B 的 S3,過程中不需要切換至 Account B 的 Role。

STS AssumeRole 則是讓 Account A 的 OrderApiRole 先取得 Account B 的 ProductDataReadRole 暫時性憑證,再使用該 Role 的權限存取 S3。

因此,兩種方式除了權限設定位置不同,實際執行 S3 API 時使用的 IAM 身分也不同。

下一篇

這三篇透過 Bucket Policy 與 AssumeRole,實作了不同 AWS 帳號之間的資源存取,並觀察兩種方式在權限設定與實際存取身分上的差異。

不過,當 AWS 帳號越來越多,需要管理的就不只是資源之間的存取權限。公司的開發與維運人員可能需要登入不同帳號,各自擁有不同的操作權限。如果每個帳號都要分別管理使用者與權限,維護起來也會越來越複雜。

下一篇將介紹 AWS IAM Identity Center,了解如何集中管理多個 AWS 帳號的人員登入與存取權限,以及如何透過群組、Permission Set 與企業既有的身分系統,簡化多帳號的權限管理。


上一篇
Day 8|跨帳號存取實作:用 Bucket Policy 、 AssumeRole 讀取 S3(中)
下一篇
Day 10|AWS 帳號變多後,登入與權限怎麼集中管理?
系列文
AWS 架構為什麼這樣選?30 天拆解服務選型與設計取捨 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言