

เวลาอยากให้ container เก็บไฟล์ไว้บนเครื่อง วิธีที่เห็นภาพง่ายคือ mount โฟลเดอร์จาก host เข้าไป แล้วให้แอปเขียนผลลง path นั้น แต่พอเริ่มทำงานกลับได้ permission denied ทั้งที่เปิด terminal บน host แล้วสร้างไฟล์ในโฟลเดอร์เดียวกันได้
สองกรณีนี้อาจใช้คนละตัวตนในการเข้าถึงไฟล์ และยังมีเงื่อนไขของ mount กับระบบป้องกันบนเครื่องร่วมอยู่ด้วย การที่ path มองเห็นใน container จึงยังไม่ได้แปลว่า process ข้างในมีสิทธิ์เขียนตามที่ต้องการ
ก่อนเพิ่มสิทธิ์ให้กว้าง ควรเริ่มจากดูว่า process ใดพยายามทำอะไรกับ path ไหนครับ แล้วค่อยไล่เงื่อนไขของไฟล์และตัวตนทีละชั้น จะช่วยแก้เฉพาะส่วนที่จำเป็นและไม่เปลี่ยนสิทธิ์ของข้อมูลอื่นไปด้วย
Bind mount นำไฟล์หรือ directory จากเครื่องที่ Docker daemon ทำงานอยู่มาแสดงใน container หากใช้ daemon อีกเครื่อง source path จึงอ้างเครื่องนั้น ไม่ใช่คอมพิวเตอร์ที่กำลังพิมพ์คำสั่งเสมอไป
ควรตรวจ source กับ destination ของ mount ที่ใช้งานจริงก่อน รวมทั้งเป็นไฟล์หรือ directory ตามที่แอปคาดหรือไม่ บางครั้งโฟลเดอร์ที่คิดว่ามีข้อมูลกลับเป็นคนละ path ทำให้พยายามเขียนผิดที่และตามสิทธิ์ผิดจุดตั้งแต่ต้น

การ mount ทับ directory ที่ image มีไฟล์อยู่แล้วจะทำให้เห็นเนื้อหาจาก mount แทนของเดิมด้วย ถ้าภายใน image เตรียมเจ้าของหรือไฟล์ตั้งต้นไว้ แต่ host directory มีอีกชุดหนึ่ง การตรวจเฉพาะ Dockerfile จึงยังไม่บอกสภาพของไฟล์ที่แอปกำลังใช้จริง
จุดนี้ต่างจากการคิดว่า container ได้สำเนา directory ที่ปรับสิทธิ์ไว้ตอน build มาใช้เสมอ ควรอ่านข้อมูล mount ของ container ปัจจุบันแล้วเทียบกับไฟล์บน host ตามเส้นทางนั้นก่อนแก้
Image สามารถกำหนด USER สำหรับการทำงาน และ Compose หรือคำสั่งเริ่ม container ก็อาจตั้ง user ทับได้ ส่วน entrypoint ของบาง image อาจมีขั้นเตรียมข้อมูลก่อนเปลี่ยนไปใช้ผู้ใช้อีกตัว จึงต้องดู process ที่ทำการเขียนจริง
บน Linux ตัวเลข UID กับ GID มีบทบาทในการตรวจสิทธิ์ไฟล์ ชื่อผู้ใช้ที่แสดงเหมือนกันภายในกับภายนอกไม่ได้รับรองว่าเลขเดียวกัน และชื่อที่ไม่มีในอีกฝั่งก็ยังอาจแทนเลขเจ้าของที่มีผลต่อสิทธิ์อยู่ได้
การใช้คำสั่งอ่านข้อมูลอย่าง id ในบริบทที่ถูกต้อง และดูเจ้าของแบบตัวเลขช่วยแยกกรณีนี้ได้ แต่ต้องเข้าใจว่าการเปิด shell เพิ่มอาจไม่ได้ใช้ user เดียวกับ process แอปหากระบุค่าต่างกัน การตรวจควรตามตัวตนของผู้ที่ล้มเหลว ไม่ใช่ยืนยันจาก shell ที่เปิดด้วย root แล้วเขียนผ่าน
ถ้าใช้ user namespace หรือ rootless mode ยังมีการ map ตัวเลขระหว่าง container กับ host เพิ่มด้วย จึงไม่ควรสรุปว่าค่า root ใน container เท่ากับ root บน host ทุกสภาพแวดล้อม ต้องอ่านรูปแบบที่ daemon นี้ใช้และตรวจ mapping ตามนั้น
หาก mount ถูกตั้ง read-only ต่อให้เจ้าของไฟล์กับ mode ดูเปิดให้เขียนได้ process ก็ยังติดเงื่อนไขของ mount อยู่ การเปลี่ยนเจ้าของไฟล์จึงไม่แก้การเขียนผ่าน mount ที่ตั้งใจให้อ่านอย่างเดียว
ควรแยกด้วยว่ากำลังแก้ไฟล์ที่มีอยู่แล้ว หรือสร้างไฟล์ใหม่ใน directory เพราะการทำงานสองแบบใช้สิทธิ์กับ object ต่างกัน และต้องผ่าน path ของ directory ที่เกี่ยวข้อง ไม่ดูเพียง mode ของไฟล์ปลายทางอันเดียวแล้วตัดสินว่าครบทุกเงื่อนไข

