實戰對外服務網站 CDN 導入 (以中華電信 Hinet CDN 為範例)

2023-02-18

紀錄為客戶對外服務網站導入 CDN 的心路歷程。

logo

說明

取得伺服器憑證、中繼憑證以及私密金鑰

從原本的 cert.pfx 分離出伺服器憑證、中繼憑證以及私密金鑰,需要使用 openssl 進行作業。

如何取得 openssl?如果有安裝 git for windows 可以在下列路徑取得 C:\Program Files\Git\usr\bin

在分離過程如果有明文密碼,例如密碼為 seCretPa55W0rd 要輸入為參數才能夠進行分離。

openssl.exe pkcs12 -in .\cert.pfx -out server.cer -nodes -password "pass:seCretPa55W0rd"

注意:密碼必須包含 pass:,否則建議不要輸入密碼,讓系統介面跳出輸入密碼的提示後再輸入。

分離的結果會儲存在 server.cer 檔案之中,包含包含私密金鑰、伺服器憑證以及相關的中繼憑證 (可能為多個)。

進階參考保哥所分享的 如何在收到 PFX 或 CER 憑證檔之後使用 OpenSSL 進行常見的格式轉換

如何取得 public key

上述步驟解出來包含 private key & 憑證,如果需要 public key 可以搭配上個步驟取得的 server.cer 並透過以下指令來取得 public key:

openssl x509 -in .\server.cer -pubkey -noout > .\publickey.pem

如何將 cer 由 binary 轉為 text (pem)

openssl x509 -inform der -in .\server.cer -outform pem -out .\server.pem

如何檢視 Certificate Text (-----BEGIN CERTIFICATE-----)

使用 SSL Shopper 的 Certificate Decoder 來進行解譯與檢視。

如何確認網站的憑證鏈以及憑證 Certificate Text

不要透過瀏覽器,使用 openssl 來確認才能達到正確的答案 (一個小時的血淚心得)。

openssl.exe s_client -showcerts -connect gcp.nat.gov.tw:443

政府客戶常見的憑證練

依序由中繼憑證到根憑證。

Common Name: 政府伺服器數位憑證管理中心 - G1
Subject Alternative Names:
Organization: 行政院
Organization Unit:
Locality:
State:
Country: TW
Valid From: July 18, 2019
Valid To: August 18, 2031
Issuer: ePKI Root Certification Authority - G2, Chunghwa Telecom Co., Ltd.
Key Size: 4096 bit
Serial Number: 996d5fe9ade16cdc8ecdbfedb14a3295

