ทำไมแอปใน Kubernetes ถึงเข้าถึง AWS ไม่ได้สักที
เวลาเราเขียนโปรแกรมบน Kubernetes (ระบบจัดการกลุ่มคอนเทนเนอร์) แล้วสั่งให้มันไปดึงข้อมูลจาก S3 (บริการเก็บข้อมูลบนคลาวด์ของ AWS) มักจะเจอปัญหาว่าแอปของเราไม่มีสิทธิ์เข้าถึง ทั้งที่ดูเหมือนตั้งค่าทุกอย่างไว้ถูกต้องแล้ว ปัญหานี้ไม่ได้เกิดจากตัว Kubernetes พัง แต่เป็นเรื่องของ Workload Identity (ตัวตนของแอปตอนรันงาน) ที่เชื่อมต่อกันไม่สมบูรณ์ระหว่างโลกของ Kubernetes และ AWS
คนส่วนใหญ่มักสับสนระหว่าง IRSA และ EKS Pod Identity เพราะมันทำหน้าที่คล้ายกัน คือการระบุว่า Pod (หน่วยเล็กที่สุดของแอปใน Kubernetes) ตัวนี้มีสิทธิ์ทำอะไรได้บ้างบน AWS ถ้าเราเข้าใจกลไกเบื้องหลังของมัน เราจะเลิกเดาสุ่มเวลาเจอ Error และแก้ปัญหาได้ตรงจุดมากขึ้น
สมมติเหมือนคุณมีบัตรพนักงานบริษัท (ServiceAccount) แต่บัตรนั้นยังไม่มีสิทธิ์เปิดเข้าห้องเก็บเอกสาร (S3) ของบริษัท AWS การจะเข้าห้องได้ คุณต้องไปลงทะเบียนบัตรใบนี้กับระบบรักษาความปลอดภัยของอาคารให้เรียบร้อยก่อน ซึ่ง IRSA และ Pod Identity คือคนละวิธีในการ "ลงทะเบียนบัตร" นั่นเอง
รู้จักกับ ServiceAccount ตัวตนของแอปใน Kubernetes
ก่อนจะไปถึงเรื่อง AWS เราต้องเข้าใจสิ่งที่เรียกว่า ServiceAccount (บัญชีผู้ใช้สำหรับแอป) ให้แม่นก่อน มันเป็นวัตถุชิ้นหนึ่งใน Kubernetes ที่ทำหน้าที่เป็น "ชื่อ" ของแอปเราเวลาคุยกับระบบภายในคลัสเตอร์ ทุก Pod ที่รันอยู่จะมี ServiceAccount ติดตัวมาเสมอ ถ้าเราไม่ได้ตั้งค่าอะไรพิเศษ มันจะใช้ค่าเริ่มต้นที่ชื่อว่า default ไปโดยปริยาย
หน้าที่ดั้งเดิมของมันคือการยืนยันตัวตนกับ API Server (ศูนย์กลางสั่งการของ Kubernetes) เพื่อดูว่าแอปนี้มีสิทธิ์อ่านหรือแก้ไขข้อมูลภายในคลัสเตอร์หรือไม่ เช่น สิทธิ์ในการดูรายการของ Pod อื่นๆ หรือการดึงข้อมูล Config (ค่าตั้งค่าของโปรแกรม) ออกมาใช้งาน
ลองดูตัวอย่างไฟล์คอนฟิกของ ServiceAccount แบบง่ายๆ กันครับ
apiVersion: v1
kind: ServiceAccount
metadata:
name: checkout-service
namespace: production
อธิบายโค้ด: บรรทัด apiVersion บอกเวอร์ชันของระบบ kind ระบุว่าคือ ServiceAccount ส่วน metadata คือชื่อและพื้นที่การทำงาน (namespace) ของมัน ผลลัพธ์ที่ได้คือเราจะได้ตัวตนใหม่ชื่อ checkout-service ขึ้นมาในระบบ
RBAC กฎเหล็กที่คุมสิทธิ์ภายในคลัสเตอร์
เมื่อเรามีตัวตนแล้ว เราต้องมีกฎที่บอกว่าตัวตนนั้นทำอะไรได้บ้าง สิ่งนี้เรียกว่า RBAC (การจัดการสิทธิ์ตามบทบาท) ซึ่งประกอบด้วย 3 ส่วนหลัก คือ Role (รายการสิทธิ์ที่ทำได้), Subject (ใครคือคนทำ) และ Binding (ตัวเชื่อมระหว่างคนกับสิทธิ์) ถ้าขาดส่วนใดส่วนหนึ่งไป แอปเราจะกลายเป็นคนไม่มีสิทธิ์ทำอะไรเลย
หลายคนพลาดตรงที่ลืมเชื่อม RoleBinding (การผูกสิทธิ์เข้ากับบัญชี) ทำให้ ServiceAccount มีชื่อแต่ไม่มีอำนาจ การตั้งค่าที่ปลอดภัยที่สุดคือการให้สิทธิ์เท่าที่จำเป็นเท่านั้น เช่น ถ้าแอปแค่ต้องอ่านข้อมูล ก็ให้สิทธิ์แค่ get และ list (ดูรายการ) ห้ามให้สิทธิ์ delete (ลบ) เด็ดขาด
ตัวอย่างการผูกสิทธิ์ให้แอปอ่านข้อมูลได้:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
subjects:
- kind: ServiceAccount
name: checkout-service
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
อธิบายโค้ด: subjects ระบุว่าคือ checkout-service ส่วน roleRef ชี้ไปที่ pod-reader ซึ่งเป็น Role ที่เราสร้างไว้ ผลลัพธ์คือ checkout-service จะได้รับสิทธิ์ตามที่กำหนดใน pod-reader ทันที
ความแตกต่างของ IRSA และ Pod Identity
ทั้ง IRSA (IAM Roles for Service Accounts) และ EKS Pod Identity ถูกสร้างมาเพื่อแก้ปัญหาเดียวกัน คือการส่งต่อตัวตนจาก Kubernetes ไปหา AWS โดยไม่ใช้รหัสผ่านแบบถาวร แต่ทั้งสองวิธีมีวิธีการทำงานต่างกันที่ระดับพื้นฐาน IRSA ใช้การทำ OIDC Provider (ตัวกลางยืนยันตัวตนด้วยโทเค็น) ส่วน Pod Identity ใช้ Agent (โปรแกรมเสริม) ที่ทำงานในคลัสเตอร์
IRSA จะทำงานโดยการเพิ่ม Annotation (การจดบันทึกพิเศษ) ลงใน ServiceAccount เพื่อให้ AWS เชื่อใจว่าบัญชีนี้คือของจริง วิธีนี้เป็นมาตรฐานที่ใช้กันมานานและมีความเสถียรสูงมาก แต่ก็ตั้งค่ายากพอสมควรสำหรับมือใหม่ เพราะต้องยุ่งกับเรื่องใบรับรองและนโยบายความปลอดภัยที่ซับซ้อน
ในขณะที่ EKS Pod Identity คือวิธีใหม่ที่ AWS ออกแบบมาให้ง่ายขึ้นมาก โดยเราแค่สร้างการเชื่อมต่อระหว่าง ServiceAccount กับ IAM Role (บทบาทของ AWS) ผ่านหน้าจอจัดการของ AWS โดยตรง ไม่ต้องไปตั้งค่า OIDC ให้ปวดหัวอีกต่อไป ถ้าคุณเพิ่งเริ่มแนะนำให้ใช้ Pod Identity เพราะจัดการง่ายกว่าและลดโอกาสพลาด
ทำไมต้องแยกสิทธิ์ภายในและภายนอก
หัวใจสำคัญที่โปรแกรมเมอร์ต้องจำคือ RBAC คุมแค่ภายใน Kubernetes เท่านั้น มันไม่มีอำนาจไปสั่ง AWS ได้เลย การที่แอปของคุณเข้า S3 ไม่ได้ อาจเป็นเพราะคุณลืมตั้งค่า IRSA หรือ Pod Identity ทั้งที่ RBAC ของคุณถูกต้องเป๊ะๆ แล้ว สิ่งนี้คือช่องโหว่ที่คนมักมองข้าม
ถ้าเราเผลอให้สิทธิ์ IAM Role กว้างเกินไป เช่น ให้สิทธิ์ "อ่านทุกอย่างใน S3" ทั้งที่แอปแค่ต้องการอ่านไฟล์เดียว นี่คือความเสี่ยงด้านความปลอดภัยที่ใหญ่หลวง การทำ Least Privilege (ให้สิทธิ์น้อยที่สุดเท่าที่จำเป็น) คือทักษะสำคัญที่แยกโปรแกรมเมอร์เก่งๆ ออกจากมือสมัครเล่น
สรุปคือเราต้องตรวจสอบ 2 ชั้นเสมอ ชั้นแรกคือ RBAC ดูว่าแอปเราคุยกับ Kubernetes ได้ไหม ชั้นที่สองคือ IRSA หรือ Pod Identity ดูว่าแอปเราคุยกับ AWS ได้ไหม ถ้าผ่านทั้งสองชั้นนี้ แอปของคุณจะทำงานได้ไร้ปัญหา
สรุป: การนำไปใช้จริงในงานพัฒนา
ในการทำงานจริง เมื่อคุณได้รับมอบหมายให้สร้างแอปที่ต้องคุยกับ AWS ขั้นตอนที่ควรทำคือ 1. สร้าง ServiceAccount ให้แอป 2. กำหนดสิทธิ์ RBAC ให้แอปคุยกับ Kubernetes ได้ตามหน้าที่ 3. เลือกใช้ EKS Pod Identity เพื่อเชื่อมต่อกับ IAM Role ที่จำกัดสิทธิ์เฉพาะไฟล์ที่ต้องการเท่านั้น
ตัวอย่างสถานการณ์: หากคุณทำโปรเจกต์อัปโหลดรูปภาพเข้า S3 สิ่งที่ต้องทำคือสร้าง IAM Role ที่อนุญาตให้ s3:PutObject เฉพาะโฟลเดอร์ /uploads เท่านั้น จากนั้นผูก Role นี้เข้ากับ ServiceAccount ของ Pod อัปโหลดรูปภาพผ่าน EKS Pod Identity เพียงเท่านี้แอปของคุณก็จะปลอดภัยและทำงานได้ถูกต้องตามหลักการวิศวกรรมซอฟต์แวร์
การเข้าใจกลไกเหล่านี้จะช่วยให้คุณเลิกกลัว Error ที่เกี่ยวกับสิทธิ์ และกลายเป็นโปรแกรมเมอร์ที่แก้ปัญหาได้ลึกถึงระดับโครงสร้างพื้นฐาน ซึ่งเป็นทักษะที่บริษัทชั้นนำมองหาในตัวคนทำงานสาย DevOps (คนดูแลระบบและพัฒนาซอฟต์แวร์) ครับ
ที่มา: Build an MCP Server in Go (Part 3): How IRSA and EKS Pod Identity Actually Work — DEV Community