สวัสดีครับผู้อ่าน ช่วงนี้คิดว่าหลายๆคน คงจะหนาวๆกันไม่น้อยเหมือนอยู่บนดอยยังไงยังงั้น แต่บนดอยก็ใช่ว่าจะแย่มองเห็นดวงจันทร์ชัดแจ๋วเลย ทำได้แต่มองแต่ไปไม่ถึงซะทีอ่ะนะ T_T
กลับเข้าเรื่อง พักนี้ก็งานหนักเหมือนเดิม ad-hoc เข้ามาเยอะมาก ช่วงนี้ผมจำเป็นต้องหัดใช้ Docker บ่อยมากขึ้นเพื่อสร้าง Environments สำหรับทดสอบอะไรหลายๆอย่าง ซึ่งถือว่า Docker เป็น Magical solution สำหรับผมเลยก็ว่าได้ สำหรับผู้อ่านที่ยังไม่เห็นภาพ เราจะมาทำความรู้จักกับมันคร่าวๆ ดีกว่า
Docker เป็นแพลตฟอร์มซอฟต์แวร์ตัวนึง ที่ทำตัวเสมือน VM บนเครื่องที่เปิดใช้งาน (host) และมี daemon เพื่อรอรับคำสั่งจาก host เช่น เปิด/ปิด/สร้าง/ลบ object (ส่วนมากเป็น container) บนแพลตฟอร์มนี้ เป็นต้น
Image เป็นโปรแกรม ที่ถูกประกอบจาก Layer หลายๆชั้น ซึ่ง Layer เปรียบเสมือนสิ่งของที่ถูกวาด เมื่อนำมารวมด้วยกันจะได้เป็นภาพออกมา (Image) โดยแต่ละ Layer ก็จะมีวัตถุประสงค์ในตัวของมันเอง ยกตัวอย่าง
- Layer A สำหรับติดตั้ง MySQL
- Layer B สำหรับติดตั้ง PHP
- Layer … สำหรับ บลาๆ
- Layer Z สำหรับตั้งค่า Permission
เพราะฉะนั้น A + B + … + Z จะได้เป็น Wordpress Image ที่สำคัญ Image ตัวนึงอาจกลายเป็น Layer ของ Image อีกตัวก็ได้ด้วยนะ เมื่อ Image ถูกสร้างมันจะถูกเก็บในรูป local ใน Docker แพลตฟอร์มหรือสามารถโหลดขึ้น Online Repository อย่าง Docker Hub ก็ได้ และท้ายที่สุด Image จะถูกแปลงเป็น Process นึงบนแพลตฟอร์มในรูปแบบ Container เพื่อที่เราจะสามารถทำงานกับมันได้ทันที
Container เป็น Docker Process ตัวนึงที่มี state เป็นของตัวเอง ซึ่งถูก scheduled มาจากแพลตฟอร์มโดยคำสั่งจาก host ผ่านช่องทาง daemon อีกที หน้าที่ของมันไม่มีอะไรมาก รันชุดคำสั่งของตัวเองที่ถูกกำหนดไว้ เช่น Image, Volume, Network ฯลฯ เป็นต้น
Docker Swarm เป็น Orchestration tool สำหรับบริหารจัดการ Docker container จำนวนมาก ผ่านการ config ไม่กี่บรรทัด เพื่อให้ container สามารถทำงานได้ยืดหยุ่น มีประสิทธิภาพหรือคงทนต่อความล้มเหลว ฯลฯ อีกทั้งยังสามารถเป็นศูนย์เก็บ shared resources สำคัญสำหรับของแต่ละ container ได้ เพื่อลดความซับซ้อนบางประการ แน่นอนว่าถ้าจะใช้งาน Docker Swarm ของติดตั้ง Docker Standalone ก่อนนะ…
How about the secret ?
ร่ายมาซะยาว ทีนี้เรารู้จักแล้วนะว่า Docker มันทำให้งานเราง่ายแค่ไหน แค่มี image หรือ config file เราสามารถรันโปรเจค open source ได้ด้วยปุ่ม enter เดียว แต่ถ้าเราลองพิจารณาโค้ดจากไฟล์ config นี้ (ห้ามทำตามนะ บ า ป มาก)
จะเห็นได้ว่าที่บรรทัด 33 ถึง 35 จะมีการ hardcode สำหรับ environment variables ของ image ตัวนี้ตรงๆ ซึ่งต่อให้มือใหม่มาเห็นดูยังไงมันก็ไม่ใช่ practice ที่ดีแน่ๆ แล้วอะไรที่มันมาช่วยไม่ให้เราต้องมานั่ง hard code แบบนี้ล่ะ? คำตอบ หนึ่งในนั้นคือกลไกของ docker secret
Docker secret เป็น feature นึงของ Docker swarm ที่เกิดมาเพื่อบริหารจัดการ credentials ต่างๆ ไม่ว่าจะเป็น password, SSH Private key, SSL หรืออะไรก็ตามในรูปแบบ blob format ที่เราจัดว่ามันเป็น sensitive data สำหรับการทำงานใน container ซึ่งมักอยู่ในเกณฑ์ 3 ข้อนี้
- ไม่ควรถูกส่งไปยังที่อื่นหรือ container อื่น
- ไม่ควรถูกเก็บใน DockerFile (ไฟล์ config) โดยเฉพาะยิ่งถ้าเป็น Plain text
- ไม่ควรอยู่ในโค้ดส่วนใดส่วนนึงของ application
จากไฟล์ config ที่ยกตัวอย่างจะเห็นได้ว่าเข้าเกณฑ์ข้อที่ 2 แน่ๆ เพราะงั้นสิ่งที่เราต้องทำก็คือ ให้ docker secret จัดการส่วนนี้ให้เราแทนการมานั่ง hard code แบบนี้
How the secret works ?
เมื่อ secret ถูกสร้างผ่านคำสั่ง docker secret create ดังตัวอย่าง
$ echo "This is a secret" | docker secret create my_secret_data -
ตัว Docker platform จะส่ง secret ไปยัง swarm manager ผ่าน TLS connection และ secret จะถูก encrypt ด้วย key ขนาด 256 bit และเก็บใน Raft store เมื่อ docker service กำลังจะถูกสร้างและต้องการใช้ secret ตัว manager จะทำการ decrypt ตัว secret แล้วแปะลงใน filesystem ของ container ตัวนั้นๆ แบบ in-memory หลังจากนั้น container ตัวนั้นก็จะทำงานได้ตามปกติตามที่ config กันไว้ และเมื่อ container จบการทำงานตัว secret ใน container ตัวนั้นจะมีกลไกในการลบตัวเองทิ้งเอง หรือหาก container สูญเสียการเชื่อมต่อก็จะยังสามารถเข้าถึง secret ตัวนั้นได้ แต่จะไม่ได้รับการ update ใดๆหากมีการเปลี่ยนแปลงในเวลานั้น ซึ่งต้อง reconnect ไปยัง swarm เพื่อทำการ update ข้อมูลล่าสุด
จุดน่าสังเกตคือ container ไม่สามารถร้องขอ secret ได้เอง มีเพียงแค่ swarm manager ที่สามารถแจกจ่าย secret แบบ decrypt ได้เท่านั้น
และนี่คือ config ที่มีการใช้ secret แทนการ hard code ตรงๆ
Does a secret considered safe?
ถ้าว่ากันตาม life cycle ของการเก็บและแจกจ่าย secret ที่เก็บ sensitive data ไว้มันดูเป็นอะไรที่เรียบง่ายและสมเหตุสมผลดี ซึ่งแนวคิดนี้ Orchestration tool ยี่ห้ออื่นก็ได้ implement ลงไปด้วย แต่ก็ควรคิดไว้ว่าไม่มีอะไรในโลกนี้ที่ attacker ไม่สามารถเข้าถึงได้ ถ้าหาก attacker สามารถเข้าถึง shell ของ container ได้ เอาจริงๆ ก็สามารถ cat ดู secret ได้ตรงๆ ผ่าน /proc/id/environ (กรณีไม่ใช้ secret แต่ hard code บน environment variables ใน docker) หรือ /run/secrets/my-secret (กรณีใช้ secret) เพราะมันเป็น in-memory file ตามที่กล่าวไว้ก่อนหน้า เพราะฉะนั้นถ้าตามความเห็นของผมการ implement secret เป็นเรื่องที่ดี แต่มันไม่ได้ช่วยป้องกันอะไรในระดับอื่นๆเท่าที่ควร เช่น application เราจำเป็นต้องมีกลไกอื่นๆมาไว้เพื่อรองรับสถานการณ์อื่นด้วยครับ
สำหรับบทความประจำสัปดาห์นี้หากมีข้อผิดพลาดใดๆ ผมขออภัยมา ณ ที่นี่ด้วยครับ
ขอบคุณครับ