文章

將檔案上傳到 S3 的 5 種方法:Console、CLI、API、SFTP 與 Presigned URL

比較使用 AWS Management Console、AWS CLI、API Gateway、AWS Transfer Family 與 Presigned URL 上傳檔案到 Amazon S3 的方式、適用情境、安全限制與實作範例。

將檔案上傳到 S3 的 5 種方法:Console、CLI、API、SFTP 與 Presigned URL

把檔案上傳到 S3 幾乎是 AWS 最常見的基本操作之一。

但「上傳檔案」背後可能是完全不同的使用情境:工程師從本機上傳、CI 發布靜態檔案、後端接收使用者附件、瀏覽器直接上傳大型檔案,或合作廠商仍然只能使用 SFTP。這些需求雖然最後都把物件寫入 S3,適合的入口卻不相同。

這篇文章比較 5 種實務上常見的做法:

  1. AWS Management Console 直接上傳
  2. 使用 AWS CLI
  3. API Gateway 直接整合 S3,或由後端上傳
  4. AWS Transfer Family(SFTP/FTPS 對外交換檔案)
  5. Presigned URL(前端或外部客戶端直傳)

快速選擇

方法適合情境優點主要限制
AWS Management Console臨時操作、少量檔案、初次接觸 S3不需要安裝工具,操作直觀仰賴人工操作,不適合自動化與大量重複作業
AWS CLI工程師、本機維運、CI/CD簡單直接,支援目錄與大型檔案執行環境需要 AWS 身分與 IAM 權限
API Gateway/後端小型附件、需要商業邏輯與驗證的 API驗證、授權、審計與命名規則集中管理受 API payload 限制;經過後端時也會占用運算資源
AWS Transfer Family合作夥伴、舊系統、SFTP/FTPS 流程不必要求對方改用 AWS API需要管理端點、使用者、網路與服務成本
Presigned URLWeb、App、第三方系統直接上傳檔案不經過後端,容易擴展必須處理 URL 有效期、CORS、檔名與上傳條件

方法 1:AWS Management Console

在還沒開始使用 CLI 或 IaC 工具以前,最直觀的做法就是登入 AWS Management Console,開啟 Amazon S3,進入目標 bucket 後選擇「Upload」上傳檔案。

這種方式不需要先安裝工具或撰寫指令,適合臨時上傳、測試,或剛開始熟悉 S3 的情境。上傳時也能在介面中設定 metadata、儲存類別與其他物件屬性。

不過,Console 操作依賴人工執行,難以重複與自動化,因此不適合 CI/CD 或需要固定排程的工作。Amazon S3 Console 目前支援上傳最大 160 GB 的單一檔案;更大的檔案應改用 AWS CLI、AWS SDK 或 S3 REST API。

方法 2:AWS CLI

適合工程師在本機、跳板機,或 CI 流程直接上傳檔案。做法簡單、上手快,但要留意 IAM 權限與金鑰管理。

上傳單一檔案

1
aws s3 cp ./report.csv s3://example-bucket/uploads/report.csv

上傳完成後,可以確認物件是否存在:

1
aws s3 ls s3://example-bucket/uploads/report.csv

上傳整個目錄

若要遞迴上傳目錄,可使用 --recursive

1
aws s3 cp ./dist s3://example-bucket/site/ --recursive

如果需求是讓來源與目的端長期保持同步,則可使用 sync

1
aws s3 sync ./dist s3://example-bucket/site/

AWS CLI 的高階 S3 指令會在檔案達到 multipart threshold 時,自動改用 Multipart Upload,不需要自行切割每個 part。正式環境建議讓本機使用 AWS IAM Identity Center,而 EC2、ECS、EKS 或 CI Runner 則使用 IAM Role 或短期憑證,避免把長期 Access Key 寫進程式碼與 Pipeline 變數。

如果 Bastion 或其他 EC2 instance 上有需要備份的檔案,可以透過 cron 定期執行 aws s3 sync。建議使用 EC2 的 IAM Role,並將權限限制在專用的 S3 prefix,不要在主機上存放長期 Access Key。

權限設定

透過 WinSCP 或 S3 Browser 上傳

WinSCP、S3 Browser 這類圖形化工具是透過 S3 API 存取物件,並不是在底層執行 AWS CLI。除了上傳物件所需的 s3:PutObject,介面若要顯示指定 bucket 內的物件,還需要 s3:ListBucket

