flawopen.com/Teardowns/cve-2024-5321-kubernetes-windows-container-log-permissions
CVE-2024-5321: Izin Log Kontainer pada Node Windows Kubernetes
CVE-2024-5321 (CVSS 6.1, sedang): pada node Windows, kubelet membuat direktori log pod dengan os.MkdirAll, yang mengabaikan mode izin di Windows, sehingga log mewarisi ACL yang membolehkan BUILTIN\Users membacanya dan Authenticated Users mengubahnya.
Sebuah rumah sakit menyimpan rekam medis setiap pasien di lemari arsip. Saat memesan lemari baru, staf menulis "khusus dokter" di formulir, tetapi di gedung ini kolom kunci diabaikan diam-diam, jadi lemari itu mengikuti aturan bawaan ruangan: semua karyawan boleh membaca dan siapa pun yang punya kartu akses boleh menulis. Perbaikannya adalah petugas yang, setiap kali lemari baru datang, memasang kunci khusus dan membuang aturan bawaan ruangan untuk lemari itu.
Konsep Kunci & Istilah
DACL / ACE- Daftar kontrol akses diskresioner Windows: entri-entri yang menentukan akun mana yang boleh membaca, menulis, atau menjalankan sebuah file atau direktori.
Pewarisan ACL- Secara bawaan, file atau direktori baru di Windows menyalin entri yang dapat diwarisi dari DACL direktori induknya. DACL yang dilindungi mencegah hal itu.
BUILTIN\Users / Authenticated Users- Grup Windows yang sangat luas: semua akun lokal, dan semua akun yang pernah log on. Kubernetes memetakan kontainer yang berjalan sebagai ContainerUser ke BUILTIN\Users saat mengakses file host.
os.MkdirAll di Windowsos.MkdirAll(path, perm)di Go hanya memakaipermdi Unix. Di Windows mode itu diabaikan dan direktori mendapat ACL warisan.
Analisis Akar Masalah (Root Cause)
setupDataDirs() di pkg/kubelet/kubelet.go membuat akar log pod (C:\var\log\pods) dengan os.MkdirAll(dir, 0750). Go mengabaikan mode di Windows, sehingga direktori itu dan file log yang ditulis di dalamnya mewarisi ACL induk, yang memberi BUILTIN\Users akses baca dan NT AUTHORITY\Authenticated Users akses ubah. PR #126104 menambahkan MkdirAll() dan Chmod() di pkg/util/filesystem yang menerjemahkan mode Unix menjadi DACL eksplisit dan menerapkannya dengan PROTECTED_DACL_SECURITY_INFORMATION, lalu memindahkan direktori log, plugin, dan checkpoint kubelet ke fungsi tersebut.
Alur Serangan Langkah demi Langkah
Kubelet membuat akar log
Di node Windows, setupDataDirs() memanggil os.MkdirAll(. Nilai kl.getPodLogsDir(), 0750)0750 diabaikan dan direktori mewarisi ACL induknya.
Grup luas mewarisi akses
Entri warisan memberi BUILTIN\Users akses baca dan NT AUTHORITY\Authenticated Users akses ubah atas direktori log pod dan file yang ditulis runtime ke sana.
Membaca log beban kerja lain
Akun lokal berhak rendah mana pun di node, atau beban kerja yang memasang jalur log lewat hostPath, dapat membaca stdout dan stderr pod lain, yang sering berisi token, string koneksi, atau data pelanggan.
Merusak bukti
Akun yang sama dapat mengedit atau memotong file log sebelum dikirim oleh agen log, sehingga aktivitas tersembunyi dari logging terpusat.
Kode Sumber: Rentan vs Aman
// pkg/kubelet/kubelet.go (kubelet v1.30.2)
func (kl *Kubelet) setupDataDirs() error {
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
return fmt.Errorf("error creating root directory: %v", err)
}
// BUG on Windows: os.MkdirAll ignores the 0750 mode. The directory inherits
// its parent's ACL, which lets BUILTIN\Users read and
// NT AUTHORITY\Authenticated Users modify every pod's log files.
if err := os.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
}
if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
return fmt.Errorf("error creating pods directory: %v", err)
}
return nil
}
// pkg/kubelet/kubelet.go (fixed in v1.30.3, PR #126104)
func (kl *Kubelet) setupDataDirs() error {
if err := os.MkdirAll(kl.getRootDir(), 0750); err != nil {
return fmt.Errorf("error creating root directory: %v", err)
}
// FIX: utilfs.MkdirAll is plain os.MkdirAll on Linux. On Windows it also
// calls utilfs.Chmod, which replaces the inherited ACL with an explicit one.
if err := utilfs.MkdirAll(kl.getPodLogsDir(), 0750); err != nil {
return fmt.Errorf("error creating pod logs root directory %q: %w", kl.getPodLogsDir(), err)
}
if err := os.MkdirAll(kl.getPodsDir(), 0750); err != nil {
return fmt.Errorf("error creating pods directory: %v", err)
}
return nil
}
// pkg/util/filesystem/util_windows.go
func MkdirAll(path string, perm os.FileMode) error {
if err := os.MkdirAll(path, perm); err != nil {
return fmt.Errorf("Error creating directory %s: %v", path, err)
}
return Chmod(path, perm)
}
func Chmod(path string, filemode os.FileMode) error {
// Maps owner, group and other mode bits to ACEs for the file's owner SID,
// its group SID and BUILTIN\Users (BU). For 0750 the result is
// "D:(A;OICI;FA;;;<owner>)(A;OICI;FRFX;;;<group>)(A;OICI;;;;BU)".
// (Abridged: the real function builds this string inline.)
dacl, err := daclForMode(path, filemode)
if err != nil {
return err
}
newSD, err := windows.SecurityDescriptorFromString(dacl)
if err != nil {
return fmt.Errorf("Error creating new security descriptor from DACL string: %v", err)
}
newDACL, _, err := newSD.DACL()
if err != nil {
return fmt.Errorf("Error getting DACL from new security descriptor: %v", err)
}
// PROTECTED_DACL_SECURITY_INFORMATION blocks inheritance from the parent,
// so the BUILTIN\Users and Authenticated Users entries no longer apply.
return windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT,
windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
nil, nil, newDACL, nil)
}
Daftar Periksa Penguatan Sistem Rekayasa
- ✓Perbarui kubelet di setiap node Windows ke 1.30.3, 1.29.7, 1.28.12, 1.27.16 atau lebih baru.
- ✓Daftarkan node Windows dengan
kubectl get nodes -l kubernetes.io/, lalu jalankanos=windowsicacls C:\var\log\podsdi masing-masing: tidak boleh ada entri BUILTIN\Users atau Authenticated Users yang memberi akses baca atau ubah. - ✓Dalam kode Go yang berjalan di Windows, jangan pernah mengandalkan argumen
permdarios.Mkdir,os.MkdirAll,os.WriteFile, atauos.Chmod; pasang DACL yang dilindungi denganwindowsdan periksa di job CI Windows..SetNamedSecurityInfo() - ✓Jangan memasang
C:\var\logatau jalur log node lainnya ke beban kerja lewat hostPath, kecuali untuk agen log tepercaya. - ✓Jauhkan rahasia dari stdout dan stderr kontainer dan samarkan token di log aplikasi, karena direktori log node dapat dibaca lebih banyak pihak daripada pod itu sendiri.