Amazon CloudFront 也可以設定要簽名才能抓檔案,只是 URL Sign 設計的觀念跟 Amazon S3 完全不一樣,這不一致的調調很... 詭異...
大致上有這些差異:
- Amazon S3 用的是 HMAC-SHA1 的機制簽名 (shared secret,也就是 Amazon S3 與你都有同一把 key),而 Amazon CloudFront 則是用 RSA key 簽名 (public key,也就是 Amazon CloudFront 存放 public key,你自己存放 private key)。
- 也因為是使用 RSA key,有人會誤解跟 Amazon EC2 用的 RSA key 相同。但實際上需要在 Security Credentials 頁裡設,有專門對 Amazon CloudFront 用的 RSA key 的段落。
- 自己對 Base64 編碼再處理,避開使用
+
、=
以及 /
。但不是有標準可以用嗎,為什麼要自己發明呢...
- 引入 Policy 的彈性機制,不僅可以對時間控制,也可以對 IP address 控制,但 Policy 這是帶在 URL 裡傳進去的... 你可以看到我的程式碼內產生出
$json_str
後簽完名帶到 URL 內了。
官方的 CloudFront Signed URLs in PHP 這篇的範例程式碼其實很清楚了,要直接拿去用其實也沒麼問題。我自己整理後是這樣:
<?php
$key_pair_id = 'APKA...';
$pem_file = '';
$resource = 'http://test2-cdn.gslin.org/test.txt';
$expires = time() + 3600;
$json_str = json_encode(
array(
'Statement' => array(
array(
'Resource' => $resource,
'Condition' => array(
'DateLessThan' => array(
'AWS:EpochTime' => $expires
)
)
)
)
),
JSON_UNESCAPED_SLASHES
);
$buf = file_get_contents($pem_file);
$key = openssl_get_privatekey($buf);
openssl_sign($json_str, $signed_policy, $key, OPENSSL_ALGO_SHA1);
openssl_free_key($key);
$signature = str_replace(
array('+', '=', '/'),
array('-', '_', '~'),
base64_encode($signed_policy)
);
echo "${resource}?",
"Expires=${expires}&",
"Signature=${signature}&",
"Key-Pair-Id=${key_pair_id}\n";
反正你搞不太懂 Amazon 為什麼要這樣設計的... =_=