iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
IT Operation

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

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

  • 分享至 

  • xImage
  •  

上一篇已經完成共用測試環境的準備,在 Account B 建立 S3 Bucket,並在 Account A 建立 EC2 與 OrderApiRole,透過 Session Manager 連線後,也確認了 EC2 正在使用的 IAM 身分。

今天先實作第一種跨帳號存取方式:使用 Resource-based Policy,讓 Account A 的 OrderApiRole 直接讀取 Account B 的 S3 Bucket。

完成基本的 S3 讀取測試後,再將測試物件改用 SSE-KMS 加密,觀察相同的 IAM Role 在不同加密設定下,會遇到什麼權限問題。

準備實作環境

本篇沿用上一篇建立的測試環境:

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

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


測試尚未授權時的存取結果

先登入 Account A,透過 Session Manager 連線至上一篇建立的 EC2:

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

進入 EC2 終端機後,先確認目前的 IAM 身分:

aws sts get-caller-identity

預期 ARN 類似:

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/20260922/201830524779HJWEtZ.png

這是因為目前 OrderApiRole 只有上一篇附加的 AmazonSSMManagedInstanceCore,尚未取得 Account B 的 S3 存取權限。

接下來會分別在 Account A 設定 Identity-based Policy,以及在 Account B 設定 Resource-based Policy,再重新執行相同指令,觀察授權前後的差異。


在 Account A 設定 IAM Policy

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

https://ithelp.ithome.com.tw/upload/images/20260922/2018305243prSFmwkg.png

切換至 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/20260922/20183052ZhBGXKKCQo.png

Policy name 可以自行輸入,最後點選 Create policy。
https://ithelp.ithome.com.tw/upload/images/20260922/20183052uVg79aWhFh.png

這份 IAM Policy 允許 OrderApiRole 執行兩種操作:

Action 用途 Resource
s3:ListBucket 列出 Bucket 中的物件 Bucket ARN
s3:GetObject 讀取及下載物件 Object ARN