-----BEGIN CERTIFICATE-----
MIIGtjCCBJ6gAwIBAgIRAJltX+mt4Wzcjs2/7bFKMpUwDQYJKoZIhvcNAQELBQAw
YzELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM
dGQuMS8wLQYDVQQDDCZlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
LSBHMjAeFw0xOTA3MTkwNjQ2NDVaFw0zMTA4MTkwNjQ2NDVaMFgxCzAJBgNVBAYT
AlRXMRIwEAYDVQQKDAnooYzmlL/pmaIxNTAzBgNVBAMMLOaUv+W6nOS8uuacjeWZ
qOaVuOS9jeaGkeitieeuoeeQhuS4reW/gyAtIEcxMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEAwg5R4LGoDj+mZIXmcHmRYv501jsSLIm7EoX/KAt74uN2
yDR436V2EWkFeWhD+TS4sx2/3JCRW+KE+IX8NYBKjsWuK9OMY4Gu4FEWJpBu1XCW
YjTPKyhHdEhDpxRxv91g3Zk68XgK7j2U5sEzCPx13QjkH7qc/Mo5BFiro8YsYAfx
gCoa/rZFEsXyZKXRJeIDw7t+iPxVy2cbQ0uNloO9670LGoOVzYVkYABv3IwZo+JR
tj+j7rLjB7xQKYmfJOA2Jc96yPm6li7zHrIQYfohGPdANmwR9opNNqYOo+LtsIYo
t3/cLp9YgAaiGdrAiKrbbEVkYH+zKzAHolf5mPBn+h3OElYfygESitWRBp2bwfOG
JwAYseTuorQHpyQps1GGcn9vcfnLhvLxa3DMrCAvSJb3SvHCyqahQz0KR0IPcu+V
LW3icaqlbJausGIGYqp8VSN6FJ0pgmYdbunBLYc1v23VvjmVMl+xNJoaSFEUscmS
qA4CuYANhkWSANk8HI9rNbvmzuyWhSv7tUXY6UB67mHp4ypGcKYbXrjiKqahv6QL
UEb7S8FD71Ds75F2vMeO4O77i6joBs/L2E6WZJvSronzJCXL0IwmpYaOAsoFOf0e
GVsPBVKn+z4Bq0WA0+r7plfWofDbUGmx9Zun++rWhoDXrma+odubN1Xj1RjlL3sC
AwEAAaOCAW4wggFqMB8GA1UdIwQYMBaAFHJbuqpyOO4lkCS1lCL6CYjKiwr7MB0G
A1UdDgQWBBTW6y2dYf4ru3CILrgHsVmw9IMiajAOBgNVHQ8BAf8EBAMCAYYwPAYD
VR0fBDUwMzAxoC+gLYYraHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9D
UkwyL0NBLmNybDCBggYIKwYBBQUHAQEEdjB0MDsGCCsGAQUFBzAChi9odHRwOi8v
ZWNhLmhpbmV0Lm5ldC9yZXBvc2l0b3J5L0NlcnRzL2VDQUcyLmNydDA1BggrBgEF
BQcwAYYpaHR0cDovL29jc3AuZWNhLmhpbmV0Lm5ldC9PQ1NQL29jc3BHMnNoYTIw
EgYDVR0TAQH/BAgwBgEB/wIBADAiBgNVHSAEGzAZMA0GCysGAQQBgbcjZAADMAgG
BmeBDAECAjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcN
AQELBQADggIBAEyrsJ9vUi6nEfwO0vgAoFefXpCRF+uDsmG/8F6OV9VRnbtzBwaz
HbxVmaBvDRVofLfoXWr+Nd8dd3BXVUNxemNrkZa8Hdgdv4s8yFbRs0W6fRTWkhCc
c39RpQtSeV7kyxCP1rMTYRSqCA9F+FcDMLXJIzZrzl7Tn6guIyqcfZv6sRN7CbbT
rYKSc0JX4t26WGFun2zLjzH8kx1TZ457TE4yyjl1oSZdgiWL6Hz7l+nbTe6WqPVV
m4am2AAmaQaLGncsGLasl7PIHx9Nc4sy7KdOMTc5r0BPCGhAiJ6ueQ6aVd49pra7
BDIqFMA7Myy4pXRYfqFnjq9RuROWYiIluzLNUSxlaFtTMUVQnWjJxnlXlBDLX9L4
OAxTOvdbtcNNS1GK+W1cWiYdTOWF4HTu5pvdUn/+8yVE4E7MPb0vGuxv3S11QG6J
tVPuHkX6BGqRXHo253gY77HZU0g3g9qVs9UaZjWS5UTcqdgLmmOQnH7USaJ9/4rX
Ru/P8IWMPG2s6tv1dRVQV5xfq21PQ4y53ytVd0+/lp0L743+1AjnOw0I8t9QxP6c
2ti+oo43rxM8YE3etVLQBeWsmJc00GOWa/XmFACsy8Lkctx0QScAAYwCfB2accfx
j9hEX1c6MAeVUVp04YJx4dtjoIFTPI1/MFX+FkxMq4Fs6k+mxSm7tNvv
-----END CERTIFICATE-----

Common Name: ePKI Root Certification Authority - G2
Subject Alternative Names:
Organization: Chunghwa Telecom Co., Ltd.
Organization Unit:
Locality:
State:
Country: TW
Valid From: November 17, 2015
Valid To: December 19, 2034
Issuer: Chunghwa Telecom Co., Ltd.
Key Size: 4096 bit
Serial Number: afcd8d642c62d645067dc857fda8f15d

