Let's Encrypt: สร้างใบรับรอง SSL แบบไม่ต้องไปรันใน server จริง (certonly manual)

Posted on
development

Imgur การขอใบรับรองดิจิตอล (CA; Certification Authority) เพื่อเข้ารหัส website ให้เป็น HTTPS แสดงเป็นกุญแจเขียวตรง address bar ซึ่งหมายถึงว่า ผู้อ่านเวบไซต์ปลอดภัยจากการโจมตีความเป็นส่วนตัวระดับหนึ่ง ข้อมูลที่รับส่งระหว่างเวบไซต์กับผู้เปิดดูได้รับการเข้ารหัส

การเข้ารหัสเวบมีความสำคัญขึ้นอย่างมากดังจะเห็นได้จากข่าวนี้ New York Times ชวนสำนักข่าวทุกสำนัก เปิด HTTPS ภายในปี 2015; blognone เป็นต้น

Eitan Konigsburg วิศวกรซอฟต์แวร์ของ New York Times ออกมาเขียนบล็อกถึงประเด็นความเป็นส่วนตัวของผู้อ่านว่ามีความสำคัญมากขึ้นเรื่อยๆ จากการโจมตีรูปแบบต่างๆ ตั้งแต่การติดตามผู้ใช้ทำให้เสียความเป็นส่วนตัว ไปจนถึงการเปลี่ยนข้อมูลบนเว็บข่าว

แต่ก่อนจนถึงตอนนี้ถ้าอยากได้ใบรับรองจากตัวแทนจะมีค่าใช้จ่าย เช่นหากจะไปขอใบรับรองจาก VeriSign ขอใบรับรองแบบ domain varification (แบบที่ LE ให้) 1 ปี เราจะต้องจ่าย 39 USD แต่ถ้าใช้ LetsEncrypt เราสามารถขอใบรับรองได้ฟรี

ทำไมฟรี?

Let’s Encrypt ให้บริการฟรีได้ ส่วนหนึ่งเพราะมันทำให้กระบวนการต่างๆ ทำได้ด้วยตัวเองได้โดยผู้ใช้ (มีสคริปต์มาให้รันเองได้ และในอนาคตจะเป็นระบบอัตโนมัติมากขึ้น) ค่าใช้จ่ายก็เลยถูกลง และอีกส่วนหนึ่งเพราะมีองค์กรหลายแห่งสนับสนุนเงินทุน รวมๆ คือคนเหล่านี้อยากเห็นอินเทอร์เน็ตที่มันปลอดภัยขึ้น

จาก bact.cc ครับ

ตอนแรก google หาวิธีทำ เช่น มาเล่น Let’s Encrypt กัน และของชาวต่างๆชาติ ล้วนแต่รันใน server ที่ต้องการ HTTPS แค่ติดตั้ง client รัน script มันจะทำทุกอย่างให้อัตโนมัติ กว่าจะได้วิธีและเนื้อหานี้มาก็มึนไปอาทิตย์กว่า

พูดมากไปหน่อย เข้าขั้นตอนทำกันดีกว่า

วิธีทำ

วิธีที่ผมใช้และนำเสนอใน post นี้ letsencrypt client ไม่ได้ลง/ติดตั้งที่ server ที่จะใช้ HTTPS

ก็คือ จะขอ cert ที่เครื่อง A เอาไปใช้กับ server B

ผมใช้ Ubuntu guest vm (virtualbox) ในการติดตั้ง letsencrypt client

ติดตั้ง letsencrypt client พิมพ์คำสั่งตามนี้

# Clone the repo
git clone https://github.com/letsencrypt/letsencrypt

# Push into the direcotry
pushd letsencrypt

# Run the automated installer (see wait times above)
time ./letsencrypt-auto

ถ้ามีปัญหาลองอ่านเพิ่มเติมจาก Let’s Encrypt on Raspberry Pi (and Ubuntu Linux, etc)

การทำแบบ “ขอ cert ที่เครื่อง A เอาไปใช้กับ server B” นี้ option ที่ใส่เข้าไป คือ

certonly --manual

ที่ Terminal พิมพ์คำสั่ง

sudo ~/.local/share/letsencrypt/bin/letsencrypt certonly --agree-tos --email example@gmail.com --domains redmine.example.com --manual

ข้อสังเกต:

--email example@gmail.com ตัวนี้ก็ใช้ email ของใครของมันนะ

กด Enter รันคำสั่งแล้ว จะมี window ขึ้นมาถามว่า IP เครื่องที่ใช้จะถูกบันทึกเก็บไว้ (logged) นะ?

LE 1st question

ให้ตอบ Yes

แล้วจะมีข้อความตามกล่องข้างล่างนี้ ที่จะแตกต่างกันคือ

  1. domain name ผมใช้ redmine.example.com แทนข้อมูลจริง
  2. Hash dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0 แต่ละครั้งที่ทำมันจะได้ไม่เหมือนกัน
Make sure your web server displays the following content at
http://redmine.example.com/.well-known/acme-challenge/dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0 before continuing:

dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0.S3d81OJkYOCUOuNBhHdd2EfmxWlq6IInmA_B14mjPGc

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
cd /tmp/letsencrypt/public_html
printf "%s" dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0.S3d81OJkYOCUOuNBhHdd2EfmxWlq6IInmA_B14mjPGc > .well-known/acme-challenge/dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"
Press ENTER to continue

ข้อความเป็นแบบนี้

Make sure your web server displays the following content at http://redmine.example.com/.well-known/acme-challenge/dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0

ก่อนจะกด ENTER ให้แน่ใจว่า สามารถแสดงข้อความนี้ ใน browser ได้

dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0.S3d81OJkYOCUOuNBhHdd2EfmxWlq6IInmA_B14mjPGc

โดยใช้ URL ที่ console ให้มา ซึ่งก็คือ URL นี้ http://redmine.example.com/.well-known/acme-challenge/dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0)

วิธีที่ทำให้มันสามารถแสดงข้อความได้ มี 2 ทาง

วิธีแรก ถ้า server ยังไม่ได้ติดตั้ง apache, nginx, etc. เลย ให้เอาคำสั่งที่แนะนำ มารันเพื่อจำลอง web server ที่ port 80 เพือให้ LestEncrypt สามารถยืนยัน domain ที่เราขอไปได้

สร้างไฟล์

mkdir -p /tmp/letsencrypt/public_html/.well-known/acme-challenge
cd /tmp/letsencrypt/public_html
printf "%s" dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0.S3d81OJkYOCUOuNBhHdd2EfmxWlq6IInmA_B14mjPGc > .well-known/acme-challenge/dNaFjetvapR2WmRGeQEDeEb8P54Z8q-aw9izpEafej0

รันคำสั่งเพื่อจำลอง web server

$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"

วิธีที่2 ผมมี apache2 อยู่แล้ว จึงเอาไฟล์ q8uaHQM7kzZ9t4fxVJ4BmmrUk-6VwAwEkFDjK0sLl0Q ไปวางที่ server ขั้นตอนคร่าวๆ ดังนี้

log in เข้า http server ไปที่ public root folder ซึ่งของผมอยู่ที่ /var/www/html ต้องเป็น root หรือ account ที่มีสิทธิเขียนไฟล์ลง folder นี้ได้นะครับ

สร้าง folder .well-known/acme-challenge

cd /var/www/html
mkdir .well-known/acme-challenge

สร้างไฟล์ พร้อมเนื้อหา

printf "%s" q8uaHQM7kzZ9t4fxVJ4BmmrUk-6VwAwEkFDjK0sLl0Q.S3d81OJkYOCUOuNBhHdd2EfmxWlq6IInmA_B14mjPGc > .well-known/acme-challenge/q8uaHQM7kzZ9t4fxVJ4BmmrUk-6VwAwEkFDjK0sLl0Q

เมื่อทดสอบเรียก URL http://redmine.example.com/.well-known/acme-challenge/q8uaHQM7kzZ9t4fxVJ4BmmrUk-6VwAwEkFDjK0sLl0Q ใน browser

จะต้องแสดงเนื้อหาแบบนี้

URL sample

หลังจากนั้น ไปกด ENTER ที่ terminal รอซักแป๊บ เมื่อทำเสร็จจะได้ข้อความแบบนี้

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/redmine.example.com/fullchain.pem. Your cert will
   expire on 2016-03-23. To obtain a new version of the certificate in
   the future, simply run Let's Encrypt again.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

เอาล่ะ ตรวจสอบๆ ได้ไฟล์ certificate มาหรือยัง ไฟล์ที่ได้ออกมาจะอยู่ที่ folder /etc/letsencrypt/live/[your domain name]

ls /etc/letsencrypt/live/redmine.example.com/
cert1.pem  chain1.pem  fullchain1.pem  privkey1.pem

หลังจากนั้นเอาไฟล์ไปไว้ที่ apache2 server ใน คู่มือของ letsencrypt ก็มีบอกเอาไว้ ไฟล์ไหนคืออะไร ใช้กับบรรทัดไหน

apache2 แก้ 3 บรรทัดนี้ เราจะใช้แค่ 3 ไฟล์

SSLCertificateFile "/home/apps/drupal-7.12-1/apache2/conf/cms/cert1.pem"

SSLCertificateKeyFile "/home/apps/drupal-7.12-1/apache2/conf/cms/privkey1.pem"

SSLCertificateChainFile "/home/apps/drupal-7.12-1/apache2/conf/cms/chain1.pem"

เมื่อ แก้ไขไฟล์ config ssl เรียบร้อยแล้ว restart apache ครั้งนึงก่อน ถ้าไม่มีข้อความฟ้องปัญหาอะไร

ทดสอบเรียก https ได้เลย

green lock

ใช้ได้แล้ว … เย้!

ท้ายสุด หลังจากใช้ได้แล้ว ผมลบ hash file ออกจาก server และเปลี่ยน permission ของ .well-know ให้ไม่สามารถเข้าถึงได้จาก internet

ตอนต่อไป จะเสนอวิธีแก้ไข “Your connection to XXX encrypted using an obsolete cipher suite”