Jaringan di dalam kluster Kubernetes bersifat datar dan terbuka. Secara bawaan, setiap Pod dapat menghubungi Pod mana pun, termasuk Pod di namespace lain, tanpa pemeriksaan identitas. NetworkPolicy adalah objek yang membatasi jalur trafik tersebut dengan mendeklarasikan sumber, tujuan, dan port yang diizinkan. Topik ini membahas perilaku bawaan yang mengizinkan segalanya, struktur manifest NetworkPolicy, syarat dukungan CNI (Container Network Interface), serta simulasi evaluasi kebijakan yang dapat dijalankan di sandbox.
Perilaku bawaan yang mengizinkan segalanya#
Semua Pod dapat saling berkomunikasi sebelum kebijakan apa pun dibuat. Model ini memudahkan pengerjaan awal, tetapi menimbulkan risiko pada kluster yang digunakan bersama, karena satu Pod yang disusupi dapat menjangkau layanan lain di seluruh namespace tanpa halangan apa pun.
Aturan isolasinya sederhana dan simetris. Pod yang tidak dipilih oleh kebijakan apa pun tetap terbuka sepenuhnya. Begitu sebuah Pod dipilih oleh setidaknya satu NetworkPolicy pada arah ingress, Pod tersebut menjadi terisolasi, dan hanya trafik yang diizinkan oleh gabungan kebijakan yang cocok yang dapat masuk. Kebijakan bersifat aditif, artinya dua kebijakan yang menyasar Pod yang sama saling menambah daftar sumber yang diizinkan, bukan saling meniadakan.
Isolasi juga berlaku untuk arah egress melalui nilai Egress pada bidang policyTypes, dan kebijakan yang membatasi kedua arah dapat ditulis sekaligus. Topik ini berfokus pada arah ingress karena arah tersebut paling sering diatur terlebih dahulu pada kluster nyata. Apabila arah egress ikut dibatasi, kebijakan tersebut perlu tetap mengizinkan permintaan DNS ke DNS kluster, karena pemblokiran pada port 53 membuat penyelesaian nama Pod ikut gagal.
Manifest NetworkPolicy dan semantik pemilihnya#
Manifest di bawah ini melindungi Pod berlabel app: api di namespace produksi. Bidang spec.podSelector memilih Pod yang menjadi target kebijakan, bidang policyTypes menyatakan arah yang diatur, dan daftar spec.ingress berisi aturan yang diizinkan. Satu aturan memuat daftar from beserta daftar port yang boleh dilewati.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: lindungi-api
namespace: produksi
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: produksi
ports:
- protocol: TCP
port: 8080Kunci dari aturan di atas terletak pada satu elemen from yang memuat dua selector sekaligus. Dalam satu elemen, podSelector dan namespaceSelector berlaku bersamaan, sehingga yang diizinkan hanyalah Pod berlabel app: web yang berada di namespace berlabel kubernetes.io/metadata.name: produksi. Apabila keduanya ditulis sebagai dua elemen terpisah dalam daftar from, maknanya berubah menjadi gabungan, yaitu semua Pod berlabel app: web di namespace mana pun ditambah semua Pod di namespace produksi.
Perintah berikut menerapkan kebijakan tersebut lalu menampilkannya beserta podSelector-nya.
# tidak-dijalankan
# terapkan NetworkPolicy ke namespace produksi
kubectl apply -f networkpolicy.yaml
# tampilkan kebijakan beserta podSelector-nya
kubectl get networkpolicy -n produksi
kubectl describe networkpolicy lindungi-api -n produksiNAME POD-SELECTOR AGE
lindungi-api app=api 5s
Name: lindungi-api
Namespace: produksi
Spec:
PodSelector: app=api
PolicyTypes: IngressDukungan CNI pada kluster#
NetworkPolicy adalah objek yang dideklarasikan ke API server, sedangkan penegakannya dilakukan oleh plugin CNI, yaitu komponen yang mengatur jaringan Pod pada kluster. Kluster yang menggunakan CNI tanpa dukungan kebijakan menerima manifest apa adanya, tetapi trafik tidak pernah dibatasi. Proyek seperti Calico dan Cilium menjadi contoh CNI yang menegakkan NetworkPolicy, dan setiap distribusi kluster umumnya menyebut dukungan kebijakannya pada dokumentasinya.
Keadaan tanpa dukungan ini sulit dikenali dari daftar objek. Objek NetworkPolicy tetap tampil di kubectl get, statusnya dianggap siap, dan tidak ada pesan error yang mengingatkan bahwa aturan tidak pernah ditegakkan. Satu-satunya pemeriksaan yang meyakinkan adalah pengujian langsung, yaitu menjalankan dua Pod uji, satu yang cocok dengan aturan dan satu yang tidak, lalu memastikan hasil koneksi keduanya berbeda.
Simulasi evaluasi kebijakan#
Semantik kebijakan di atas dapat diuji tanpa kluster dengan menelusuri aturannya secara langsung. Skrip berikut membaca networkpolicy.yaml menggunakan PyYAML, lalu mengevaluasi lima pasangan sumber dan tujuan terhadap podSelector kebijakan, kedua selector pada elemen from, dan daftar port. Kasus terakhir sengaja menargetkan Pod yang tidak dipilih kebijakan untuk memperlihatkan perilaku Pod yang tidak terisolasi. Pemeriksaannya mengikuti urutan kebijakan nyata, yaitu kecocokan podSelector, kecocokan sumber pada setiap elemen from, lalu kecocokan port.
"""Evaluasi manifest NetworkPolicy terhadap beberapa pasangan sumber dan tujuan."""
import yaml
with open("networkpolicy.yaml", encoding="utf-8") as berkas:
kebijakan = yaml.safe_load(berkas)
spec = kebijakan["spec"]
pod_selector = spec["podSelector"]["matchLabels"]
ns_kebijakan = kebijakan["metadata"]["namespace"]
def label_cocok(labels, selector):
return all(labels.get(k) == v for k, v in selector.items())
def cocok_dari(pod_sumber, ns_sumber, dari):
label_pod = {"app": pod_sumber}
label_ns = {"kubernetes.io/metadata.name": ns_sumber}
ps = dari.get("podSelector", {}).get("matchLabels", {})
nss = dari.get("namespaceSelector", {}).get("matchLabels", {})
cocok_pod = label_cocok(label_pod, ps)
if "namespaceSelector" in dari:
cocok_ns = label_cocok(label_ns, nss)
else:
# podSelector saja berarti Pod di namespace kebijakan
cocok_ns = ns_sumber == ns_kebijakan
return cocok_pod and cocok_ns
# kasus uji: (pod sumber, namespace sumber, label pod tujuan, namespace tujuan, port)
kasus = [
("web", "produksi", {"app": "api"}, "produksi", 8080),
("web", "pengembangan", {"app": "api"}, "produksi", 8080),
("jobs", "produksi", {"app": "api"}, "produksi", 8080),
("web", "produksi", {"app": "api"}, "produksi", 9090),
("web", "produksi", {"app": "web"}, "produksi", 8080),
]
print(f"Kebijakan {kebijakan['metadata']['name']} di namespace {ns_kebijakan}")
print(f"podSelector kebijakan : {pod_selector}")
print()
for pod_sumber, ns_sumber, label_tujuan, ns_tujuan, port in kasus:
if not label_cocok(label_tujuan, pod_selector) or ns_tujuan != ns_kebijakan:
hasil = "DIIZINKAN (tujuan tidak dipilih kebijakan)"
else:
diizinkan = False
for aturan in spec.get("ingress", []):
port_cocok = any(p["port"] == port for p in aturan.get("ports", []))
for dari in aturan.get("from", []):
if cocok_dari(pod_sumber, ns_sumber, dari) and port_cocok:
diizinkan = True
hasil = "DIIZINKAN" if diizinkan else "DITOLAK"
tujuan = f"{label_tujuan['app']} ({ns_tujuan}):{port}"
print(f" {pod_sumber} ({ns_sumber}) -> {tujuan} : {hasil}")Kebijakan lindungi-api di namespace produksi
podSelector kebijakan : {'app': 'api'}
web (produksi) -> api (produksi):8080 : DIIZINKAN
web (pengembangan) -> api (produksi):8080 : DITOLAK
jobs (produksi) -> api (produksi):8080 : DITOLAK
web (produksi) -> api (produksi):9090 : DITOLAK
web (produksi) -> web (produksi):8080 : DIIZINKAN (tujuan tidak dipilih kebijakan)Baris pertama diizinkan karena label Pod sumber, label namespace sumber, dan port 8080 semuanya cocok. Baris kedua ditolak karena namespace pengembangan tidak memenuhi namespaceSelector, baris ketiga ditolak karena Pod jobs tidak berlabel app: web, dan baris keempat ditolak karena port 9090 tidak tercantum pada aturan. Baris kelima diizinkan tanpa melihat aturan mana pun karena Pod berlabel app: web tidak dipilih podSelector kebijakan, sehingga Pod tersebut tidak pernah terisolasi. Kelima hasil tersebut identik dengan penegakan kebijakan oleh CNI yang mendukung NetworkPolicy, sehingga skrip yang sama dapat menjadi acuan cepat sebelum manifest diterapkan ke kluster.
Kesalahan umum#
Tiga kesalahan berikut paling sering muncul saat NetworkPolicy mulai diterapkan. Ketiganya menyebabkan kebijakan yang tampak benar tetapi tidak bekerja sesuai maksud.
- Menganggap kebijakan sudah ditegakkan padahal CNI tidak mendukungnya. Gejalanya tidak ada, karena objek tampil normal dan tidak ada pesan error. Perbaikannya adalah memverifikasi dukungan kebijakan pada dokumentasi CNI, lalu mengujinya dengan dua Pod uji sebelum mengandalkannya.
- Melupakan sifat aditif antara kebijakan. Kebijakan baru yang dimaksudkan untuk membatasi tidak menghapus izin yang diberikan kebijakan lain pada Pod yang sama. Perbaikannya adalah memeriksa seluruh kebijakan yang menyasar Pod tersebut, bukan hanya kebijakan yang baru ditulis.
- Salah ketik label pada selector. Trafik yang sah ikut terputus, dan gejalanya berupa aplikasi yang langsung gagal setelah kebijakan diterapkan. Perbaikannya adalah mencocokkan label aktual dengan
kubectl get pods --show-labelssebelum kebijakan diterapkan.
Pola pemeriksaannya selalu berurutan, yaitu memastikan dukungan CNI, memeriksa label aktual, lalu meninjau kebijakan lain yang menyasar Pod yang sama. Urutan ini menjaga agar perubahan kebijakan tidak menggandakan masalah yang belum selesai.
Ringkasan#
- Tanpa kebijakan, semua Pod dapat saling mengakses lintas namespace, sedangkan Pod yang dipilih kebijakan ingress menjadi terisolasi dan hanya menerima sumber yang ada pada daftar aturannya.
- Satu elemen
frommenggabungkanpodSelectordannamespaceSelectorsecara bersamaan, sedangkan elemen terpisah diperlakukan sebagai alternatif yang digabungkan. - Penegakan NetworkPolicy bergantung pada CNI yang mendukungnya, sehingga keberadaan objek di API server tidak berarti pembatasan sudah berjalan.
Referensi#
- Network Policies — Dokumentasi Kubernetes — Konsep NetworkPolicy, semantik podSelector dan namespaceSelector, serta sifat aditif kebijakan.