เมื่อช่วงต้นปีที่ผ่านมา Let’s Encrypt ก็ได้เปิดตัว Wildcard SSL แล้วก็เลยคิดว่าควรจะรีบย้ายไปสักที
เหตุผลหลักๆ คืออย่างที่พอทราบกันว่าใน certificate ที่ออกด้วย Let’s Encrypt นั้นจะต้อง list subdomain ทั้งหมดใน subject alternate name

ซึ่งถ้าเรามี internal subdomain ก็ไม่เหมาะเท่าไรที่จะ list ในนั้น วิธีที่ผมกันคนขี้สงสัยแบบนี้ก็คือการเอา domain ภายในไปออกอีกใบนึง จะได้ไม่อยู่ในรายชื่อ
แต่ที่หลายคนไม่รู้คือการออกใบรับรอง SSL โดยผู้ให้บริการที่น่าเชื่อถือนั้นจะมีการส่งข้อมูลไปยังฐานข้อมูล Certificate Transparency ด้วย ตัวอย่างเช่น subdomain ของ whs.in.th ไม่ว่าจะเอาไปซ่อนไว้ใบไหนก็จะเห็นทั้งหมด ฉะนั้นก็เลยคิดว่าน่าจะต้องเริ่มเลิกใช้แล้ว
Prerequisite
ข้อกำหนดการออก wildcard certificate ของ Let’s Encrypt คือเราจะต้องยึนยันตนผ่าน DNS ซึ่งผมเห็น guide ภาษาไทยจำนวนหนึ่งแนะนำให้ตั้งค่า DNS เอง ซึ่งอันตราย เพราะมันจะ auto renew ให้ไม่ได้แล้วเว็บจะเข้าไม่ได้หลังหมดอายุ
ฉะนั้นแล้วเราจะต้องใช้ DNS Hosting ที่สามารถ automate ได้ด้วย ซึ่งเจ้าที่ฟรีก็จะมี DigitalOcean กับ CloudFlare
สำหรับเว็บผมนั้นใช้ DNS Hosting ดังนี้
- whs.in.th: Google Cloud DNS
- cupco.de: CloudFlare
ที่เลือกใช้ 2 อันเพราะอยากกระจายความเสี่ยง (และ 2 เจ้านี้รองรับ DNSSEC) ส่วนที่ไม่ใช้ SSL ฟรีของ CloudFlare เพราะไม่อยากให้ CloudFlare เห็นข้อมูลของเราวิ่งผ่านจึงใช้เป็น DNS อย่างเดียวโดยไม่เปิด proxy และบาง subdomain ที่เปิด proxy นั้นก็ตั้งให้ CloudFlare verify การเชื่อมต่อระหว่าง CloudFlare กับ server ด้วยเพื่อความปลอดภัย
ขอ API Key
สำหรับ CloudFlare สามารถขอ API Key ได้ที่หน้า Profile ด้านล่างสุด เลือก Global API Key
ตอนนี้ดูเหมือนว่า CloudFlare จะยังไม่มี API key per domain หรือจำกัด role (ถึงแม้จะเป็น enterprise ก็ตาม — เค้าแนะนำให้ทำ service account มาแล้วจำกัด permission)
จากนั้นให้เอา key ไว้ในไฟล์ ini ดังนี้
dns_cloudflare_email = อีเมลที่ใช้ login
dns_cloudflare_api_key = api key ที่ได้
สำหรับ Google Cloud นั้นให้เข้าไปออก Service account
โดยตั้ง role = DNS Administrator และเลือก Furnish new private key แบบ JSON แล้วเก็บไฟล์ JSON ไว้ใน folder เดียวกับ CloudFlare API key
SSL First Time
จากนั้นเราจะออก cert ใบแรกกันครับ
$ sudo docker volume create certs
# อย่าลืมเปลี่ยน path ไป folder เก็บ account และชื่อไฟล์ account
$ sudo docker run --rm -v "/path/to/account/folder:/dns:ro" \
-v "certs:/etc/letsencrypt:z" certbot/dns-google renew \
--dns-google-credentials /dns/service_account.json
Saving debug log to /var/log/letsencrypt/letsencrypt.log
How would you like to authenticate with the ACME CA?
-------------------------------------------------------------------------------
1: Obtain certificates using a DNS TXT record (if you are using Google Cloud DNS
for DNS). (dns-google)
2: Spin up a temporary webserver (standalone)
3: Place files in webroot directory (webroot)
-------------------------------------------------------------------------------
Select the appropriate number [1-3] then [enter] (press 'c' to cancel): ตอบ 1
Plugins selected: Authenticator dns-google, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): กรอกอีเมล
-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: a
-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
-------------------------------------------------------------------------------
(Y)es/(N)o: n
Please enter in your domain name(s) (comma and/or space separated) (Enter 'c'
to cancel): กรอกโดเมนลงไป เช่น whs.in.th,*.whs.in.th
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for whs.in.th
dns-01 challenge for whs.in.th
...
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/whs.in.th/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/whs.in.th/privkey.pem
Your cert will expire on 2018-10-02. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
เป็นอันใช้ได้ สำหรับ CloudFlare ก็ทำคล้ายๆ กัน คือ
sudo docker run --rm -v "/path/to/account/folder:/dns:ro" \
-v "certs:/etc/letsencrypt:z" certbot/dns-cloudflare renew \
--dns-cloudflare-credentials /dns/cloudflare.ini
ติดตั้งลงใน nginx
เสร็จแล้วเราก็สามารถ mount volume เข้าไปใน nginx ได้เลย
sudo docker run -d --restart=always --name=nginx \
-v nginx:/etc/nginx \
-v certs:/etc/certs:ro,z \
-p 80:80 -p 443:443 \
--hostname madoka.whs.in.th nginx
สำหรับการตั้งค่า certificate นั้นแนะนำให้ตั้งตาม Mozilla SSL Generator โดยระบุดังนี้
ssl_certificate /etc/certs/live/whs.in.th/fullchain.pem;
ssl_certificate_key /etc/certs/live/whs.in.th/privkey.pem;
ssl_trusted_certificate /etc/certs/live/whs.in.th/chain.pem;
เป็นอันเรียบร้อย
Renew
สำหรับการ renew นั้นเราจะทำ shell script ไว้
#!/bin/bash
CERT_VOLUME=certs
DNS_VOLUME=/path/to/dns
docker run --rm -v "$DNS_VOLUME:/dns:ro" -v "$CERT_VOLUME:/etc/letsencrypt:z" certbot/dns-google renew \
-n --agree-tos --dns-google-credentials /dns/service_account.json
docker run --rm -v "$DNS_VOLUME:/dns:ro" -v "$CERT_VOLUME:/etc/letsencrypt:z" certbot/dns-cloudflare renew \
-n --agree-tos --dns-cloudflare-credentials /dns/cloudflare.ini
docker kill -s HUP nginx
จะเห็นว่าตอนท้ายนั้นเราจะยิง HUP ไปหา nginx container ด้วยเพื่อให้ reload certificate
แล้วก็ใส่ไว้ใน crontab ของ root ให้รันทุกวันเป็นอันเสร็จ
$ sudo crontab -e
0 0 * * * /path/to/update-certs.sh > /dev/null 2>&1
(อาจจะแก้ให้มัน log ไว้เพื่อตรวจสอบก็ได้)
สรุป
หนึ่งปีครึ่งผ่านไป รู้สึกว่า Let’s Encrypt มีการพัฒนาขึ้นมาก ทั้งบริการ และ certbot ก็ตาม รอบนี้รู้สึกว่าขั้นตอนซับซ้อนน้อยกว่าเดิมมากและ user friendly
สำหรับตอนหน้าหลังจากเป็นสายฟรีมานาน ว่าจะออก SSL EV ใบละหมื่นบ้างว่าจะมีขั้นตอนอย่างไร