ปัญหาที่อาจจะเจอกับการใช้งาน AWS Load Balancer Controller กับ Security Group
ช่วงนี้มีงานหนึ่งที่ทีมเราเจอปัญหาแปลก ๆ ตอน deploy Kubernetes Service ที่ใช้ AWS Load Balancer Controller (LBC) แล้วฝั่งลูกค้าไม่สามารถเข้าถึง service ได้ทั้งจากใน office และจากที่บ้านที่ต่อ VPN เข้า AWS
ปัญหานี้ทำให้เราต้องกลับมาทบทวนเรื่อง Security Group (SG) ใน AWS และการทำงานของ LBC อีกรอบ แล้วก็พบว่ามีจุดน่าสนใจหลายอย่าง เลยขอมา share ไว้ตรงนี้เผื่อใครเจอเคสคล้าย ๆ กันครับ
ปูพื้นฐานของ AWS กันก่อน
AWS Load Balancer Controller คืออะไร
AWS LBC เป็น Kubernetes controller ที่ช่วยให้เราสามารถสร้างและจัดการ AWS Elastic Load Balancers (ELB) ได้โดยอัตโนมัติจาก Kubernetes resource Service
(OSI layer 4 = TCP) หรือ Ingress
(OSI layer 7 = HTTP) ซึ่งช่วยให้การทำงานร่วมกันระหว่าง Kubernetes กับ AWS เป็นไปอย่างราบรื่น
Service manifest ของเราตอนแรกหน้าตาประมาณนี้
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: my-service
ports:
- port: 443
name: https
targetPort: 8080
AWS LBC มันก็จะไปสร้าง ELB ขึ้นมาตัวนึงที่ชื่อว่า my-service-XXX
ให้โดยอัตโนมัติ แล้วเราก็สามารถเข้าถึง Kubernetes workload ผ่าน ELB อันนั้น
Security Group ใน AWS คืออะไร
Security Group เป็นกลุ่มของกฎที่ควบคุมการเข้าถึง network ของ AWS Resources เช่น EC2 Instances หรือ Load Balancers โดยกำหนดว่า IP หรือ port ใดบ้างที่สามารถเข้าถึงหรือออกจาก Resource นั้นได้
กลับมาที่งานของเรา
โจทย์ของเราคือทำอย่างไรให้ traffic สามารถเข้าถึง
my-service
ทั้งจากใน office และจากที่บ้านที่ต่อ VPN เข้า AWS
วิธีการแก้ปัญหามีด้วยกัน 2 วิธี ได้แก่
1. กำหนด loadBalancerSourceRanges
ใน Kubernetes Service
loadBalancerSourceRanges
เป็น field ที่ใช้ใน Kubernetes Service แบบ type: LoadBalancer
ซึ่งช่วยกำหนดว่า IP ranges ไหนบ้างที่สามารถเข้าถึง Load Balancer นี้ได้ พูดง่าย ๆ มันเป็น whitelist ของ IP address ที่เรายอมให้เข้า service นี้ได้จากภายนอก โดย AWS LBC จะไปสร้าง Security Group แบบ default ของมันเอง แล้วเปิด rule ให้ตรงกับ IP พวกนี้
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
selector:
app: my-service
ports:
- port: 443
name: https
targetPort: 8080
loadBalancerSourceRanges:
- 203.0.113.0/24
- 198.51.100.0/24
2. Configure Security Group ที่จะใช้กับ Load Balancer
เราสามารถ configure Security Group ที่จะใช้กับ Load Balancer ได้โดยใช้ annotation service.beta.kubernetes.io/aws-load-balancer-security-groups
เช่น
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-0123456789abcdef0
spec:
type: LoadBalancer
selector:
app: my-service
ports:
- port: 443
name: https
targetPort: 8080
ในกรณีที่เราไม่ได้กำหนด annotation นี้ AWS LBC จะสร้าง Security Group ใหม่โดยอัตโนมัติและจัดการ access control ให้เอง
หากเรากำหนด Security Group เองโดยใช้ annotation ข้างต้น หมายความว่าเราต้องการควบคุม Security Group เองแทนที่จะใช้ default เช่น ต้องใช้ Security Group เดียวกันกับ resource อื่นใน AWS, ต้องใช้ร่วมกับ firewall policy, หรือมี workflow พิเศษ (ซึ่งก็ครอบคลุมไปถึงโจทย์ของเรา) เราจำเป็นต้องจัดการ access control ระหว่าง Load Balancer กับ Backend Instances หรือ ENIs เอง
ถ้าใส่ทั้งสองอย่างพร้อมกัน ระบบจะเลือกใช้ Security Group ที่เรากำหนดไว้ผ่าน annotation
service.beta.kubernetes.io/aws-load-balancer-security-groups
และ จะไม่สนใจค่าในloadBalancerSourceRanges
เลย
แต่ AWS LBC มี annotation service.beta.kubernetes.io/aws-load-balancer-manage-backend-security-group-rules
ที่เมื่อกำหนดเป็น "true"
จะช่วยจัดการกฎเหล่านี้ให้อัตโนมัติ ถึงแม้เราจะระบุ Security Group เองไว้ก็ตาม เช่น
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-security-groups: sg-0123456789abcdef0
service.beta.kubernetes.io/aws-load-balancer-manage-backend-security-group-rules: "true"
spec:
type: LoadBalancer
selector:
app: my-service
ports:
- port: 443
name: https
targetPort: 8080
loadBalancerSourceRanges:
- 203.0.113.0/24
- 198.51.100.0/24
เท่านี้ตัว Load Balancer ก็จะเปิดทางให้กับ Backend Instances ได้ถูกต้อง แม้ Security Group ที่ระบุจะถูกควบคุมจากเราก็ตาม
ข้อควรระวัง
หากเราลบ Security Group ที่ถูกสร้างโดย AWS LBC ออกผ่าน AWS Console แล้วทำการ redeploy Service ใน Kubernetes ใหม่ AWS LBC จะไม่ทราบว่า Security Group ถูกลบไปแล้ว และจะไม่สร้างหรือ update อะไรเพิ่มเติม ดังนั้น ควรหลีกเลี่ยงการลบ Security Group โดยตรงจาก AWS Console