I decide to write this article in Thai instead of in English. Because, one of my friend told me that there still was a need for more Thai tech article. In the future, may be I will switch around based on what I think the article language should be. Although, if in the future Zola support i18n and I have enough time, I will write in both language.
Mosquitto เป็น หนึ่งใน opensource mqtt service broker ที่นิยมใช้กันสำหรับการส่งข้อความไปมาระหว่างอุปกรณ์ต่างๆในวงเครือข่ายของ IoT โดยที่ Mosquitto เป็นโครงการที่ถูกดูแลโดยมูลนิธิ eclipse ที่มีชื่อเสียงจากการทำ ide ของ java ที่ผมเชื่อว่าหลายๆคนก็เคยใช้กันครับ คราวนี้แล้วอะไรคือ jail อะไรคือ FreeBSD และ อะไรคือ BastilleBSD มาลองดูกันครับ
This article is using FreeBSD 12.1 & Bastille 0.6.0
อรัมภบท
ก่อนอื่นเลยในยุค 2020 คนส่วนใหญ่เวลาจะลง service อะไรมักก็จะนึกถึงพวก container ต่างๆ เช่น docker ที่เป็นที่นิยมทั่วไป หรือ podman ของ RedHat ที่เป็น rootless container อันไหนดีกว่า ผมก็ยังไม่ค่อยจะแน่ใจเท่าไรแต่ตั้งใจไว้ว่าว่างๆจะหาเวลามาศึกษาดูครับ แต่สิ่งนึงที่ทั้งสองอันนี้เหมือนกันก็คือมันเป็น linux native ทั้งหมดครับ
อย่างที่รู้ๆกันว่าระบบปฏิบัติการในปัจจุบันนั้นมีหลากหลายมาก ระบบปฏิบัติงานนึงที่ค่อนข้างมีชื่อเสียงนั่นก็คือ FreeBSD ตัว FreeBSD เองนั้นก็สามารถที่จะลง docker ได้นะครับ แต่จำเป็นที่จะต้องมี linux layer หรือ packages มาลงด้วยไม่ได้เป็น native แบบอย่างแท้จริง สำหรับ FreeBSD แล้วเขามีอุปกรณ์ตัวนึงที่ชื่อว่า jail หรือคุกที่จะไว้กักขัง กักตัว หน่วงเนี่ยว process ไม่ให้ไปไหนหรือออกนอกพื้นที่ที่ถูกตั้งไว้ไปได้ ฟังดูแล้วก็คล้ายกับ container อยู่ใช่ไหมครับ
Jail and FreeBSD
FreeBSD 12.1 นี้มีอยู่บนผู้ให้บริการ(VPS) หลากหลายรายเช่น UpCloud, DigitalOcean, Vultr และก็อื่นๆอีกหลายหลายเจ้าครับ (ในบทความนี้ผมทำบน VM ของผมนะครับ) สำหรับตัว Jail นั้นถ้ามีฝีมือคุณก็สามารถตั้งค่าได้เองเลยเพียงแค่เข้าไปอ่านบน FreeBSD Handbook ก็เท่านั้นเอง แต่ถ้าอยากสะดวกสบายหน่อยก็จะมีพวกตัวช่วยอยู่เช่น
แต่ละอันก็ถูกเขียนจากภาษาที่แตกต่างกัน และมีความสามารถที่แตกต่างกันออกไป ตัว Bastille ที่ผมใช้นะเขาบอกว่าจุดเด่นคือใช้งานง่ายและขนาดเล็ก(สารภาพก่อนเลยว่าผมเลือกตัวนี้ผม website เขาสวยและ docs อ่านง่ายมากๆๆ)
ติดตั้ง bastille : jail manager
ข้อมูลส่วนใหญ่ออกแนวอ้างอิงมาจากวิธีการติดตั้งบนเว็บไซต์หลักของเขาครับ วิธีการติดตั้ง
มาเริ่มกันเลยหลังจากที่เราสร้าง droplet เสร็จก็จะเจอหน้าตาแบบเปล่าสิ่งที่ต้องทำก่อนเสมอหลังจากติดตั้ง FreeBSD เสร็จก็คือการอัพเดท patch และ ติดตั้ง patch ซึ่งเราสามารถทำได้ด้วยวิธีการนี้
root@App02:~ # freebsd-update fetch
root@App02:~ # freebsd-update install
คำสั่งข้างบนก็ออกแนวคล้ายๆกับ "apt update & apt upgrade" นั่นแหละครับ คราวนี้เราก็พร้อมที่จะลง packages แหละ แต่เดียวก่อน???? เนื่องจาก FreeBSD มีการอัพเดท package แบบ quaterly หรือทุกๆ 3 เดือน ดังนั้นเพื่อให้เราได้ packages ที่ใหม่ๆสดๆจากต้นน้ำเราจึงจำเป็นต้องทำการเลือกของเราให้เป็นสายต้นน้ำก่อน "ไม่จำเป็นต้องทำถ้าโอเคหรือเน้นความเสถียรเป็นหลัก"
root@App02:~ : mkdir -p /usr/local/etc/pkg/repos
root@App02:~ : echo 'FreeBSD: { url: 'pkg+http://pkg.FreeBSD.org/\$\{ABI\}/latest', enabled: yes }' > /usr/local/etc/pkg/repos/FreeBSD.conf
และเมื่อเราพร้อมก็ถึงเวลาติดตั้ง bastille กันครับ คำสั่งก็จะคล้ายกับฝั่ง linux เลย :)
root@App02:~ : pkg install bastille
และเพื่อทำให้ bastille สามารถถูกสั่งเปิดปิดได้จากคำสั่ง "service" ที่ก็คล้ายๆกับคำสั่ง "systemctl" ละนะเราจึงจำเป็นที่จะต้องทำการเปิด bastille ขึ้นด้วยคำสั่ง
root@App02:~ : sysrc bastille_enable="YES"
bastille_enable: -> YES
ตั้งค่า bastille
หลังจากเราติดตั้ง bastille เสร็จแล้ว เราก็จำเป็นที่จะต้องทำการสร้าง network interface ให้กับ jail ของเรา ตรงนี้จะต่างจาก default ของ docker นิดนึงตรงที่เราจำเป็นต้องสร้างทุกอย่างขึ้นมาเองทั้งหมดก่อน โดยที่ไฟล์ config ของ bastille จะอยู่ที่ /usr/local/etc/bastille/bastille.conf
โดยปกติแล้วไฟล์ config ที่ user ทำการติดตั้งเองจะถูกเก็บที่ /usr/local/etc/
ในขณะที่ถ้าเป็นของ system จะเก็บที่ /etc/
การเก็บแบบนี้ทำให้หาง่ายขึ้นเยอะๆมากๆครับ
ตั้งค่า local network
เพื่อให้ jail ของเรามี net ใช้ได้ได้ เราจึงจำเป็นต้องทำการสร้าง interface ขึ้นมาก่อนวิธีการทำ interface ก็คือ
root@App02:~ : sysrc cloned_interfaces+=lo1
root@App02:~ : sysrc ifconfig_lo1_name="bastille0"
root@App02:~ : service netif cloneup
เราได้ทำการสร้าง network ภายในที่ชื่อว่า "bastille0" เป็นที่เรียบร้อยแหละ ก็เหลือแค่ทำการสร้าง NAT เพื่อให้ jail ของเราสามารถใช้ได้ โดยเราจะใช้ built-in firewall ของ FreeBSD ที่ชื่อ PF (Packet Filter)
This was directly copy from bastille guideline
ext_if="em0" ## ***
set block-policy return
scrub in on $ext_if all fragment reassemble
set skip on lo
table <jails> persist
nat on $ext_if from <jails> to any -> ($ext_if)
## static rdr example
## rdr pass inet proto tcp from any to any port {80, 443} -> 10.17.89.45
## dynamic rdr anchor (see below)
rdr-anchor "rdr/*"
block in all
pass out quick modulate state
antispoof for $ext_if inet
pass in inet proto tcp from any to any port ssh flags S/SA modulate state
# If you are using dynamic rdr also need to ensure that the external port
# range you are using is open
*** ตรงนี้ให้เปลี่ยนเป็น interface ที่ต่อเน็ตข้างนอกได้นะครับให้เช็คจาก ifconfig
ทำการ enable firewall เพื่อเสร็จสมบูรณ์
root@App02:~ : sysrc pf_enable="YES"
root@App02:~ : service pf start
สร้าง Jail
ตอนนี้เราก็ทำทุกอย่างพร้อมแล้ว มาเริ่มสร้าง jail กันดีกว่า เริ่มด้วยการโหลด image ก็เหมือนคำสั่งในการ pull image ลงมาของ docker นั่นแหละครับ ดึง image ลงมาเพื่อเอาไว้เป็นฐานในการสร้าง jail แต่ละ jail
root@App02:~ : bastille bootstrap 12.1-RELEASE update
ทำการสร้าง jail ขึ้นมาในที่นี้ผมจะให้ jail ของผมชื่อว่า "mosquitto-mqtt" โดยที่คุณต้องกำหนด ip address ของ jail ตัวนี้เองครับ ให้มันอยู่ใน range ของ 3 ตัวนี้ครับ 10.0.0.0/8
, 172.16.0.0/12
และ 192.168.0.0/16
root@App02:~ : bastille create mosquitto-mqtt 12.1-RELEASE 10.17.89.100
start jail ขึ้นมา
root@App02:~ : bastille start mosquitto-mqtt
ติดตั้งและตั้งค่า mosquitto
ก่อนอื่นเลยเราก็ต้องเข้าคุกเข้าตารางก่อนด้วยคำสั่ง เพื่อเข้าไปใน jail ของเราที่สร้างขึ้นไว้
root@App02:~ : bastille console mosquitto-mqtt
ทีนี้เราก็จะเข้ามาอยู่ในคุกที่เราสร้างไว้ เราก็พร้อมที่จะเข้าสู่อาหารจานหลักนั่นก็คือติดตั้ง mosquitto กันซักที
root@mosquitto-mqtt:~ : pkg install mosquitto
เหมือนเช่นเคยครับ ลงเสร็จเราก็ต้องทำการ enable service ด้วยด้วยคำสั่ง sysrc mosquitto_enable="YES"
ผมชอบจำเป็น true อยู่เรื่อยเลยแหะ ก็จะเสร็จกับการติดตั้ง
เวทอะมินิด เรายังต้องทำการตั้งค่าอีกซักนิดๆหน่อยก่อนที่เราจะ start mosquitto ขึ้นมาได้ เช่นเคยครับ config ของ mosquitto ก็จะอยู่ที่ /usr/local/etc/mosquitto/mosquitto.conf
ตัวไฟล์จะมีคำอธิบายอย่างละเอียดว่าแต่ละตัวแปรหมายความว่าอะไรให้ด้วย อย่างยาวเลยแหละ!! แต่คราวๆที่จำเป็นก็คือต้องเป็น user nobody
ไม่ใช่ค่า default user mosquitto
หลักจากนั้น mosquitto ก็พร้อม start แล้ว
root@mosquitto-mqtt:~ : service mosquitto start
ยังไม่เสร็จนะ เราแค่ทำการลง mosquitto เสร็จเฉยๆ เรายังต้องทำการ port binding กับ host ด้วยไม่งั้นคนนอกก็จะไม่สามารถใช้ service ของเราได้
ตั้งค่า pf อีกรอบ
กลับมาอยู่บน host อีกรอบในรอบนี้เราต้องทำการ bind port ของ host เข้ากับของ jail ซึ่งก็สามารถทำได้โดยใช้คำสั่ง rdr ของ bastille
root@App02:~ : bastille rdr mosquitto-mqtt tcp 1883 1883
default port ของ mosquitto เป็น 1883 แต่เป็น unecrypted channel ถ้าต้องการ encrypted ก็ต้องใช้ port 8883 และมี cert SSL ผมขอติดไว้ครั้งหน้านะ
นอกจากที่จะทำการ bind port ไปแล้วเราก็ยังต้องทำการแก้ไขไฟล์ /etc/pf.conf/
ของเราด้วย ไม่งั้นก็จะไม่สามารถใช้ port นี้ได้ โดยให้แก้เป็น
pass in inet proto tcp from any to any port {1883, ssh} flags S/SA keep state
ที่เหลือก็แค่ restart pf เพื่อให้ตั้งค่าใหม่อัพเดท
root@App02:~ : pfctl -f /etc/pf.conf
เพียงเท่านี้ ก็เสร็จหมดทุกอย่างแล้ว เฮ้!
ทดสอบทุกอย่าง
เมื่อเราลงทุกอย่างเสร็จหมดอันเป็นที่เรียบร้อยก็ถึงเวลาทดสอบกันซักที เราจะทดสอบด้วยคำสั่ง mosquitto_pub
ที่จะรันจากอีกเครื่อง
root@App03:~ : mosquitto_pub -h app02.local -t "vm/shoutout" -m "Stay at home is so boring" -d
Client mosq-X2wcbXbfu9nsUQo43Z sending CONNECT
Client mosq-X2wcbXbfu9nsUQo43Z received CONNACK (0)
Client mosq-X2wcbXbfu9nsUQo43Z sending PUBLISH (d0, q0, r0, m1, 'vm/shoutout', ... (25 bytes))
Client mosq-X2wcbXbfu9nsUQo43Z sending DISCONNECT
ส่งได้เรียบร้อยสบายใจ
ส่งท้าย
จะเห็นได้ว่าการที่จะติดตั้ง mosquitto ใน jail ของ freebsd นั้นเราอาจจะต้องทำ manually มากกว่า docker อยู่หลายขุมทีเดียวเชียวละ แต่ก็แลกด้วยความปลอดภัยและความโปร่งที่มาเป็นการตั้งค่าพื้นฐาน ก็อย่างที่บอกว่าปีนี้ผมตั้งใจจะลองเล่น FreeBSD และ OpenBSD ดู ถ้าใครสนใจก็ลองมาคอยอ่านได้นะครับ แต่ผมว่าไม่น่าจะมีใครอ่านมากกว่านะ authlog แทบไม่เด้งเลยฮา มีแต่บอททั้งนั้น T_T
P.S. Take care of yourself during this tough time, and I wish you all the best.