有些工具會先列出帳號中的所有 buckets,此時才需要 s3:ListAllMyBuckets。這個權限會讓使用者看到帳號內的 bucket 名稱;如果工具能直接設定目標 bucket,便可省略此權限。以下是允許使用者瀏覽並上傳至 uploads/ 的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListUploadPrefix",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::example-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": ["uploads", "uploads/*"]
        }
      }
    },
    {
      "Sid": "UploadObjects",
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::example-bucket/uploads/*"
    },
    {
      "Sid": "ListBucketsInClient",
      "Effect": "Allow",
      "Action": "s3:ListAllMyBuckets",
      "Resource": "*"
    }
  ]
}

如果還要讓使用者下載或刪除物件,再依實際需求加入 s3:GetObjects3:DeleteObject,不必一開始就全部開放。

透過 CLI 上傳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListUploadPrefix",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::example-bucket",
      "Condition": {
        "StringLike": {
          "s3:prefix": ["uploads", "uploads/*"]
        }
      }
    },
    {
      "Sid": "UploadObjects",
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::example-bucket/uploads/*"
    }
  ]
}

這份權限足以上傳並查看 uploads/。如果要執行前面以 site/ 為目標的目錄上傳,必須把該 prefix 一併加入 policy;若只需要上傳、不需要列出物件,則可以移除 s3:ListBucket

方法 3:API Gateway 直接整合 S3,或由後端上傳

API Gateway 直接上傳到 S3

API Gateway 不只能呼叫 Lambda。使用 REST API 的 AWS service integration,也能將請求直接交給 S3,不必先經過 Lambda:

1
Client → API Gateway REST API → Amazon S3

設定時需要建立 API Gateway 的 execution role,允許它對指定位置執行 s3:PutObject。例如只允許寫入 uploads/

1
2
3
4
5
6
7
8
9
10
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::example-bucket/uploads/*"
    }
  ]
}

接著在 REST API 建立 PUT method,選擇 S3 作為 AWS service integration,將 URL 中的檔名映射到 S3 object key,並傳遞上傳所需的 Content-Type。若要接收二進位檔案,還必須設定 API 的 binary media types。

execution role 只代表 API Gateway 有權寫入 S3,並不等於呼叫者已通過驗證;對外提供 API 時,仍要另外設定 IAM、Cognito Authorizer 或其他授權機制。這個做法雖然省去 Lambda,但檔案內容仍會經過 API Gateway,因此依然受到 10 MB 的 payload 上限限制。

透過 Lambda 或後端上傳

適合要由後端統一控管驗證、授權與審計的場景。彈性高,但系統複雜度也會提高。

1
Client → API Gateway → Lambda/Backend → Amazon S3

在這個架構中,後端可以先確認登入身分、檔案類型、業務單號與物件名稱,再透過 AWS SDK 呼叫 PutObject。核心操作大致如下;實際的 HTTP request 解析與錯誤處理會依框架而不同:

1
2
3
4
5
6
7
8
9
10
import boto3

s3 = boto3.client("s3")

s3.put_object(
    Bucket="example-bucket",
    Key="uploads/report.pdf",
    Body=file_bytes,
    ContentType="application/pdf",
)

這種方式的優點是所有規則都集中在後端。例如只有訂單擁有者可以上傳附件、資料庫寫入成功後才能建立物件,或必須在上傳後觸發掃毒與審核流程。

缺點是檔案內容會先經過 API Gateway 與後端,占用兩段網路流量及運算資源。以 API Gateway HTTP API 為例,payload size 上限為 10 MB,而且不能提高;如果請求還需要 Base64 編碼,實際可承載的原始檔案會更小。因此,這種方式比較適合小型附件,不適合大型影片、備份或資料集。

大型檔案通常應改用 Presigned URL,讓 API Gateway 只負責驗證使用者並產生上傳授權,而不是傳送檔案本體。

方法 4:AWS Transfer Family

適合需要 SFTP/FTPS 與外部系統交換檔案的場景,能讓既有流程較平順地接上 S3。

AWS Transfer Family 是 AWS 代管的檔案傳輸服務,支援 SFTP、FTPS、FTP、AS2 與瀏覽器式傳輸,後端可以使用 S3 或 EFS。對方仍然可以使用熟悉的 WinSCP、Cyberduck、FileZilla 或 OpenSSH,不需要先學會 AWS CLI 或取得 AWS 憑證。

基本流程如下:

  1. 建立 S3 bucket 與 Transfer Family 使用的 IAM Role。
  2. 建立支援 SFTP 或 FTPS 的 Transfer Family Server。
  3. 選擇 Service managed、Microsoft AD 或自訂 Identity Provider。
  4. 為使用者設定 Home Directory 與可存取的 S3 prefix。
  5. 將 Transfer Family endpoint 提供給合作夥伴。

使用 SFTP client 上傳時,操作方式和一般 SFTP server 相同:

1
2
sftp -i ~/.ssh/partner-key partner@s-0123456789abcdef0.server.transfer.ap-northeast-1.amazonaws.com
sftp> put report.csv /uploads/report.csv

要注意的是,S3 本身沒有真正的目錄階層,SFTP client 顯示的目錄實際上是 object key prefix。chmod、symbolic link 等檔案系統操作,也不一定能對應到 S3。

Transfer Family 適合既有 B2B 檔案交換、固定來源 IP、企業身分驗證或不容易修改的舊系統。若只是偶爾讓單一使用者上傳一個檔案,建置 Transfer Family 往往比 Presigned URL 更複雜,也要評估 endpoint 與資料傳輸成本。

方法 5:Presigned URL

適合前端或第三方客戶端直接上傳,減少後端流量壓力。需要設定合理的過期時間與上傳條件。

1
2
3
4
1. Client 向 Backend 請求上傳授權
2. Backend 驗證身分並產生 Presigned URL
3. Client 使用 URL 直接把檔案 PUT 到 S3
4. S3 Event 通知後續處理流程

產生 Presigned URL 的 IAM principal 必須擁有對目標 object key 的上傳權限。以下 Python 範例建立一個 15 分鐘內有效、只用於指定 object key 的 PUT URL:

1
2
3
4
5
6
7
8
9
10
11
12
13
import boto3

s3 = boto3.client("s3")

upload_url = s3.generate_presigned_url(
    ClientMethod="put_object",
    Params={
        "Bucket": "example-bucket",
        "Key": "uploads/8f6c2f4a/report.pdf",
        "ContentType": "application/pdf",
    },
    ExpiresIn=900,
)

Client 取得 URL 後即可直接上傳:

1
2
3
4
curl --request PUT \
  --header "Content-Type: application/pdf" \
  --upload-file ./report.pdf \
  "<presigned-url>"

如果 Content-Type 被納入簽章,Client 上傳時必須使用相同的 header,否則 S3 會回傳簽章不符。瀏覽器直接上傳時,也要在 bucket 設定允許指定網域與 HTTP method 的 CORS 規則。

Presigned URL 應視為短期的 Bearer Token:拿到 URL 的人,在過期前都能使用它。實作時至少要注意:

  • 由後端決定 bucket 與 object key,不要直接信任使用者提交的完整路徑。
  • 使用 UUID 或 tenant prefix,避免不同使用者覆寫同一個 key。
  • 設定短而合理的有效期限,不要把 URL 寫進公開 Log 或分析工具。
  • 上傳前驗證可接受的副檔名、MIME type 與業務狀態,上傳後再驗證實際內容。
  • 如果需要限制檔案大小或表單欄位,可考慮 Presigned POST 與 policy condition。
  • 大型檔案可進一步使用 Presigned Multipart Upload,讓 Client 分段、平行與重試上傳。

同一個 Presigned URL 在過期前可以重複使用;如果目標 key 已存在,未啟用 Versioning 時可能覆寫原物件,啟用 Versioning 時則會建立新版本。它不是一次性 URL,因此不能只依賴「使用過一次」來保證安全。

共通的安全與維運考量

無論選擇哪一種方法,都應該檢查以下項目:

IAM 最小權限

限制可存取的 bucket、prefix 與操作。只負責上傳的程式通常只需要 s3:PutObject;確實需要查詢、下載或刪除時,再加入 s3:ListBuckets3:GetObjects3:DeleteObject。修改 bucket policy 或 Lifecycle rule 等管理權限,不應交給一般的上傳程式。

避免物件被意外覆寫

S3 的 object key 就是物件識別名稱。同一個 key 再次上傳時可能覆寫原物件;需要保留歷史時,應啟用 S3 Versioning,或使用不可重複的 key。

加密與敏感資料

S3 會自動使用 SSE-S3 加密新上傳的物件。若法規、稽核或權限分離要求使用客戶管理金鑰,可以設定 bucket 預設使用 SSE-KMS,並補上需要的 KMS 權限。

檔案內容不能只相信副檔名

.jpg.pdfContent-Type 都由 Client 提供,不能證明內容安全。外部上傳應先進入隔離 prefix,再透過事件驅動流程進行格式檢查、掃毒或人工審核,確認後才移到正式區域。

大型檔案與未完成上傳

S3 單次 PUT 最多可上傳 5 GB;更大的物件要使用 Multipart Upload,目前單一 S3 object 最大可達 50 TB。Multipart Upload 若未完成,已上傳的 parts 仍會產生儲存費用,應設定 Lifecycle rule 自動清除逾期且未完成的上傳。

小結

沒有單一最佳方案,重點是誰在上傳、檔案多大、是否需要相容既有協定,以及檔案內容是否必須經過後端。

  • 臨時上傳少量檔案:使用 AWS Management Console。
  • 受信任的工程師或 CI/CD:先從 AWS CLI 開始。
  • 小型檔案只需要轉送至 S3:可使用 API Gateway 的 AWS service integration。
  • 小型檔案且必須由後端執行商業邏輯:使用 API Gateway + Backend。
  • 合作夥伴只能使用 SFTP/FTPS:使用 AWS Transfer Family。
  • Web、App 或第三方直接上傳:優先考慮 Presigned URL。

多數面向終端使用者的上傳功能,可以讓後端負責「授權與決定 object key」,再讓 Client 透過 Presigned URL 將檔案直接送到 S3。這通常能在安全、效能與系統複雜度之間取得較好的平衡。


參考資料

本文章以 CC BY 4.0 授權