幫你的 S3 Bucket 掛上 Cloudflare CDN

程式技術
幫你的 S3 Bucket 掛上 Cloudflare CDN

前幾天看到有大大在臉書上分享了一個慘烈的案例。內容是說他的客戶在 GCP (Google Cloud Platform) 上的公開儲存空間被 DDoS 攻擊,上面的某個檔案在兩天內被下載了數億次。因為訪問雲端儲存空間的流量是要計費的,所以即使只有短短兩天,還是產生了高達 1 萬美金的鉅額費用。😳

這樣的案例其實並不是第一次發生,之前 AWS 也發生過類似的事情。基本上所有公有雲的儲存服務都會對訪問的流量計價。也就是說,如果你有一個公開的雲端儲存空間,而且裡面有存放檔案,那麼只要有人想,他就可以讓你的帳單直接爆炸。

AWS 有一個非常離奇的案例。有一位用戶的 S3 Bucket 名稱,恰巧與某款熱門免費工具預設的資料備份 S3 Bucket 名稱相同,結果導致許多使用該工具的人,在未修改預設設定的情況下,會嘗試將資料寫入這位用戶的 S3 Bucket,雖然寫入會因為沒有權限而失敗,但大流量還是讓這位用戶因此收到了高達 1300 美金的帳單。

這件事情最離奇的點,是嘗試對沒有權限的 Bucket 寫入資料是會計價的!目前這個問題已經被 AWS 修復。

那麼有什麼方法可以避免自己的公開儲存空間被 DDoS 呢?案例分享下方的留言,就有不少人提到可以藉由掛上 CDN (Content Delivery Network) 來避免產生巨額費用。不過這個解決辦法可能只適用於佛心廠商 Cloudflare,Cloudflare 的 CDN 服務除了是免費的,還提供對 DDoS 一定的保護,對小網站來說非常夠用。

然而大部分廠商提供的 CDN 服務,例如 AWS Cloudfront 或是 Azure CDN,這些服務也還是要根據流量收費的。所以說如果想要完全避免 DDos 所造成的負面影響,最好的辦法還是課金,除了掛上 CDN,還要搭配 WAF (Application Firewall) 來過濾掉異常的流量。

WAF 對小網站來說,有點殺雞用牛刀了 (還有就是太貴)。如剛剛所說,小網站簡單的掛上 Cloudflare 就行。下面就來簡單的分享如何幫 S3 Bucket 掛上 Cloudflare 的 CDN。

幫你的 S3 Bucket 掛上 Cloudflare CDN

如果想要將你的 S3 Bucket 掛上 CDN,首先你必須要有一個自己的網域,並將這個網域交由 Cloudflare 託管。

以我擁有的 docfunc.com 網域為例,假設我想建立一個 S3 Bucket 用來存放我個人的檔案,可以怎麼做?

首先先到 S3 上面建立一個 Bucket,地區我選在 us-west-2,名稱我設定為 files.docfunc.com

2024_11_16_09_15_45_9c236374d7e5.png

Bucket  的設定記得關閉 Block Public Access settings for this bucket,讓Bucket 是可以被公開訪問的。

2024_11_16_09_16_09_77718c57e4b0.png

調整完設定後,就可以開始建立 Bucket。需要注意的是,Bucket 建立好之後還不是公開的狀態。我們需要設定 Bucket Policy 來允許所有人訪問。

前往 Bucket 的頁面,找到 Permissions 下的 Bucket Policy 設定,將其修改為以下內容,就可以開放 Bucket 的訪問權限。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAccessFromEveryone",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::files.docfunc.com/*"
    }
  ]
}

修改完 Bucket Policy 後,可以嘗試上傳一個圖片上去,看看能否透過 S3 的網址來訪問剛剛上傳的圖片,此時可以注意一下圖片的 S3 網址長什麼樣子。如果你之前有建立過 Bucket,你應該會注意到這個 S3 網址格式似乎有點特別。

2024_11_16_08_52_49_aa9c0643341f.png
網址好像有點特別?

如果你的 Bucket 名稱並不是網域的格式,那麼圖片的 S3 網址應該會長這樣:

https://<BUCKET_NAME>.s3.<AWS_REGION>.amazonaws.com/...

我們剛剛建立的 Bucket 名稱是網域的格式,所以圖片的 S3 網址會長這樣:

https://s3.<AWS_REGION>.amazonaws.com/<BUCKET_NAME>/...

發現差別了嗎?😁

接下來到 Cloudflare 的主控台幫這個 Bucket 掛上 CDN。在 docfunc.com 這個網域底下新增一個名稱為 files.docfunc.com 的 CNAME 記錄,並將其指向 s3.<AWS_REGION>.amazonaws.com 網域。

CNAME 記錄全稱為真實名稱記錄 (Canonical Name Record),用來用於將一個域名映射到另外一個域名 (真實名稱)。

如果你想讓多個域名對應到同一個 IP,CNAME 紀錄會非常方便。

假設你想讓 blog.example.comwww.example.com 都指向 example.com 背後對應的 IP,那麼就可以在 blog.example.comwww.example.com 上面新增一個 CNAME 紀錄指向 example.com。如果 IP 需要更動,那麼只需要修改 example.com 的 A 紀錄即可。

2024_11_16_00_23_47_8a7f522ea8c2.png

注意 CNAME 紀錄的網址必須要與 Bucket 名稱完全相同。

設定好 CNAME 紀錄之後,嘗試用 files.docfunc.com 這個網域訪問剛剛的圖片。如果你成功看到圖片,就代表你已經成功的幫 S3 Bucket 掛上 Cloudflare 的 CDN了!

2024_11_16_08_54_21_9037825321d9.png
換網址後又能看到小八了 (實際上是兔兔)

等一下!還沒結束!

原本 S3 的網址,此時還是可以訪問的。如果 DDoS 攻擊還是走你原本 S3 的網址,那麼掛上 CDN 也沒用。因此我們要修改 Bucket Policy,只允許 Cloudflare 的 IP 能夠訪問你的 Bucket

修改一下 Bucket Policy,使用 Condition 來限制來源 IP。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAccessFromCloudflare",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::files.docfunc.com/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "2400:cb00::/32",
            "2606:4700::/32",
            "2803:f800::/32",
            "...以下省略其他 IPv6 CIDR",
            "173.245.48.0/20",
            "103.21.244.0/22",
            "103.22.200.0/22",
            "...以下省略其他 IPv4 CIDR"
          ]
        }
      }
    }
  ]
}

修改完 Bucket Policy 後再次訪問原本 S3 的網址,就會看到訪問被阻擋了。

2024_11_16_08_55_53_cdb7da0875cc.png

除了掛上 Cloudflare CDN,同時也建議開啟預算告警 (Budget Alert)。當費用超過預先設定的預算上限時,可以讓雲端廠商寄信通知我們,好讓我們在第一時間反應。

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言
新增留言
編輯留言