อีกชั้นคือ filesystem หรือระบบควบคุมการเข้าถึงบน host เช่น SELinux ตามการตั้งค่าของเครื่อง หากสิทธิ์พื้นฐานดูถูกต้องแต่ยังถูกปฏิเสธ ควรอ่านหลักฐานจากระบบนั้นก่อนเปลี่ยนค่า ไม่ปิดกลไกทั้งหมดเพื่อให้แอปผ่านแล้วถือว่าทราบสาเหตุแล้ว
Docker Desktop กับ daemon บน Linux โดยตรงก็อาจมีเส้นทางแชร์ไฟล์และเงื่อนไขต่างกัน จึงควรระบุสภาพแวดล้อมเวลาเก็บผล การนำคำสั่งแก้เจ้าของจากอีกเครื่องมาใช้ตามอาจไม่ได้แก้จุดเดียวกันและอาจเปลี่ยนข้อมูลกว้างเกินจำเป็น
ถ้างานต้องเขียนเฉพาะ directory สำหรับข้อมูลออก ก็ควรเตรียมพื้นที่นั้นและกำหนดสิทธิ์ให้ตัวตนที่เกี่ยวข้อง แยกจากไฟล์ตั้งค่าที่แอปต้องอ่านอย่างเดียว การแยกหน้าที่ช่วยให้รู้ว่าการเขียนตรงไหนเป็นสิ่งที่ตั้งใจอนุญาต
การเปลี่ยนเป็น root หรือเปิดสิทธิ์ทุกคนอาจทำให้อาการหายบางกรณี แต่ยังไม่ได้อธิบายว่าตัวตนเดิมขาดสิทธิ์ตรงไหน และอาจเปิดให้ process อื่นเขียนข้อมูลได้เพิ่ม จึงควรเลือกแก้เจ้าของ กลุ่ม หรือรูปแบบการ mount ตามโครงของงานจริง
ก่อนเปลี่ยนสิทธิ์ข้อมูลเดิมต้องรู้ว่ามีบริการอื่นใช้ร่วมอยู่หรือไม่ โดยเฉพาะ directory ที่มีข้อมูลจำนวนมาก การเปลี่ยนเจ้าของแบบ recursive ทั้งต้นไม้อาจกระทบไฟล์ที่ไม่ได้เกี่ยวกับปัญหาหรือทำให้บริการเดิมอ่านไม่ได้ ควรจำกัด path และเก็บข้อมูลเดิมสำหรับย้อนกลับเมื่อจำเป็น
ถ้า image มีข้อกำหนดเรื่อง user กับ directory เฉพาะ ควรใช้เอกสารของ image รุ่นนั้นประกอบ ไม่บังคับเลข UID ที่คุ้นกับทุกบริการ เพราะบางแอปมีขั้นเริ่มต้นและสิทธิ์ที่ต้องจัดเตรียมต่างกัน
เริ่มใน directory ทดสอบที่แยกจากข้อมูลใช้งาน แล้วตรวจการอ่าน สร้างไฟล์ แก้ไข และลบตามสิ่งที่แอปต้องทำ รวมถึงยืนยันว่าจุดที่ตั้งให้อ่านอย่างเดียวถูกปฏิเสธเมื่อพยายามเขียน การเขียนผ่านหนึ่งไฟล์ยังไม่บอกว่าขอบเขตที่เหลือถูกต้องทั้งหมด
หลังแก้ให้เริ่ม container ตามวิธีปกติแล้วตรวจอีกครั้ง เพื่อไม่ให้ผลผ่านเฉพาะ shell ชั่วคราวที่ใช้ตรวจ หากมีการสร้างไฟล์ใหม่ ควรดูเจ้าของกับ mode ของไฟล์นั้นด้วย เพราะรอบถัดไปหรืออีกบริการอาจต้องอ่านมันต่อ
ควรเก็บ source/destination, mount mode, ตัวตน process และข้อความ error ที่ตัดข้อมูลลับแล้วไว้กับผลตรวจ โดยไม่เผยแพร่ path ส่วนตัวที่ไม่จำเป็น บทนี้เป็นวิธีไล่เงื่อนไข ยังไม่ได้เปลี่ยนสิทธิ์หรือทดสอบเขียนไฟล์บน volume ของผู้ใช้
ปัญหาเขียน bind mount ไม่ได้ต้องดูทั้ง path ที่ถูกนำมาใช้ ตัวตน process การ map UID/GID และข้อจำกัดของ mount กับ host เมื่อแยกเงื่อนไขเหล่านี้แล้วค่อยแก้เฉพาะพื้นที่ของงาน เราจะรักษาสิทธิ์ข้อมูลให้ตรงหน้าที่ และยืนยันผลจากการทำงานของแอปจริงได้โดยไม่เปิดขอบเขตเกินกว่าที่ต้องใช้