Security และ Atlas
mongod ใหม่ที่เริ่มด้วยการตั้งค่าเริ่มต้นไม่มี authentication และคอยฟังการเชื่อมต่อ บนเครื่องแล็ปท็อปของคุณที่ผูกกับ localhost นั่นไม่มีอันตราย แต่บน server ที่มี public IP นี่คือข้อมูลรั่วที่รอวันเกิด — และตลอดหลายปีที่ผ่านมา MongoDB instances ที่ไม่ปลอดภัยได้ทำให้ข้อมูลปริมาณมหาศาลรั่วไหลด้วยวิธีนี้เป๊ะ ๆ
Security ใน production ไม่ใช่ฟีเจอร์เดียวจบ แต่เป็นชั้นป้องกันสั้น ๆ ที่ซ้อนกัน แต่ละชั้นปิดประตูคนละบาน: ใครเชื่อมต่อได้, การเชื่อมต่อได้รับการปกป้องอย่างไร, การเชื่อมต่อได้รับอนุญาตให้มาจากที่ไหนบ้าง และเกิดอะไรขึ้นกับ bytes บนดิสก์
ชั้นของการป้องกัน
หัวข้อที่มีชื่อว่า “ชั้นของการป้องกัน”ลองมอง request เป็นสิ่งที่ต้องผ่านประตูหลายบานก่อนจะแตะข้อมูลของคุณ เครือข่ายตัดสินว่าการเชื่อมต่อได้รับอนุญาตเลยหรือไม่ TLS ปกป้อง bytes ระหว่างทาง Authentication ตรวจสอบว่าคุณเป็นใคร และ authorization ตรวจสอบว่าคุณได้รับอนุญาตให้ทำอะไรได้บ้าง:
flowchart LR Client["Application"] --> Net["Network gate — firewall, bind IP, VPC"] Net --> TLS["TLS — encrypts the connection"] TLS --> Auth["Authentication — who are you"] Auth --> RBAC["Authorization — what may you do"] RBAC --> Data["Data — encrypted at rest on disk"]
ไม่มีชั้นเดียวที่เพียงพอ Authentication โดยไม่มีการจำกัดเครือข่ายก็ยังเชื้อเชิญความพยายามแบบ brute-force; เครือข่ายที่ล็อกแน่นแต่ไม่มี auth ก็เชื่อใจทุกคนที่อยู่ข้างใน Defense in depth หมายถึงการเปิดทุกชั้น
Authentication และ roles (RBAC)
หัวข้อที่มีชื่อว่า “Authentication และ roles (RBAC)”ก้าวแรกคือการกำหนดให้ต้องมี authentication เพื่อไม่ให้ใครเชื่อมต่อแบบไม่ระบุตัวตนได้ จากนั้น MongoDB ควบคุมว่าผู้ใช้แต่ละคนทำอะไรได้ผ่าน role-based access control — RBAC คุณสร้างผู้ใช้และมอบ roles ให้พวกเขา และ role คือชุดของ permissions หลักการคือ least privilege: แอปพลิเคชันที่อ่าน reports เพียงอย่างเดียวได้ role แบบอ่านอย่างเดียว ไม่ใช่กุญแจของผู้ดูแลระบบ คุณเปิด auth ในไฟล์ config แล้วจึงสร้างผู้ใช้
# mongod.conf — require authenticationsecurity: authorization: enabled// Create an app user limited to read and write on one databasedb.getSiblingDB("admin").createUser({ user: "library_app", pwd: passwordPrompt(), roles: [{ role: "readWrite", db: "library" }]})เมื่อเปิด auth แล้ว ทุกการเชื่อมต่อต้องแสดง credentials driver ส่ง credentials ไปใน connection string หรือแยกเป็น option ก็ได้:
mongosh "mongodb://library_app@host:27017/library?authSource=admin&tls=true"const uri = "mongodb://library_app:secret@host:27017/library?authSource=admin&tls=true";const client = new MongoClient(uri);await client.connect();uri = "mongodb://library_app:secret@host:27017/library?authSource=admin&tls=true"client = MongoClient(uri)uri := "mongodb://library_app:secret@host:27017/library?authSource=admin&tls=true"client, err := mongo.Connect(options.Client().ApplyURI(uri))if err != nil { return err}let uri = "mongodb://library_app:secret@host:27017/library?authSource=admin&tls=true";let client = Client::with_uri_str(uri).await?;TLS, network rules และ encryption at rest
หัวข้อที่มีชื่อว่า “TLS, network rules และ encryption at rest”อีกสามชั้นทำให้ภาพสมบูรณ์ TLS เข้ารหัส traffic ระหว่าง client และ server เพื่อให้ credentials และข้อมูลไม่ถูกอ่านออกจากสายส่งได้; คุณชี้ mongod ไปที่ certificate แล้วบังคับให้ต้องใช้
# mongod.conf — require TLS and restrict where it listensnet: bindIp: 10.0.1.5,localhost tls: mode: requireTLS certificateKeyFile: /etc/ssl/mongodb.pemsnippet เดียวกันนั้นแสดงประตู network การตั้งค่า bindIp ควบคุมว่า mongod รับการเชื่อมต่อบน interface ไหน — ให้ผูกกับ address ภายใน ไม่ใช่ 0.0.0.0 บน host สาธารณะ ในระบบคลาวด์คุณห่อ server ไว้ใน VPC หรือ private subnet และใช้ firewall หรือ security group เพื่อให้มีเพียง server แอปพลิเคชันของคุณเท่านั้นที่เข้าถึงพอร์ต 27017 ได้เลย สุดท้าย encryption at rest สลับไฟล์ข้อมูลบนดิสก์ เพื่อให้ดิสก์หรือ backup volume ที่ถูกขโมยไปไร้ประโยชน์หากไม่มีกุญแจ; ใน deployment ที่จัดการเองนี่เป็นฟีเจอร์ระดับ storage-engine หรือ filesystem ที่คุณเปิดใช้เอง ส่วนใน managed service เปิดมาให้ตั้งแต่ต้น
MongoDB Atlas: เส้นทางที่ง่าย
หัวข้อที่มีชื่อว่า “MongoDB Atlas: เส้นทางที่ง่าย”การทำทั้งหมดนี้ด้วยมือ — การ provision replica set, สร้างใบรับรอง, ตั้งค่า firewall, หมุนเวียนกุญแจ, จัดตาราง backup — เป็นงานจริงและทำผิดเล็ก ๆ น้อย ๆ ได้ง่าย MongoDB Atlas คือ managed cloud service ของ MongoDB ที่มีอยู่เพื่อให้คุณไม่ต้องทำงานพวกนี้เอง Atlas cluster มาแบบปลอดภัยโดยค่าเริ่มต้น: ต้องมี authentication, TLS เปิดอยู่เสมอ, encryption at rest เปิดใช้งาน และฐานข้อมูล ไม่ สามารถเข้าถึงได้จนกว่าคุณจะเพิ่ม entry ลงใน IP access list เอง นอกจากนั้นยังได้ backup อัตโนมัติพร้อม point-in-time restore และแดชบอร์ด monitoring ที่มี Performance Advisor จากบทเรียนที่แล้วฝังอยู่ในตัว
ใน Compass / Atlas: คุณเชื่อมต่อ Compass กับ Atlas cluster ด้วย connection string ที่คัดลอกมาจาก Atlas UI ซึ่งรวม TLS และผู้ใช้ฐานข้อมูลของคุณไว้แล้ว ใน Atlas เอง Database Access จัดการผู้ใช้และ roles, Network Access จัดการ IP allow-list และแท็บ Backup จัดการ snapshots — สี่ชั้นเดียวกัน นำเสนอเป็นฟอร์มแทนที่จะเป็นไฟล์ config
เคล็ดลับและข้อควรระวัง
หัวข้อที่มีชื่อว่า “เคล็ดลับและข้อควรระวัง”- อย่าเปิดพอร์ต 27017 สู่อินเทอร์เน็ตโดยไม่มี authentication เด็ดขาด นี่คือกฎเหล็ก เพราะข้อมูลรั่วครั้งดัง ๆ เกิดจากเรื่องนี้ทั้งนั้น ผูกกับ interface ส่วนตัวและกำหนดให้ต้องมี auth ก่อนสิ่งอื่นใด
- ใช้ least privilege ให้ผู้ใช้แอปพลิเคชันแต่ละคนได้เฉพาะ roles ที่จำเป็นบนเฉพาะฐานข้อมูลที่ใช้ อย่ามอบ role admin ให้กับโค้ดของแอป
- TLS ปกป้องข้อมูล ระหว่างขนส่ง; encryption at rest ปกป้อง บนดิสก์ คนละชั้นกัน — เปิดทั้งคู่ ไม่ใช่เลือกอย่างเดียว
- การจัดการทั้งหมดนี้เองทำได้แต่มีโอกาสผิดพลาด หากคุณไม่มีเหตุผลที่หนักแน่นพอที่จะรัน cluster ของตัวเอง Atlas ให้การป้องกันเหล่านี้ที่ตั้งค่าถูกต้องมาให้พร้อมใช้
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Self-hosted MongoDB | ควบคุม infrastructure และ config ได้เต็มที่ | ต้องรับผิดชอบ patch, TLS certificate rotation, backup และ security audit เองทั้งหมด |
| MongoDB Atlas | Security เปิดโดยค่าเริ่มต้น, backup และ patch จัดการให้, ลดภาระ ops | ควบคุมรายละเอียดระดับ low-level ได้น้อยกว่า, ต้นทุนเป็นแบบ usage-based ต่างจาก self-hosted |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ใช้ database user เดียวกันสำหรับทุก service หรือทุก environment — ถ้า credential ของ user ตัวเดียวรั่ว ทุก service ที่ใช้ user เดียวกันถูกกระทบหมด ควรแยก user ต่อ service และต่อ environment (dev/staging/prod) เพื่อจำกัดผลกระทบเมื่อเกิดปัญหา
- เข้าใจว่า TLS ปกป้อง data ทั้งหมดแล้วเลยข้าม encryption at rest — TLS ปกป้องเฉพาะข้อมูลระหว่างขนส่งเท่านั้น ถ้า disk หรือ backup snapshot ถูกขโมยไปโดยไม่ได้เข้ารหัส at rest ข้อมูลก็ยังอ่านได้ตรง ๆ
- ตั้ง IP access list ใน Atlas เป็นเปิดกว้างทุก address เพื่อความสะดวกตอน develop แล้วลืมจำกัดก่อนขึ้น production — เปิดกว้างขนาดนั้นเท่ากับปิด network layer ทิ้งไปทั้งอัน authentication เพียงอย่างเดียวไม่ได้ทดแทน network restriction ที่หายไป
💡 ตัวอย่างจากของจริง
เหตุการณ์ MongoDB instance ที่เปิด public โดยไม่มี authentication ที่เป็นข่าวหลายครั้งในอดีต (เช่นคลื่นการโจมตีเรียกค่าไถ่ปี 2017 ที่ instance นับหมื่นเครื่องถูกยึดข้อมูลไป) — เป็นตัวอย่างว่าการข้ามแค่ authentication layer เดียวสร้างความเสียหายได้มากแค่ไหน
ทีมสตาร์ทอัพที่ย้ายจาก self-hosted ไป Atlas — ใช้ Database Access และ Network Access ของ Atlas แทนการจัดการ
mongod.confและ firewall rule เองทุกเครื่อง ลดเวลาที่ทีมเล็ก ๆ ต้องใช้ดูแล security ให้เหลือแค่การตั้งค่าในหน้า UI