上一篇我們把圖片上傳到 S3,也拿到了圖片網址
但如果把網址貼給朋友,卻看到 AccessDenied,奇怪,圖片不是已經傳好了嗎?
因為你能上傳,跟別人能不能看,是兩件事。S3 還沒允許其他人讀這張圖片
今天就接著把圖片開放給別人看,再把它關回來,讓你能多瞭解 S3 的權限設計~
我們來回到全貌圖,今天看橘色這條線:瀏覽器直接向 S3 讀圖片。這段沒有經過 EC2,所以這次要改的是 S3 的設定,不用動主機的 Security Group
為了能看到圖片資料,我們會用 Bucket Policy(儲存桶政策) 寫下「允許任何人讀這張圖」
但 S3 還有 Block Public Access(封鎖公開存取)。如果它擋住公開讀取,就算 Policy 寫了允許,朋友還是看不到。接著就來試試這兩個設定
沿用上篇的練習 Bucket,裡面放一張可以給大家看的 practice/sample.png。ACLs disabled、SSE-S3 都維持原設定,Bucket Policy 目前也是空的
這次除了上傳,還會修改 S3 的政策與封鎖設定,所以先確認自己的 IAM User 有這些權限,當然用 root 練習也是可的
還沒喔,取消封鎖後,還要告訴 S3,這張圖片可以給誰看
這裡有個容易漏掉的地方:AWS 帳號可以統一封鎖底下的 Bucket。如果帳號這邊還擋著,只改 Bucket 也沒用,所以我們先看帳號設定
到 S3 → Account and organization settings → Block Public Access settings for this account,先記下原設定,最後要再恢復過來
我們用 Bucket Policy,相關的是下面兩項。畫面上的說明都含有 public bucket or access point policies:
| 設定名稱 | 勾選後會怎樣? |
|---|---|
BlockPublicPolicy |
不讓你存入會公開的 Bucket Policy |
RestrictPublicBuckets |
Bucket 已有公開 Policy 時,還是會擋住匿名讀取 |
這兩項已關閉就不用改。有勾選的話,先確認這是自己的練習帳號,而且其他 Bucket 不會跟著公開,再來按 Edit 取消這兩項
接著按 Save changes,依畫面輸入 confirm 儲存。這是在改整個帳號的設定,其他 Bucket 也會受影響
回到練習 Bucket 的 Permissions → Block public access (bucket settings) → Edit
取消 Block all public access,確認下方四項都未勾選,再按 Save changes,依畫面輸入 confirm 確認
現在用新的無痕視窗打開原本的 Object URL,應該還會是 AccessDenied。因為我們只取消封鎖,還沒寫下允許誰讀取
到同一個 Permissions → Bucket policy → Edit,貼上以下內容,把 YOUR_BUCKET_NAME 換成自己的 Bucket 名稱:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadPracticeImage",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/practice/sample.png"
}
]
}
這條規則合起來就是:允許任何人讀取這個 Bucket 裡的 practice/sample.png
| 欄位 | 這次代表什麼? |
|---|---|
Effect: "Allow" |
允許 |
Principal: "*" |
任何人,包含沒有登入 AWS 的網友 |
Action: "s3:GetObject" |
讀取 S3 物件內容 |
Resource |
只指定這張圖片,包含完整 Key |
Resource 要填的是 AWS 用來辨認這張圖片的名稱,這種寫法叫 ARN。所以前面是 arn:aws:s3:::,後面接 Bucket 名稱與完整 Key
這次只想開放一張圖,就保留 practice/sample.png。如果把這段換成 *,就會變成允許讀取整個 Bucket 裡的物件
確認後按 Save changes。這條規則只有讀取,沒有允許網友上傳、刪除或列出其他檔案。也附上(Bucket Policy 說明、公開讀取範例)
從圖片的 Properties → Object URL 複製網址,關閉所有無痕視窗,再開新的無痕視窗貼上
照前面的設定做完,沒有其他限制的話,這次應該就看得到圖片了
你會發現,圖片沒重傳,網址也沒換
這裡複製 Object URL。Open 按鈕提供的連結可能帶有暫時的讀取權限,用它開得了圖片,不過這還不能證明一般網友也能看(官方說明)
如果還是看不到,先檢查 Policy 有沒有存成功、Bucket 名稱與 Key 有沒有寫對,再看帳號與 Bucket 是否還擋著公開讀取
回到 Permissions → Block public access (bucket settings) → Edit,重新勾選 Block all public access,確認四項都勾選,儲存
先保留下方的 Policy,不要刪除。然後關閉所有無痕視窗,再開新的無痕視窗,貼上剛才同一個 Object URL
這次應該又會看到 AccessDenied (該不會是在耍我
咦,Policy 裡不是還寫著 Allow 嗎?
因為 Allow 還在,但我們把公開讀取擋回去了。剛才勾選的 RestrictPublicBuckets,會擋住這種沒有登入 AWS、直接用網址讀取的請求。但 Policy 並沒有被刪掉
也幫大家把剛才的過程整理成一張圖,方便對照
如果舊分頁還看得到,記得換新的無痕視窗再試。圖片已經載入或下載到別人的電腦,不會因為你改權限就消失;要重新向 S3 讀取,才看得出差異
不用的。前面是練習讓任何人讀一張圖片,實際做網站時,也可以讓 Bucket 保持私有
這裡拿一般平台流程來分享:使用者在網頁選好圖片,先向後端請求上傳。後端確認可以後,才給他一個有期限的上傳網址,叫做 預簽名 URL(Presigned URL)
這個網址是後端用自己的 AWS 身分產生的,會指定要上傳到哪個 Key。當然,後端自己也要有上傳到那個位置的權限,也附上(官方上傳說明)
整個流程可以看下面這張圖:
重點會在第二段:瀏覽器拿到網址後,圖片直接傳到 S3,不用先傳到我們的後端主機
那 S3 怎麼知道這個人能不能上傳?它會檢查網址的簽名與 AWS 權限。至於這個人有沒有登入網站、能不能上傳,前面就得由後端確認好
而且前端說「傳好了」,後端也不能直接當作完成。還要去確認,傳的是不是剛才允許這位使用者上傳的那個檔案、檔案是否真的存在且符合要求,再把 Key、檔案是誰的、是否上傳完成,記進資料庫
那上傳完,前端要怎麼顯示圖片?
如果圖片只想給特定使用者看,後端先確認他能看,再給另一個有期限的讀取網址。剛才拿到的是上傳用的,不能直接拿來讀圖
所以資料庫會保留圖片的 Key,需要時再產生新的連結,不會只存一個過期就不能用的網址
要提醒一下,有期限不代表只能用一次,也不代表只有原本那個人能用。網址被轉傳,拿到的人在它有效時也可能使用,所以期限只給這次操作需要的時間
真正接到前端時,還要設定 CORS,讓瀏覽器允許網站向 S3 發出這類請求。至於能不能上傳,也要檢查前面講的權限,設定 CORS 不會自動取得上傳權限
剛才 S3 給我們的網址,大概長這樣:
https://my-site-images.s3.ap-northeast-1.amazonaws.com/practice/sample.png
光看網址就知道圖片放在 AWS,那如果想換成自己網站的名字呢?
https://images.example.com/practice/sample.png
這段是可以的,AWS 有個服務叫 CloudFront,就能幫我們做到這件事。圖片照樣放在 S3,由 CloudFront 拿給網友看。拿過的圖片也能先留一份,下次有人要看,就不用每次都回 S3 拿
設定時,要把 CloudFront 接到自己的 S3,再設定網域與 HTTPS 憑證,這裡附上 設定教學
如果你是無課金玩家,也可以用 Cloudflare R2 的免費額度來練習。R2 是另一個放檔案的地方,所以圖片要改傳到 R2,做法大概是:
免費額度有上限,超過還是會收費,也附上(R2 價格)
兩種做法整理如下,主要看右邊,圖片是放在 S3 還是 R2:
最後總結一下:
| 重點 | 記住這句 |
|---|---|
| 自己的 IAM 權限 | 決定自己能不能管理 S3,不等於替網友授權 |
| Bucket Policy | 寫清楚誰、可以做什麼、對哪個物件 |
| 取消公開封鎖 | 還要有公開授權,圖片才會讓網友讀取 |
| Policy 寫 Allow | 還要看有沒有適用的封鎖或其他限制 |
| 收尾 | 重新封鎖,再移除這次的公開規則 |
希望這篇有讓你對 S3 的權限更有概念,我們下篇見 :D