Study Notes - AWS S3


S3 全名是 Simple Storage Service,故縮寫 S3,它是 AWS 在 2006 年推出的 第二個 SaaS 服務,有很長的歷史。雖然名字有個 Simple,但其實它不容易。本文整理研讀官方文件、以及工作上遇到的問題,整理以下的筆記:

  • 一、基本概念 (Concepts)
  • 二、核心功能 (Core Functions)
  • 三、存取權限 (Access Control)
  • 四、資料保護 (Data Protection)
  • 五、服務限制 (Limitation)
  • 六、開發 (Development)
  • 七、成本 (Cost)
  • 八、應用場景 (User Scenarios)
  • 九、常見問答 (FAQ)

一、基本概念 (Concepts)

整理幾個 S3 的核心概念:

  • Buckets
  • Objects
  • Keys
  • Resions
  • Data Consistency Model

Bucket

Bucket 中文可以翻譯成水桶、籃子,是容器 (Container) 的概念,也就是可以放東西的容器。

在 S3 裡的 Bucket 名稱是 唯一的、而且是全域 (Global)、跨 Account、跨 Region 的,換言之,不管是哪一個 AWS 的使用者,Bucket Name 都不能與其他人重複。雖然 Bucket 名稱是唯一的識別,但是建立 Bucket 時要選擇 Region,表示實際上資料 Region Level 的,換言之,如果在乎存取的延遲時間,就要注意 Region 的位置。

Bucket Name 與 Static WebSite 的關係後面段落詳細說明。

Bucket 名稱的命名規則

底下是 AWS 官方建議的命名注意事項:

  • 命名要符合 DNS 命名規範,例如不可以用底線 (_, underscore)、大寫字母 (uppercase, 2018/03 後)
    • 因為這名稱會被拿區當作 DNS 名稱,DNS 命名不允許有底線。
  • 長度至少 3 個字元,最多 63 個字元
  • 名稱開始要小寫字母或者數字
  • 不要使用 IP address 當作名稱
  • 名稱不要包含點 . 當作段落的切割字元。
    • 目前可以使用,沒有阻擋。
    • 如果要使用 Transfer Acceleration,那 bucket name 不可以包含點

Bucket Name 命名建議格式:{ACCOUNT_NAME}-{REGION}-{PURPOSE}

  • 建議使用 AWS Account Name 做開頭,避免與其他使用者衝突。在 IAM 的首頁可以設定,這個名稱也被當來 IAM Login 的 URL,例如:https://{AWS_ACCOUNT_NAME}.signin.aws.amazon.com/console
  • 例如我的一個 AWS Account Name 叫做 gtlab01,那麼 bucket name 的開頭就是 gtlab01-us-west-2-s3-lab,如此不會與其他人衝突,也可以區分不同 region 的 bucket。
  • 命名格式後面可以自行延伸,主要就是前置 ({ACCOUNT_NAME}-{REGION}) 與切割符號 (我使用 -) 要注意,後面可以延續其他實際的用途,像是環境、服務名稱 … etc.

功能全貌

每個 Bucket 除了儲存的物件之外,都會有三大主要的功能區塊,展開有以下:

  • Properties
    • Versioning: 物件的版本管理
    • Server Access Logging: 存取紀錄
    • Staitc Website Hosting: 靜態資料網站
    • Object-level Logging: 紀錄 API 存取的紀錄,主要配合 CloudTrail
    • Default Encryption: 預設的加密方式
    • Advanced: Object Lock、Tags、Transfer Acceleration、Events、Requester Pays … 等,後面分段描述。
  • Permission: Block Public Access, Access Control List, Bucket Policy, CORS
  • Management: Lifecycle、Replication、Analytics、Metric、Inventory

詳細介紹整理在後面。

Objects

S3 是一個 Object Store,存放在 S3 Bucket 裡的東西都稱為 Object (物件),一個 Object 由以下組成:

  • Key: 有時候會稱 Object Key、Key Name,在 Bucket 裡的唯一識別
  • Version Id: 在 Bucket 裡,Key 和 Version ID 的組成,識別出一個 Object。S3 以此做到 Object Versioning 功能。
  • Value: 就是實際儲存的資料內容。單一資料最大 5TB。
  • Metadata: 是一個 Key-Value 的資料結構,儲存物件的控制資訊。分成 User-definied MetadataSystem-defined Metadata 兩大類。
  • Subresources: 定義 Bucket 與 Object 關係的。
  • Access Control Information

整理下圖描述整個 Object 的組成:

Object Keys

也稱做 Object Key、Key Name,在 Bucket 裡是唯一識別,由 (Prefix + Delimiter) + Key Name 組成。整理概念如下圖:

Prefix 可以想像成目錄 (Folder) 的概念,透過 Delimiter (/) 隔開。以此規則,例如:

  • Bucket Name: www.abc.com
  • Key:
    • dev/design.md
    • dev/seq-flow.md
    • marketing/rel/purchese.pdf
    • index.html

這四個都是 Key,只是 index.html 沒有 prefix,其他則有。在 S3 Console 就會看到目錄的結構。

Version Id

S3 支援 Object 的版本管理,稱為 Versioning。每個物件都有屬於自己的 Version Id 用來區別版本。詳細後面描述。

Object Metadata

Object Metadata 由 Key-Value 組成的資料結構,分成兩個部分: System-defined Metadata (SDM)User-defined Metadata (UDM),整理概念如下圖:

SDM 主要是 S3 用來系統資訊和控制屬性的。系統資訊像是時間、日期、MD5 … 等;控制屬性像是 server-side encryption 的是否開啟、version-id、Storage Class。大概分成可以修改與不可以修改兩大部分。下圖摘自官方文件的詳細列表:

放一個 Object,並指定 UDM:

1
2
3
4
5
6
7
8
9
10
11
12
13
aws s3api put-object \
--acl private \
--body s3-permission-control-flow.png \
--bucket abc-dev-us-west-2-lab-s3 \
--key pic/s3-permission-control-flow.png \
--metadata type=picture,status=release,version=1 \
--tagging date=20170614,team=operation

# return result
{
"ETag": "\"74977eb17855dee8451f477f9exxxxxx\"",
"VersionId": "5iVAfsiL3CLRPq9UAFuTVpxiwxxxxxx"
}

取得 Object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
aws s3api head-object \
--bucket abc-dev-us-west-2-lab-s3 \
--key pic/s3-permission-control-flow.png

# return result
{
"AcceptRanges": "bytes",
"LastModified": "Fri, 14 Jun 2019 06:43:51 GMT",
"ContentLength": 175470,
"ETag": "\"74977eb17855dee8451f477f9exxxxxx\"",
"VersionId": "5iVAfsiL3CLRPq9UAFuTVpxiwxxxxxx",
"ContentType": "binary/octet-stream",
"Metadata": {
"version": "1",
"status": "Release",
"type": "picture"
}
}

User-defined Metadata 的資料會在 HTTP Header x-amz-meta-{UDM_NAME} 呈現,例如上述範例就會產生 x-amz-meta-version 這樣的 header.

Storage Classes

儲存在 S3 上的物件,依照使用情境與需求,分成幾種 儲存類型 (Storage Classes),這些類型也會反映在 SLA (可用性、持久性)成本效能之上。下表是 官方文件 的提供的資訊:

Regions

建立 Bucket 的時候,除了名稱要考慮唯一性之外,也要選擇 Bucket 的位置。官方文件描述,只要物件存在 Region 之內,就不會再離開,除非使用者自行傳輸到其他地方。所以當應用程式需要考量傳輸效能時,在規劃 Bucket 時也要同時考慮地理位置,避免因為網路傳輸的問題,影響效能。

Data Consistency Model (資料一致性模式)

  • 所有的 Region 的支援 PUTS and DELETES 操作的 最終一致性模型
  • 寫入新的 Object 而且立刻 list bucket: 新的 Object 不會顯示在 list ,直到更改傳遞到所有的 servers
    • PUTS: read-after-write consistency
  • 更新既有的物件,同時立刻讀取:S3 可能會傳回前一個物件,直到更改傳遞到所有的 servers
  • 刪除既有物件,同時立刻讀取:S3 可能回傳要刪除的物件,直到更改傳遞到所有的 servers
  • 刪除既有物件,同時 list bucket 裡的 keys: S3 可能還是會顯示刪除的 object,直到更改傳遞到所有的 servers
  • 目前 S3 不支援 Object Locking

下表描述 Eventually Consistent Read (最終一致性讀取) & Consistent Read (一致性讀取) 的差異:

更多關於 最終一致性 的概念,參閱 Eventually Consistent 與 Dynamo NWR 模型


二、核心功能 (Core Functions)

S3 除了存資料之外,有很多因應而生的功能,這些功能都很實用,也是很多人選擇 S3 的主因。

以下整理一些我個人認為的核心功能,我把他們分成兩大類:

  • 應用功能:應用服務使用的功能,主要是提供 Feature、創造價值,屬於進攻。
  • 管理功能:維運管理功能,主要是針對資安、節省成本,屬於防守。

Static Website Hosting

有以下幾種方法可以讓 S3 當作靜態網頁服務:

  1. 使用 S3 Bucket 的 Static Website Hosting 功能 (沒有 HTTPS)
  2. 整合 Route 53 Alias + S3 Bucket (沒有 HTTPS)
  3. 整合 CloudFront + Route 53 Alias + S3 Bucket (有 HTTPS)