-----BEGIN CERTIFICATE-----
MIIHZDCCBUygAwIBAgIRAK/NjWQsYtZFBn3IV/2o8V0wDQYJKoZIhvcNAQELBQAw
XjELMAkGA1UEBhMCVFcxIzAhBgNVBAoMGkNodW5naHdhIFRlbGVjb20gQ28uLCBM
dGQuMSowKAYDVQQLDCFlUEtJIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
HhcNMTUxMTE3MDg1MTM1WhcNMzQxMjIwMDIzMTI3WjBjMQswCQYDVQQGEwJUVzEj
MCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xLzAtBgNVBAMMJmVQ
S0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMIICIjANBgkqhkiG
9w0BAQEFAAOCAg8AMIICCgKCAgEApFkfoC/fvuD76dy1if5alwPJOnenjlyv8uMY
OfWq3Q9G0mgPV5ynY2DTWM41wqf2iMJPfxso6dCnAMQXTW3iD8UOJiMgq/c6KKJM
CgvMjs7mAJpaQA3UUBqb0Q2clPnb7lzQ8YoHzZorQCxJpF1iX6dr3+5WCFDzQhhs
MbBe5ZxzkrwO0gx9xThXvLtY2yYZAu3jQ4SKTlZr262hMdnMImeWeP93ncxkxTIg
au9OMNUkJf2Iea9xGv7VSxsViLwYcKq9rTgKZjBG5YmF1XYkqamz5llgD7SpU8I6
nUUa1q7jd17EYjYzLzDEv5XxLTildejRapMuRYdLSqLfv1gnmspiGape1LGASZbd
K+xfj5vgnZeI9YQDo6+zpXMtQbrlB7dva3H398lar2mZsy/IT0LrbGtxZ3jfCqxP
10qFAEYa1c24n+qVnQ980cYFheYI3ogXgfbVtW7qoRzXYarjWUKJnFl+sXxkNN1h
Iyo5tRCr/IapUxrF62rigE5ZkcA4if6zXdb7kenXsH3ZeAjM9SvMK+Gh1pRzwf5R
9Ix9CrWairn12uDJs9iPqoKDjWlTLf0ABBhKoNpU4XmMiet/9YLnoLl3Ta75ugI7
iHbrfF2zWhPbfCkWa5nRHeRIIaINXgGI6L7xmE0+xxZXHF/hCG8cTFhDVveAZYxx
DqIEZ08CAwEAAaOCAhYwggISMB8GA1UdIwQYMBaAFB4M97Zn8uGSJglFwFU5Lnc/
QkqiMB0GA1UdDgQWBBRyW7qqcjjuJZAktZQi+gmIyosK+zAOBgNVHQ8BAf8EBAMC
AQYwQAYDVR0fBDkwNzA1oDOgMYYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3Np
dG9yeS9DUkxfU0hBMi9DQS5jcmwwgYIGCCsGAQUFBwEBBHYwdDA7BggrBgEFBQcw
AoYvaHR0cDovL2VjYS5oaW5ldC5uZXQvcmVwb3NpdG9yeS9DZXJ0cy9lQ0FHMS5j
cnQwNQYIKwYBBQUHMAGGKWh0dHA6Ly9vY3NwLmVjYS5oaW5ldC5uZXQvT0NTUC9v
Y3NwRzFzaGEyMA8GA1UdEwEB/wQFMAMBAf8wgecGA1UdIASB3zCB3DANBgsrBgEE
AYG3I2QAATANBgsrBgEEAYG3I2QAAjANBgsrBgEEAYG3I2QAAzANBgsrBgEEAYG3
I2QABDANBgsrBgEEAYG3I2QACTANBgsrBgEEAYG3I2QAADANBgsrBgEEAYG3I2QE
ATANBgsrBgEEAYG3I2QEAjANBgsrBgEEAYG3I2QEAzAJBgdghnYBZAABMAkGB2CG
dgFkAAIwCQYHYIZ2AWQAAzAJBgdghnYBZAAEMAkGB2CGdgFkAAAwCAYGZ4EMAQIB
MAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggIBALwy4mxatKA6
X+UM2IDpnWajNmek00EM4qh5E7eiQY0yZV5Eit9D/8q9h0hD77NjVaYPwsOWqWAi
VtDAro+nWDHfkAG14ptRNBoGjJjzZi/+OeI2WTc8ZER6C8rAjQ7b/RxMzwxfDjRt
gCbT2qq01rPiJ+qDgyUniDstbyQj08bSo3GJWp6ZsSNDAP26ygODpSgL0Ja806By
k2b4npQevdkmQ0k43S9IU0MeSlWT8hxzluyFlPRl4yuev5le91outdEdpV98KvYc
gLAWwW5UcFOM6SRsYTBS2dfSRgKreDnMNdbUHmbAVsb3wLD6WqLoe6LyRNOeXctK
PA6+e5i/JN6NZnqejcMopuS+pyWyrNiHlRShGUfTiXrcbT8fbyOswAT8JsX4fWyZ
Yub0kKfFG8hEKQsIxNiyKH4cw6HBih31EYaYS9IEj19NxfHl0KbPm22cpBJoGwkZ
Wgg//PflFFHNTdKSalDxPHMKdyZbTBugLtqFVkV+vu1y6WRoGfHwzpa9aQsMWAwL
YRnBZnSYzfN9QFZsoHCSDJJVt30Oi6fURJy34+dtvs+sQihiN886uYTJ0Cex1R+O
b9HXCKFrGTumgwD+nitt7hwlB74K9lqrKQrtfgfBFFMG9Tu/E/OI6JoST2j8KmSN
1rpcxoMH3tamxqm3+xpLM9HekbBoJ0V2
-----END CERTIFICATE-----