這裡要注意,s3:ListBucket 是 Bucket 層級的權限,因此 Resource 不需要加上 /*;s3:GetObject 則是物件層級的權限,需要在 Bucket ARN 後面加上 /*,表示允許讀取 Bucket 中的物件。

本次只授予列出與讀取權限,不包含 s3:PutObject 或 s3:DeleteObject,因此不會因為這份 Policy 而取得上傳及刪除物件的權限。

完成後,Account A 的 OrderApiRole 已經有了允許讀取目標 Bucket 的 IAM Policy,但目前仍然缺少 Account B 資源側的授權。


在 Account B 設定 Bucket Policy

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

貼上以下 JSON:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowOrderApiRoleListBucket",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/OrderApiRole"
      },
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::shared-product-data-prod"
    },
    {
      "Sid": "AllowOrderApiRoleReadObjects",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::111122223333:role/OrderApiRole"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::shared-product-data-prod/*"
    }
  ]
}

如果 Bucket 已經有其他 Policy,請將上述兩個 Statement 合併至原本的 Statement 陣列,不要直接覆蓋既有的授權設定,設定完畢後點選右下角的Save changes。

這份 Bucket Policy 與前面 IAM Policy 的主要差異,在於多了 Principal:

"Principal": {
  "AWS": "arn:aws:iam::111122223333:role/OrderApiRole"
}

Principal 指定的是「誰可以存取這個資源」。

這裡填入 Account A 的 OrderApiRole ARN,表示 Account B 允許這個特定的 Role 讀取 Bucket,而不是開放給 Account A 的所有 IAM 身分。

本次實作也不需要修改 OrderApiRole 原本信任 EC2 的 Trust Policy,因為 EC2 不會切換至 Account B 的 Role,而是直接以 Account A 的身分存取 S3。


測試跨帳號讀取 S3

完成兩側授權後,回到 Account A 的 EC2,重新執行:

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

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

接著,下載上一篇上傳的測試檔案。以下以 test.png 為例,請將檔名替換成你實際上傳的物件名稱:

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

https://ithelp.ithome.com.tw/upload/images/20260922/20183052CDUYPVdXyn.png

如果要驗證本次設定的是唯讀權限,也可以嘗試將檔案上傳回 Bucket:

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

在沒有其他政策額外授權的情況下,預期會收到 AccessDenied,因為本次沒有授予 s3:PutObject 權限。

最後,再次確認目前使用的 IAM 身分:

aws sts get-caller-identity

預期 ARN 仍然是:

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

https://ithelp.ithome.com.tw/upload/images/20260922/201830522KiMHTQOfn.png

可以看到,即使成功讀取了 Account B 的 S3 Bucket,EC2 使用的仍然是 Account A 的 OrderApiRole。

整個過程並沒有 AssumeRole 至 Account B,而是透過 Account B 的 Bucket Policy,直接授權 Account A 的 Role 存取資源。

到這裡,第一種跨帳號存取方式就完成了。


補充測試:SSE-KMS 加密對跨帳號存取的影響

上一篇建立 S3 Bucket 時,預設加密方式使用的是 SSE-S3。

SSE-S3 由 Amazon S3 管理加密金鑰,當 IAM 權限允許讀取物件時,S3 會自動處理解密,不需要另外設定 KMS 權限。

但如果物件使用的是 SSE-KMS,除了 S3 的存取權限之外,還需要確認目前的 IAM 身分是否具有使用對應 KMS Key 的權限。

參考:AWS 官方文件|Using server-side encryption with AWS KMS keys

接下來沿用相同的 OrderApiRole,分別測試 AWS managed key 與 Customer managed key。

測試一:使用 AWS managed key 加密物件

先登入 Account B,進入 S3 → General purpose buckets → shared-product-data-prod → Properties → Default encryption → Edit。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052sPJsKdkBIM.png

將加密方式修改為:

  • Encryption type:Server-side encryption with AWS Key Management Service keys(SSE-KMS)。
  • AWS KMS key:AWS managed key(aws/s3)。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052EiikrSm7Xw.png

儲存設定後,重新上傳一個測試檔案。

這裡要注意,修改 Bucket 的預設加密設定,不會自動改變先前已上傳物件的加密方式。因此,這次另外上傳測試物件,確保它實際使用 SSE-KMS 加密。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052hzVWDeSF7Q.png

上傳完成後,可以再點選剛才上傳的物件 → Properties → Server-side encryption settings,確認物件使用 SSE-KMS,且 KMS Key 為 aws/s3。

接著回到 Account A 的 EC2,以下以 test-aws-kms.png 為例,請將檔名替換成你實際上傳的物件名稱,執行:

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

預期會收到類似以下錯誤:

download failed: s3://shared-product-data-prod/test-aws-kms.png
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

https://ithelp.ithome.com.tw/upload/images/20260922/20183052Nq2XNaLDAi.png

這次的 AccessDenied 並不是因為缺少 S3 Bucket Policy,而是因為物件使用了 Account B 的 AWS managed KMS key。

AWS managed key 由 AWS 管理其 Key Policy,無法自行修改政策來授權其他 AWS 帳號的 IAM 身分使用,因此無法直接將使用 Account B 的 aws/s3 加密的物件分享給 Account A 讀取。

參考:AWS 官方文件|Allowing users in other accounts to use a KMS key

也就是說,即使 Account A 的 IAM Policy 和 Account B 的 Bucket Policy 都已經允許 s3:GetObject,仍然無法直接讀取使用 Account B 的 aws/s3 加密的物件。

如果要讓其他帳號讀取 SSE-KMS 加密的 S3 物件,就需要改用可以自行設定 Key Policy 的 Customer managed key。


測試二:建立 Customer managed key

接著登入 Account B,進入 Key Management Service(KMS)→ Customer managed keys → Create key。

設定如下:

項目 設定
Key type Symmetric
Key usage Encrypt and decrypt
Key material origin KMS
Alias alias/product-data-cross-account
Region ap-northeast-1

其他設定可以先保留預設值。

在 Define key administrative permissions 階段,選擇具有 KMS 管理權限的管理者。

在 Define key usage permissions 階段,可以先保留適當的 Account B 本地使用者或角色權限;後續再透過 Key Policy 明確授權 Account A 的 OrderApiRole。

建立完成後,進入該 KMS Key 的詳細資訊頁面,記錄 Key ARN。

範例如下:

arn:aws:kms:ap-northeast-1:444455556666:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

後續 IAM Policy 與 Key Policy 都會使用這個 ARN,實作時請替換成你實際建立的 Key ARN。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052eAhqpidaOF.png

在 Account B 設定 KMS Key Policy

進入 KMS → Customer managed keys → 選擇剛才建立的 Key → Key policy。

切換至 Policy view,找到原有政策的 Statement 陣列,加入以下 Statement:

{
  "Sid": "AllowAccountAOrderApiRoleDecrypt",
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::111122223333:role/OrderApiRole"
  },
  "Action": "kms:Decrypt",
  "Resource": "*"
}

這裡要注意,請保留原本 Key Policy 中的管理者權限及其他必要設定,不要直接用上述內容覆蓋整份 Key Policy。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052fuf8ogC0F5.png

這份授權代表 Account B 允許 Account A 的 OrderApiRole 使用這把 KMS Key 執行 kms:Decrypt。

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

在 Account A 補上 KMS IAM Policy

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

貼上以下 JSON:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DecryptAccountBProductData",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:ap-northeast-1:444455556666:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    }
  ]
}

https://ithelp.ithome.com.tw/upload/images/20260922/20183052aCVYY06nu0.png

Policy name 可以自行輸入,最後點選 Create policy。

這裡與前面的跨帳號 S3 授權概念類似:Account A 的 IAM Policy 允許 OrderApiRole 使用指定 KMS Key,而 Account B 的 Key Policy 則允許該 Role 使用這把金鑰。

對於跨帳號使用 Customer managed key 的情境,僅設定 IAM Policy 或 Key Policy 其中一側並不足夠,需要同時具備適當授權。

參考:AWS 官方文件|Allowing users in other accounts to use a KMS key

將測試物件改用 Customer managed key 加密

完成 KMS 授權後,回到 Account B 的 S3 Bucket。

進入 Properties → Default encryption → Edit,將預設加密方式維持在 SSE-KMS,並改為選擇剛才建立的 Customer managed key。

儲存設定後,重新上傳一個新的測試物件。

上傳完成後,進入物件的 Properties,確認其加密方式為 SSE-KMS,且使用的 KMS Key ARN 與剛才建立的 Customer managed key 相同。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052Q6ofZYvuaJ.png

重新測試跨帳號讀取

回到 Account A 的 EC2,以下以 test-aws-cmk.png 為例,請將檔名替換成你實際上傳的物件名稱,執行:

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

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

最後,再次執行:

aws sts get-caller-identity

預期仍然顯示:

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

這代表即使讀取的是 Account B 使用 Customer managed key 加密的 S3 物件,目前使用的仍然是 Account A 的 OrderApiRole。

https://ithelp.ithome.com.tw/upload/images/20260922/20183052LTldz9uRwk.png


整理測試結果

經過前面的操作,可以將三種加密方式的跨帳號讀取結果整理如下:

加密方式 額外 KMS 授權 預期讀取結果
SSE-S3 不需要 成功
SSE-KMS(AWS managed key) 無法跨帳號授權使用 aws/s3 AccessDenied
SSE-KMS(Customer managed key) 需要設定 KMS Key Policy 與 IAM Policy 授權後成功

跨帳號直接存取 S3 的權限分配

本篇使用 IAM Policy 與 Bucket Policy,讓 Account A 的 OrderApiRole 直接讀取 Account B 的 S3 Bucket,權限分配如下圖:

https://ithelp.ithome.com.tw/upload/images/20260922/20183052In62yNR59S.png

這種做法需要由兩側分別授權:

  • 存取端 Account A: 透過 IAM Policy,允許 OrderApiRole 讀取目標 S3 Bucket。
  • 資源擁有端 Account B: 透過 Bucket Policy,允許 Account A 的 OrderApiRole 存取 Bucket。

當兩側都完成授權,且沒有其他政策限制時,就能直接跨帳號讀取 S3,不需要 AssumeRole 至 Account B。

如果物件使用 SSE-KMS 加密,則還需要確認是否具有對應的 KMS 解密權限。

下一篇

今天完成了第一種跨帳號存取方式,透過 Account A 的 IAM Policy 與 Account B 的 Bucket Policy,讓 EC2 直接讀取另一個帳號的 S3 Bucket。

即使成功讀取物件,透過 aws sts get-caller-identity 仍然可以看到,目前使用的是 Account A 的 OrderApiRole。

下一篇會改用第二種方式:在 Account B 建立 ProductDataReadRole,讓 Account A 的 OrderApiRole 先透過 STS AssumeRole 取得 Account B 的暫時性身分,再使用該身分讀取相同的 S3 Bucket。


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

尚未有邦友留言

立即登入留言