S3 Bucket + Route53

  1. 建立 S3 Bucket
    • 使用 Domain Name 當作 S3 Bucket Name,例如:website1.abc.com,此例子放在 us-west-2
    • 開啟 Static Website Hosting 功能,一定要開啟,否則功能不會正常(如下訊息)。
    • 權限:
      • 關閉 Block public access,預設是開啟的。因為太多資安事件,後來新增的預設功能。
      • 用 Bucket Policy 或 Object ACL ,後面描述
    • 放一個 index.html
  2. 設定 Route 53
    • 新增一筆 A Record
    • 開啟 Alias,選擇已經建立好的 S3 Bucket,或者填入:s3-website-us-west-2.amazonaws.com.。 如果 AutoComplete 沒有 S3 Bucket 可以選,表示沒有開啟 Static Website Hosting,如果已經開啟卻沒得選,重新載入 Route53 Console。如下圖:
  3. 權限設定:要讓使用者可以瀏覽靜態資料

    • Bucket Policy:好處是 Object 上傳後,不需要額外的權限設定。底下是範例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::website1.abc.com/*"
      }
      ]
      }
    • Object ACL:開啟個別 Object 的 Permission,方法有以下:

      • 在 S3 Console,選擇 Object -> “Make Public”
      • 在 S3 Console:點選 Object -> 右邊 Properties -> Permission -> Public access -> 開啟 Read Object
      • 透過 SDK / API 操作(如下),指定 ACL 為 public-read
        1
        2
        3
        4
        5
        6
        7
        aws s3api put-object \
        --acl public-read \
        --body s3-permission-control-flow.png \
        --bucket website1.abc.com \
        --key images/s3-permission-control-flow.png \
        --content-type image/png \
        --content-disposition "inline; filename=s3-permission-control-flow.png"

權限兩種方法都可以,如果要安全性高一點,選擇 Object ACL 控制,透過程式控制;如果是開放資料,像是文件,則可以使用 Bucket Policy 控制。

Endpoints of Path-Style and Virtual-Hosted Style

S3 支援兩種存取格式的 Endpoints,格式如下:

  1. Path-Style (v1):
    • Bucket in us-east-1: https://s3.amazonaws.com/{BUCKET_NAME}/{OBJECT_KEY_NAME}
    • Bucket in other regions: https://s3-{REGION_CODE}.amazonaws.com/{BUCKET_NAME}/{OBJECT_KEY_NAME}
  2. Virtual-Hosted Style (v2)
    • Bucket in us-east-1: 同下
    • Bucket in other regions: http://{BUCKET_NAME}.s3-website-{REGION_CODE}.amazonaws.com/{OBJECT_KEY_NAME}

為了方便說明,我建立兩個 Bucket 當範例:

  1. website.abc.com -> region 在 us-east-1 (N. Virginia)
  2. website1.abc.com -> region 在 us-west-2 (Oregon)

Path-Style 是第一代 (1) 的格式,選擇一個 Object,下圖是 Overview,這是放在 Virginia 的 Object URL:

下圖是放在 Oregon 的 Object URL,有包含 REGION_CODE: us-west-2

不難發現,Path-Style 就是以 Region 為主要的 Hostname,然後把 Bucket Name 當作 URL 路徑看待,而且支援 HTTPS。另外 Virginia 因為是第一個 region,所以預設的 S3 Domain Name 就是給他用,其他則有個別的 Domain Name.

Virtual-Hosted Style 是第二代 (v2) 的格式,主要就是以 Bucket Name 作為 Hostname。同樣的用 us-east-1、us-west-2 做範例,如下圖,在 Bucket -> Properties -> Static Website Hosting 找存取的 Endpoint:


要注意的是:Path-Style 支援 HTTPS,但是 Virtual-Hosted Style 並不支援,如果要 HTTPS 需要依賴 CloudFront。

相關新聞:

Event Notifications

S3 支援 Events 功能,屬於 Bucket Level 設定,透過 Notification 達到事件處理的功能。

每個 Event 由以下組成:

  • Name: 顯示用名稱,不是 Key / Id,可以修改
  • Event Types: 分成 Create、Remove、Others 三大類
  • Filter: 依據 Prefix、Suffix 為過濾條件,例如 prefix=images/suffix=jpg
    • PUT, prefix=images, suffix=jpgPUT, prefix=images/, suffix=txt 是不同的條件。
    • 注意 filter 條件不能重複
  • Destinations: 處理,支援 SNS, SQS, Lambda

Events Types (Action) 包含以下:

  • Create an object:
    • s3:ObjectCreated:*
    • s3:ObjectCreated:Put|Post|Copy|CompleteMultipartUpload
    • 如果上傳失敗,不會收到 failed operation
  • Remove an object:
    • s3:ObjectRemoved:*
    • s3:ObjectRemoved:Delete|DeleteMarkerCreated
    • 透過 lifecycle 刪除,或者刪除失敗不會收到 failed operation
  • Others:
    • restore objects: s3:ObjectRestore:Post, s3:ObjectRestore:Completed
    • s3:ReducedRedundancyLostObject

設定好 Event 之後, 觸發後 S3 會送出這樣的 Message:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"Records":[
{
"eventVersion":"2.1",
"eventSource":"aws:s3",
"awsRegion":"us-west-2",
"eventTime":The time, in ISO-8601 format, for example, 1970-01-01T00:00:00.000Z, when Amazon S3 finished processing the request,
"eventName":"event-type",
"userIdentity":{
"principalId":"Amazon-customer-ID-of-the-user-who-caused-the-event"
},
"requestParameters":{
"sourceIPAddress":"ip-address-where-request-came-from"
},
"responseElements":{
"x-amz-request-id":"Amazon S3 generated request ID",
"x-amz-id-2":"Amazon S3 host that processed the request"
},
"s3":{
"s3SchemaVersion":"1.0",
"configurationId":"ID found in the bucket notification configuration",
"bucket":{
"name":"bucket-name",
"ownerIdentity":{
"principalId":"Amazon-customer-ID-of-the-bucket-owner"
},
"arn":"bucket-ARN"
},
"object":{
"key":"object-key",
"size":object-size,
"eTag":"object eTag",
"versionId":"object version if bucket is versioning-enabled, otherwise null",
"sequencer": "a string representation of a hexadecimal value used to determine event sequence,
only used with PUTs and DELETEs"
}
},
"glacierEventData": {
"restoreEventData": {
"lifecycleRestorationExpiryTime": "The time, in ISO-8601 format, for example, 1970-01-01T00:00:00.000Z, of Restore Expiry",
"lifecycleRestoreStorageClass": "Source storage class for restore"
}
}
}
]
}

問題:

Q: 同一個 Event,支援同時多種 Destinations?

問題可以改成同一個 Event 的 Filter,可否支援多個 Dest?透過 SNS 就可以做到,也就是 Pub/Sub Fanout 的功能。。

Q: 同一個檔案,重複 Put,S3 會發 Event?

實測過:會。

Q: 刪除不存在的 Object,會重複驅動 Event?

實測過:不管有無開啟 Versioning 都會收到 Event,只是 EventName 會有所差異:ObjectRemoved:DeleteObjectRemoved:DeleteMarkerCreated

Q: 如果擔心 S3 Event 有遺漏,該如何確認?

依照官方文件,以及實測的經驗,遺漏的機率很小,但如果真的需要檢驗方式,可以透過 Inventory 功能。假設上傳後儲存到 S3 沒問題,問題會發生的是在 S3 發動 Event 這個過程。相關文件:

Q: 能否控制 S3 發送 Event 的速率?

目前只能透過 Lambda Concurrency 控制。實測以下的狀況:

  • Lambda Concurrency=3
  • 短時間 (< 5m) 之內,上傳約 1300 個圖檔
    觀察 Lambda ConcurrentExecutions 的狀況,以及 Invocations 的總和

Q: Lifecycle 刪除的檔案會發動 Event?

不會。

Q: 哪裡可以監控 Event 發動的狀況?

目前只能從 Destination 端的 Metric 監看,像是 Lambda 的 Invocations、SQS 的 Invocations、SNS 的 NumberOfMessagesPublished 等。

Q: Event 是發生在 S3 Action 前、還是後?

我也想知道。

Lifecycle Management

Bucket Level 的功能,主要用途是透過 條件 + 轉換 + 過期

  • 條件 (Rule):Prefix 或者 Tags
  • 轉換 (Transition):
    • 針對目前的版本或者前一些版本
    • 在 n 天之後,把 Object 轉換成指定的 Object Class
  • 過期 (Expiration):
    • 針對目前的版本或者前一些版本
    • 在 n 天之後完全刪除,或者把 MarkDelete 的刪除
    • 刪除未完成的 multipart upload

是非常實用的維運功能,經常使用的就是

  • 刪除 n 天之前的備份資料
  • 把轉換 n 天之前 Object 放到 Gliacier (磁帶)

Monitoring

監控 S3 的方法有很多,主要還是以 CloudWatch 為主。在 Bucket Level 的設定 -> Management -> Metrics 直接把 CloudWatch Metric 整合了。分成 Storage、Request、Data Transfer 三大部分。其中 Storage 預設是開啟的,Requests、Data Transfer 是另外要付費的。

另外可以透過 Filter 的方式,針對 Prefix、Tags 過濾想要監控的資訊。

除了 CloudWatch 的監控,AWS 還有其他服務可以做更細緻的監控,列舉如下:

  • S3 Server Access Logs:S3 自身的 Access Logs。
  • Trusted Advisor:成本、資安
  • AWS Config Rules:程式化、自動化
  • Amazon Macie:機器學習的安全服務,可以找到敏感資料、個資 … 等。
  • CloudTrail:AWS 本身的 Audit Log

Others

其他本文尚未整理的功能。

  • Analytics: Data Lake (Athena, Redshift, QuickSight), IoT Streaming Data, Machine Learning and AI Storage, Storage Class Analysis
  • Access Log
  • Cross-Region Replication
  • Tags
  • Batch
  • Transfer Acceleration: Spped up data uploads using CloudFront in reverse.
  • BitTorrent

三、存取權限 (Access Control)

S3 存取的授權方式有兩種:Resource-based policiesUser Policies。底下整理自 Overview of Managing Access

Resource-based Policies

概念如下圖 (取自 官方文件),分成針對 Bucket 的 Bucket PolicyBucket ACL,以及針對 S3 Object 的 Object ACLs

Bucket ACLs / Object ACLs: 每個 Bucket 和 Object 都有一個 ACL 的關聯。ACLs 用來針對特定 識別 發放權限。像是可以發放給另一個 AWS Account 權限。可以透過設定 Account Canonical User ID ,讓另一個帳號可以存取 Bucket(但是不會在 Bucket List 上出現)。可設定的資訊如下:

  • Canonical User ID: 是個 Long String,大概像這樣:7ae3d7f85d42d21d250ff1c13b3b8ec92189bedbd648252984ba6526a3b071d1,可以在 S3 Bucket ACL 裡找到。
  • Bucket ACLs:
    • List Objects、Write Objects、Read Bucket Permissions、Write Bucket Permissions
  • Object ACLS:
    • Read Objects、Read Object Permissions、Write Object Permissions
    • 注意:沒有 Write Objects

Bucket ACLs 以 XML 呈現,新版的 S3 Console 透過 GUI 設定即可。舊版的 Console 則需要自行設定 XML,格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>*** Owner-Canonical-User-ID ***</ID>
<DisplayName>owner-display-name</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="Canonical User">
<ID>*** Owner-Canonical-User-ID ***</ID>
<DisplayName>display-name</DisplayName>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>

Bucket Policy: 主要發放權限給 AWS Account 或者 IAM Users,整個 Bucket 與 Object 都會應用 Policy。Policy 的設定同 IAM Policy 的設計,每個 Statement 主要有必要的 Effect、Principal、Action、Resource 以及選擇性的 Condition。

Principal 用來授權給哪一個 AWS Account 或者 特定的 Canonical User ID。AWS Account 使用的就是 ARN 格式,例如:

1
2
3
4
5
6
"Principal": {
"AWS": [
"arn:aws:iam::AccountNumber-WithoutHyphens:root",
"arn:aws:iam::AccountNumber-WithoutHyphens:user/user1"
]
}

Canonical User ID 範例:

1
2
3
"Principal": {
"CanonicalUser": "64-digit-alphanumeric-value"
}

Condition 通常用來篩選條件,像是控制來源 IP、特定的 http header … etc。底下範例是授權特定來源 IP 存取的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::examplebucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "192.168.143.0/24"
},
"NotIpAddress": {
"aws:SourceIp": "192.168.143.188/32"
}
}
}
]
}

User policy

這個 User 指的是 AWS IAM,包含 IAM users、groups、roles,概念如 官方文件 的圖:

IAM 相關概念請參閱 Study Notes - Identity and Access Management (IAM) 的整理

S3 如何處理授權請求?

官方文件: How Amazon S3 Authorizes a Request 針對 Bucket Operation 和 Object Operation 有兩張圖,比較複雜,下圖是我自己簡化的整理。主要以 IAM User 的角度出發,分成三個驗證步驟:

  1. 確認是否符合 Bucket ACL,主要確認是不是 CanonicalUser
  2. 是否符合 Bucket Policy 的條件,預設 Bucket Policy 是空的。
  3. 如果 2) 不符合,那麼看看是否符合 IAM Policy


四、資料保護 (Data Protection)

資料保護分成資料加密 (Data Encryption) 以及版本控管 (Versioning) 討論。

Data Encryption

S3 的資料加密分成以下種:

  • Server-Side Encryption (SSE): 由 Server-Side 負責加密後寫入儲存體,加密過程的運算資源、加密演算法都由 Server-Side 提供。
    • SSE-S3:全名是 Server-Side Encryption with Amazon S3-Managed Keys。加密過程使用的 Data Key 與 Master Key 都由 S3 管理,不需要自行管理,Master Key 則會定期更新 (Rotation)。S3 使用 256-bit Advanced Encryption Standard (AES-256) 加密。
    • SSE-KMS:顧名思義就是使用 KMS 的 CMKs (Customer Master Keys) 加密 S3 Object。KMS 會負責管理 Data Key。
    • SSE-C: 全名是 Server-Side Encryption with Customer-Provided Keys,由使用者提供 Encryption Key 作加密。
  • Client-Side Encryption (CSE)
    • Client-Side (PGP, GPG)

以下整理 SSE 三種的差異:

Versioning

S3 Bucket Level 支援版本管控,亦即每個物件都可以有版本的概念。S3 Object 由 Key + VersionId + Metadata + Value 組成。其中 VersionId 就是用來代表版本概念的關鍵屬性。

做了實驗:

  1. 上傳一個檔案
  2. 同一個檔案,再上傳一次
  3. 刪除檔案
  4. 同一個檔案,再上傳一次
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
FILENAME="IMG_0001.JPG"
BUCKET_NAME="dev-us-west-2-lab-s3"

## 1. 上傳一個檔案
aws s3api put-object \
--acl private \
--body ${FILENAME} \
--bucket ${BUCKET_NAME} \
--key pic/${FILENAME}

## 2. 同一個檔案,再上傳一次
aws s3api put-object \
--acl private \
--body ${FILENAME} \
--bucket ${BUCKET_NAME} \
--key pic/${FILENAME}

## 3. 刪除檔案
aws s3api delete-object \
--bucket ${BUCKET_NAME} \
--key pic/${FILENAME} \

## 4. 同一個檔案,再上傳一次
aws s3api put-object \
--acl private \
--body ${FILENAME} \
--bucket ${BUCKET_NAME} \
--key pic/${FILENAME}

結果如下圖:

觀察到的現象:

  1. S3 不會比對檔案來源,同樣的檔案會產生不同的 VersionId
  2. 被蓋過去的檔案,可以下載

Q: 如何指定特定的 VersionId 為 Latest Version?

目前的方法只能指定 VersionId ,然後重新上傳該物件,把物件改掉。

Q: 被標記 Delete Marker 可以下載?

實測結果不行。


五、服務限制 (Limitiation)

Bucket Restrictions and Limitation


六、開發 (Development)

S3 每個 bucekt 除了提供 static website hosting 的功能,也提供了 REST API 給開發者使用。REST API for bucket 規則如下:

  • Path-Style:
    • us-east-1: https://s3.amazonaws.com/{BUCKET_NAME}/
    • other regions: https://s3-{REGION_CODE}.amazonaws.com/{BUCKET_NAME}/
  • Virtual-Hosted Style: https://{BUCKET_NAME}.s3-{REGION_CODE}.amazonaws.com
    • 要注意的是,名字不是 s3-website-{REGION_CODE}

權限的設定如下:

  • 關掉 Block Public Access
  • 開啟 Bucket ACL 的 List Object

不需要開啟 Static Website Hosting

例如 bucket name 叫做 website.abc.com,那就可以透過 https://website.abc.com.s3-us-west2.amazonaws.com 存取,下圖是 Path-Style 和 Virtual-Hosted Style 的範例:



七、成本 (Cost)

S3 的成本分成幾個部分:儲存費用、請求費用、資料傳輸、S3 Transfer Acceleration、跨區複寫

儲存費用

Storage Classes: 依照儲存的類型,有不同的成本價錢,不同 region 也會有不同的定價。底下以 Oregon 做範例整理。下圖是 S3 Standard Class 的價錢,分成三個區段:

下圖是其他 Storage Classes 比較表:

下圖各種 Storage Classes 成本比例分析表:

請求成本

依照 REST 的請求,以及資料傳輸,費用會有所差異。計費考量的面相有以下:

  • 操作:PUT、COPY、POST、GET、SELECT 請求,其中 DELETE、CANCEL 是不用費用的。
  • 透過 S3 功能 (Select) 取得的資料傳輸費用

依照 Storage Classes,分成不同價錢,傳輸的資料也有不同價錢。


八、應用場景 (User Scenarios)

應用場景我分成兩大類:解決方案、功能特性。解決方案通常會整合其他 AWS Services,整體也比較複雜;功能特性會著重在 S3 自身的功能應用。

  • 功能特性
    • 大量上傳
    • Pre-signed URL
    • 在 EC2 使用 S3 當作延伸磁碟
    • 如何跨帳號存取 S3 Bucket
  • 解決方案 (Solution)
    • 靜態資料傳遞:搭配 CloudFront
    • 非同步批次處理:搭配 Lambda
    • Log 儲存與分析:搭配 Kinesis Firehose、Athena
    • 跨區資料備份與同步

跨帳號存取 S3 Bucket

AWS Account A 有一個 Bucket 叫做: Acc-A-Bucket1,AWS Account B 有個 User 叫做 user1,想要存取此 Bucket。

  1. 取得 Account B 的 Canonical User Id,然後到 Acc-A-Bucket1 Permissions -> ACLs -> Access for other AWS accounts,加入 CU ID.
  2. 驗證:使用 user1 的 profile 下 CLI

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    ## List Bucket and Object
    ~$ aws s3 ls s3://Acc-A-Bucket1/
    2019-06-10 22:53:22 0
    2019-06-10 22:53:52 38201 AccessControlAuthorizationFlowBucketResource.png
    2019-06-10 22:53:52 50491 AccessControlAuthorizationFlowObjectResource.png
    2019-06-10 22:53:58 1410705 Amazon-S3.png
    2019-06-10 22:53:52 23472 resource-based-policy.png
    2019-06-10 22:53:51 18793 user-policy.png

    ## 複製檔案:無法存取
    ~$ aws s3 cp s3://Acc-A-Bucket1/user-policy.png .
    fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
  3. 設定 Acc-A-Bucket1 的 Bucket Policy,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Principal": {
    "AWS": "arn:aws:iam::1234567890123:user/user1"
    },
    "Action": "s3:*",
    "Resource": "arn:aws:s3:::Acc-A-Bucket1/*"
    }
    ]
    }
  4. 驗證:使用 user1 的 profile 下 CLI:

    1
    2
    ~$ aws s3 cp s3://Acc-A-Bucket1/user-policy.png .
    download: s3://Acc-A-Bucket1/user-policy.png to ./user-policy.png

結論:

  • 跨帳號授權,必須在目標 Bucket 上設定同時 ACL 與 Bukcet Policy
  • 原 IAM USer 的 IAM Policy 不需要額外設定權限。

在 EC2 使用 S3 當作延伸磁碟

這是很多人一開用 S3 想到的,底下整理著名的工具:

剛開始用 S3 就用找過類似的,但因為 S3 的資料模型關係,往往使用體驗不如預期,所以大部分我不會建議這樣使用。

Bucket List

有時候需要提供列出檔案下載的功能,類似於 Apache Index,可以利用 Bucket ACL + CORS 達到此功能。設定如下:

  • 設定 Bucket ACL,允許 Read Object
  • 設定 CORS 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    </CORSConfiguration>
  • 開啟 Static Website Hosting

  • 下載: https://github.com/rufuspollock/s3-bucket-listing ,設定 index.html 如下:

    1
    2
    3
    4
    5
    <script type="text/javascript">
    var S3BL_IGNORE_PATH = true;
    var BUCKET_URL = 'https://{BUCKET_NAME}.s3-{REGION_CODE}.amazonaws.com';
    </script>
    <script src="/list.js"></script>
  • 瀏覽網站,可以看到如下畫面:


九、常見問答 (FAQ)

Q: 使用 S3 當靜態網站,能支援 HTTPS?

目前 S3 website endpoint 不支援 HTTPS,通常會搭配 CloudFront + ACM。參見 Website Endpoints

Q: 使用 S3 當靜態網站,能限定來源 IP?或者特定 VPC?

可以,Bucket Policy 範例參閱: Example Bucket Policies for VPC Endpoints for Amazon S3

Q: S3 可以當 SFTP 站嗎?

自幹可以用 s3fs-fuse mount s3 bucket,然後開 ftp server,也可以直接用 AWS 的 Transfer for SFTP Service,好處不用開機器、直接用 S3,不過有點貴就是了。

Q: S3 的授權有分 Resource-based Policy 和 User Policies,應該使用哪一種存取方法?

好問題,AWS re:Invent 2018: Deep Dive on Amazon S3 Security and Management 有回答這問題,截圖如下:

Q: 如果沒有給 IAM Policy 的權限,但有 Bucket Policy,那麼同一個 Account 底下的 IAM User 可以存取 Bucket?

可以。底下是一個 Bucket Policy 範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::123456689012:user/user1",
"arn:aws:iam::123456689012:user/user2"
]
},
"Action": [
"s3:GetObject",
"s3:GetBucketLocation",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::image.abc.com/*",
"arn:aws:s3:::image.abc.com"
]
}
]
}

Q: CloudFront 與 S3 整合的時候,需要開啟 Static Website Hosting?

不用,但要使用 Object ACL or Bucket Policy,如下:

  • Object ACL: 允許 Public Read
  • Bucket Policy: 允許 GetObject

這兩種選一種就好,然後 Block public access 要關掉。

Q: S3 Bucket 做 Static Web Hosting,可否限制特定網站存取?

可以。確認 Browser 送出的 Request 會包含 http referer,然後透過 Bucket Policy 的 Condition,限制 Referer 的 Domain Name 即可,底下範例是首頁放在 bucket www.abc.com,圖檔放在 bucket image.abc.com,這個 Bucket Policy 設定在 image.abc.com:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"Version": "2012-10-17",
"Id": "image.abc.com",
"Statement": [
{
"Sid": "Allow get requests originating from www.abc.com and abc.com.",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::image.abc.com/*",
"Condition": {
"StringLike": {
"aws:Referer": [
"http://www.abc.com/*",
"http://abc.com/*"
]
}
}
}
]
}

Q: AWS CLI 提供 s3 和 s3api,這兩個有什麼差別?

s3 是 high-level commands,s3api 則是 low-level commands,差異就是可控性。想要控制細緻的參數,像是 max_concurrent_requests、max_queue_size、max_bandwidth、multipart_threshold … 等效能的調教與除錯,那麼就要使用 s3api,詳細的配置參閱 AWS CLI S3 Configuration

Q: Virtual-Hosted Style 提到 S3 Bucket Name 會變成 Hostname,如果名稱有很多點 . 會不會有問題?

實測 bucket name: a.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9.0.1.2.3.4.5.6.7.8.9.0.1,長度 63,結果是可以運行的,如下圖。依據 wikipeida 上對 DNS 的描述,節點數最多可以到 127 個,但是這個規範並沒有被定義在 RFC 裡。

Q: 有一些 AWS 服務建立的 Bucket (elasticbeanstalk-ap-northeast-1-{AWS_ACCOUNT_ID}) 無法刪除,可以刪?

找到 Bucket Policy,應該會看到類似以下的 Policy,刪除即可。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "eb-ad78f54a-f239-4c90-adda-49e5f56cb51e",
"Effect": "Allow",
"Principal": {
"AWS": "AROAILKGB6ZL4XGFxxxxxx"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::elasticbeanstalk-us-east-1-123456789012/resources/environments/logs/*"
},
{
"Sid": "eb-58950a8c-feb6-11e2-89e0-0800277d041b",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:DeleteBucket",
"Resource": "arn:aws:s3:::elasticbeanstalk-us-east-1-123456789012"
},
{
"Sid": "eb-af163bf3-d27b-4712-b795-d1e33e331ca4",
"Effect": "Allow",
"Principal": {
"AWS": [
"AROAILKGB6ZL4XGxxxxxx",
"AROAI3S3HFNQTDLxxxxxx"
]
},
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::elasticbeanstalk-us-east-1-123456789012",
"arn:aws:s3:::elasticbeanstalk-us-east-1-123456789012/resources/environments/*"
]
}
]
}


結語

越是有歷史的,表面看起來越是簡單的,背後越是有學問。AWS 每年 reInvent 都增加很多新服務,幾年下來數量翻倍的成長,但是實際上,還是圍繞在核心服務的所組合出來的應用架構。核心服務像是 EC2、S3、SQS、VPC、EBS、RDS、API Gateway、CloudFront、ELB、DynamoDB、CloudWatch、AutoScaling … 這些構成了整個 AWS 服務的生態系。深度的學好這些基礎服務的概念,對於學習其他服務會很有幫助。


延伸閱讀

站內延伸

官方文件

Deep Dive and Whitepapers

S3 新功能 (New Feature)

  • 2019/04/30: Amazon S3 Introduces S3 Batch Operations for Object Management
  • 2018/12/04: Amazon S3 Inventory adds Apache Parquet output format
  • 2018/11/27: AWS Announces Amazon S3 Object Lock in all AWS Regions
  • 2018/11/26: Announcing S3 Intelligent-Tiering — a New Amazon S3 Storage Class
  • 2018/11/15: Introducing Amazon S3 Block Public Access – another layer of protection for your accounts and buckets
  • 2018/09/05: Amazon S3 Announces New Features for S3 Select
  • 2018/08/08: Amazon VPC Flow Logs can now be delivered to S3
  • 2018/07/18: Amazon S3 Announces Increased Request Rate Performance
  • 2018/04/30: Amazon S3 Adds Support for Amazon Glacier and S3 One Zone-Infrequent Access to Amazon CloudWatch Storage Metrics
  • 2018/04/05: Amazon S3 Select Is Now Generally Available
  • 2018/04/05: Announcing S3 One Zone-Infrequent Access, a New Amazon S3 Storage Class

更新紀錄

  • 2019/06/11: 重構文章結構,分成數個部分。
  • 2017/09/03: 更新 S3 + CloudFront 整合

Comments