Common Name:
Subject Alternative Names:
Organization: Chunghwa Telecom Co., Ltd.
Organization Unit: ePKI Root Certification Authority
Locality:
State:
Country: TW
Valid From: December 19, 2004
Valid To: December 19, 2034
Issuer: Chunghwa Telecom Co., Ltd.
Key Size: 4096 bit
Serial Number: 15c8bd65475cafb897005ee406d2bc9d

-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----

外部 DNS 設定

為了保持原本提供服務的域名持續使用,必須要另設一個新的域名提供 CDN 專門指向,而原本的域名則以 CNAME 的方式指向 CDN 伺服器。

調整前:

域名 DNS 類型 指向
www.sdwh.dev A Server IP

調整後:

域名 DNS 類型 指向
www.sdwh.dev CNAME www-sdwh.cdn.hinet.net
wwwori.sdwh.dev A Server IP

CDN 伺服器與原伺服器關係

第一張圖片的架構為不使用 CDN 時,外部 DNS 提供 A Record 的方式,讓外部可以直接連到網站所在的伺服器。

第二張圖片的架構為使用 CDN 時,藉由在外部 DNS 新增 CNAME 的方式,將原本的網址指向 CDN 伺服器。

並且在 CND Portal 上進行設定,對應到既有的 A Record,讓 CDN Server 可以連結到實際的網站所在伺服器,並將快取結果對外服務。

可以進一步限制實體網站所在伺服器僅限 CDN Server 連線。

第三張圖片的架構為使用 CDN 時,若網站所在的伺服器有多個站台 (multi-tenant) 則需要在外部 DNS 設定額外的原站域名,讓 CDN Server 可以區別對應到不同的站台。

設定 CDN 後台

測試 CDN

public class Program
{
    static void Main(string[] args)
    {
        string url = "https://wwwori.sdwh.dev/blogPost?article=1024";
        CdnPurge.Purge(url);

    }
}

public class CdnPurge
{
    private const string BaseUrl = "https://api.cdn.hinet.net/cdnPortalAPI/addPreloadPurge";
    private const string Token = "";
    private const int ServiceId = 1;
    private const string ServiceName = "www";
    private const string Action = "purge";
    private const int UseDeviceType = 0;

    public static void Purge(string url)
    {
        var data = new { data = new[] { new { url } } };
        string urlPayload = JsonConvert.SerializeObject(data);

        var req = WebRequest.CreateHttp(BaseUrl);
        req.Method = HttpMethod.Post.Method;
        req.ContentType = "application/x-www-form-urlencoded";

        string postData = 
          $"token={Token}&serviceID={ServiceId}&serviceName={ServiceName}&action={Action}&useDeviceType={UseDeviceType}&url={HttpUtility.UrlEncode(urlPayload)}";

        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        req.ContentLength = byteArray.Length;

        using (Stream dataStream = req.GetRequestStream())
        {
            dataStream.Write(byteArray, 0, byteArray.Length);
        }

        using (WebResponse response = req.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(responseStream))
                {
                    string responseText = reader.ReadToEnd();
                    Console.WriteLine(responseText);
                }
            }
        }
    }
}

特別設定

防火牆需要放行中華電信的 CDN 節點。

原站的標頭可以使用實際的網域名稱。

搭配 WAF 需要注意封鎖行為要針對實際連線的 IP 而非 CDN 節點的 IP。

快取的時間越長,原站的負擔越小,但資料的即時性越低,解決的方式可以透過 CDN API 主動清除,或者是降低快取的時間,搭配 Use Cache Stale 的方式來確保網頁的即時性。