yeke.io · dokümanlar · guardrail

Guardrail politikaları

Bir işlemin ne zaman duracağını veya ek onay isteyeceğini politikalarla belirleyin. Bu rehber CEL koşullarını, etkileri, örnekleri ve politikaları üretime almadan önce test etmeyi anlatır.

Dosya modu (YEKE_POLICY_DIR) her katmanda çalışır. İmzalı paket modu, çift onay alanı ve bakım penceresi Enterprise'dır ve bu sayfada ayrı bir bölümde işaretlenmiştir.

Politika nedir, zincirde nerede koşar

Politikalar mevcut yetkileri daraltabilir veya ek kontrol isteyebilir. Kubernetes RBAC’in vermediği bir yetkiyi veremez.

YEKE'de her yazma tek bir zincirden geçer ve guardrail o zincirin bir halkasıdır. Sıra sabittir; politika dry-run'dan sonra koşar, yani apiserver'ın "uygulansaydı ne olurdu" cevabı elindeyken karar verir.

POST /operations
  → doğrulama → önceki hâl → koleksiyon genişletme → sınıflandırma
  → dry-run → guardrail → plan hash'i → onay kartı → apply

Bunun pratik sonucu, koşulunuzun elindeki bilgidir: object alanı dry-run'ın döndürdüğü nesnedir (yoksa istek gövdesi), step.dryRun.changedPaths ise gerçekten değişecek yolların listesidir. Politika bir tahmine değil, ölçülmüş bir sonuca bakar.

Politikanın yapamadıkları

  • Kubernetes RBAC'in yerine geçmez. İstek apiserver'a kullanıcının kendi kimliğiyle gider ve son kararı apiserver verir. Guardrail, RBAC'in verdiği yetkiyi genişletemez ve RBAC'in reddettiğini onaylayamaz — önüne kapı koyar, yerine geçmez.
  • allow ya da bypass etkisi yoktur. Dört etki var (deny, require, warn, redact) ve hiçbiri gevşetmez. Guardrail yalnızca sıkılaştırır.
  • Yapısal onay tabanı politikadan bağımsızdır. Politika seti bomboş olsa bile her yazma en az standard, destructive sınıflanan her adım en az elevated onay ister. "Onaysız yıkıcı işlem yok" iddiası politika hijyenine değil koda dayanır — bir politika bu tabanın altına inemez.
  • Politika hatası "serbest" demek değildir. match çalışma anında hata verirse o adım deny sayılır ve kartta Politika hatası olarak politikanın id'siyle görünür. Bedeli gerçektir: bozuk bir politika işlemleri durdurur — ama görünür şekilde durdurur.

Dosya modu ve alanlar

Dosya modunda politika değişikliklerini yüklemek için core’u yeniden başlatın.

YEKE_POLICY_DIR bir dizin gösterir; içindeki *.yaml ve *.yml dosyaları açılışta, ad sırasına göre yüklenir. Bir dosya ya politika belgesidir (üst düzey policies:) ya da bakım takvimidir (üst düzey freezes:) — ikisi aynı dosyada bulunamaz, yükleyici reddeder. Ayrım dosyanın adından değil üst düzey anahtardan yapılır: dosyayı yeniden adlandırmak içeriğini değiştirmez.

# /etc/yeke/policies/10-uretim.yaml
policies:
  - id: kurum.uretim-silme
    description: "Üretim namespace'lerinde silme"
    enabled: true
    match: 'step.action == "delete" && step.target.namespace == "uretim"'
    effect: require
    level: elevated
AlanZorunluNe yapar
idevet Politikanın adı (1–128 karakter). Kartta ve denetim izinde görünür. Aynı id iki kaynakta tanımlanırsa core açılmaz — hangisinin geçerli olduğu belirsiz kalamaz.
descriptionhayır Serbest açıklama. messageCode ve message yoksa kartta gerekçe olarak bu görünür; o da yoksa politikanın id'si görünür.
enabledhayır (true) false yazılan politika yine derlenir ama değerlendirmeye girmez. Kapalı bir politikanın bozuk olduğunu açıldığı gün öğrenmek, hatayı en kötü ana ertelemek olurdu.
matchevet CEL ifadesi (1–8192 karakter); bool dönmek zorunda. Derlenemezse core açılmaz.
effectevet deny · require · warn · redact. Anlamları aşağıdaki tabloda.
levelhayır standard ya da elevated. Yalnız effect: require ile yazılabilir; başka bir etkiyle yazılırsa core açılmaz. Yazılmazsa standard.
messagehayır Eşleşmenin tek satırlık gerekçesi, operatörün kendi cümlesi (≤2048 karakter). messageCode de yazılmışsa bu alan hiç okunmaz.
messageCodehayır Gerekçenin kodu — kapalı küme (aşağıda). Kod kazanır, çünkü çevrilebilen odur: kartta kullanıcının kendi dilinde çıkar.
flagshayır Sınıflandırmaya eklenecek bayraklar. irreversible bayrağını yalnız politika atar; kart onu "geri alınamaz" olarak çizer.
caveatshayır Kartta gösterilecek ek uyarılar — operatörün kendi cümleleri. Arayüz bunları "sunucudan geldi" etiketiyle çizer ve çevirmez.
caveatCodeshayır Uyarının kodu — kapalı küme (aşağıda). Kartta kodlar önce, serbest metin sonra gelir.
severityhayır Adımın yıkıcılık sınıfını yükseltir. Tek kabul edilen değer destructive; mutating yazmak bir düşürme girişimidir ve reddedilir. effect: redact ile yazılamaz.
redactPathskoşullu Maskelenecek alan yolları. Yalnız effect: redact ile yazılabilir ve orada zorunludur — boş liste de reddedilir.
requireSecondApprovalhayır Enterprise. true ise eşleşen plan ikinci bir onaycının rızasını ister. Etkiden bağımsızdır: bir warn politikası da ikinci bir göz isteyebilir.
requiredApproverGrouphayır Enterprise. Onaycı kümesini bir gruba daraltır. requireSecondApproval: true olmadan yazılamaz — istenmeyen bir onayı daraltmak sessizce hiçbir şey yapmazdı.

Tanımadığı anahtarı yutmaz, açılışta ölür

  • Yazım hatası sessizce geçmez. Şema katıdır: yukarıdaki listede olmayan bir anahtar (levell, affect) reddedilir. Yutulsaydı operatör "yazdım ama çalışmıyor" ile baş başa kalırdı.
  • Bozuk bir politika core'u açmaz. Ayrıştırılamayan YAML, şemaya uymayan alan, derlenemeyen match, tekrar eden id — dördü de açılışı durdurur. Bozuk politikayı atlayıp devam etmek, operatörün yazdığını sandığı ama sistemin hiç yüklemediği bir kural üretirdi.
  • YEKE_POLICY_DIR verilip okunamazsa da açılmaz. Dizin yoksa değişkeni hiç vermeyin: var sayıp okuyamamak, politikaların sessizce yüklenmemesi demektir.
  • Değişiklik = dosya + yeniden başlatma. Dosya modunda politika için bir yazma ucu yoktur; yürürlükteki set süreç ömrü boyunca sabittir. Yeniden başlatmadan yürürlüğe giren tek kaynak imzalı pakettir (aşağıda).

match yazımı — CEL bağlamı

Adlandırma Kubernetes'in ValidatingAdmissionPolicy sözlüğünü izler: object ve oldObject orada ne demekse burada da o demek.

İfade adım başına değerlendirilir — genişletilmiş her hedef ayrı görünür — ve bool dönmek zorundadır. Bool olmayan bir sonuç (ör. yalnızca step.action yazmak) hatadır, "doğru" sayılmaz.

Değişkenİçerik
op.source Planı kim kurdu: "ui" (arayüz), "nl" (sohbet), "api" (doğrudan API çağıranı; kabuk da şemanın sözlüğünde bir API çağıranıdır).
op.identity.user
op.identity.groups
İsteğin apiserver'a gideceği Kubernetes kimliği ve grupları.
op.cluster.id
op.cluster.name
Hedef cluster.
op.cluster.execRecording Cluster'ın terminal kaydı için duruşu — lisanstan bağımsız. Yapılandırma denetimi için: "bu cluster kayıt için ayarlanmış mı".
op.cluster.recordingActive Duruş ve session-recording lisansı usea izin veriyor — bu oturumda kaydın gerçekten başlayıp başlamayacağı. Lisans kaldırıldığında duruş true kalır ama bu alan false olur; güvence isteyen kural bunu okumalı.
op.revertOf Bu plan bir geri alma ise kaynak planın kimliği, değilse null.
step.action create · update · patch · delete · stream.
step.method
step.path
Adımın HTTP fiili ve apiserver yolu — startsWith, contains, matches ile sınanabilir.
step.target.schemaId Hedefin şema kimliği: grup varsa grup.tekil (apps.deployment), çekirdek grupta yalnız tekil ad (pod).
step.target.group
step.target.version
step.target.kind
step.target.resource
API grubu (çekirdek grup ""), sürüm, tip adı ve çoğul kaynak adı.
step.target.namespaced Tip namespace kapsamlı mı (bool).
step.target.namespace
step.target.name
step.target.subresource
Hedefin namespace'i, adı ve subresource'u. Üçü de her zaman doludur; yokluk "" ile temsil edilir, eksik anahtar olarak değil.
step.classification.severity mutating ya da destructive.
step.classification.flags Bayrak listesi: cluster-scoped, collection, finalizers, owner-managed, orphan-delete, dry-run-unsupported, irreversible, stream, conflicting-declaration ve subresource:<ad> biçiminde tipe özgü bayraklar.
step.dryRun.status ok · failed · unsupported · skipped · not-applicable.
step.dryRun.changedPaths Dry-run'ın ölçtüğü, gerçekten değişecek alan yollarının listesi.
object Yeni hâl: dry-run sonucu, yoksa istek gövdesi. delete adımında null.
oldObject Canlı önceki hâl. create adımında null.

İki farklı alan sınıfı — ve has() kuralı

op ve step altındaki her alan sözleşme alanıdır ve her zaman doludur; doğrudan okuyabilirsiniz. Buna karşılık object ve oldObject gerçek Kubernetes nesneleridir ve alanları eksik olabilir — eksik alan okumak CEL'de hatadır, sessizce false değil. Hata da fail-closed tarafa düşer, yani politikanız yanlışlıkla plan reddedebilir. Kural basit: object / oldObject altına inen her yolu has() ile koruyun.

# yanlış — nesnede spec yoksa politika hata verir, adım deny olur
match: 'object.spec.replicas == 0'

# doğru — has() null kök üstünde de fırlatmaz, false döner
match: 'has(object.spec) && has(object.spec.replicas) && object.spec.replicas == 0'

Desteklenen sözdizimi

Motorun semantiği her açılışta 54 ifadelik bir uyum korpusuyla sınanır; geçmezse core açılmaz. Aşağıdaki yapıların hepsi o korpusta doğrulanmıştır:

  • Karşılaştırma ve mantık: ==, !=, &&, ||, !, üçlü işleç (? :). Kısa devre çalışır (false && <hata> = false) ama hata yutulmaz: true && <hata> hatadır.
  • in: hem liste üyeliği (step.target.resource in ["pods", "nodes"]) hem harita anahtarı ("kritik" in oldObject.metadata.labels).
  • has(): alan var mı. Yok olan alanda false döner, hata vermez.
  • İndeksleme: oldObject.metadata.labels["app"], step.classification.flags[0]. Dikkat: olmayan bir harita anahtarına ya da liste indeksine erişmek hatadır — indekslemeden önce in ya da has() ile sorun.
  • Metin fonksiyonları: startsWith(), endsWith(), contains(), matches() (düzenli ifade).
  • Makrolar ve boyut: exists(), all(), size().
  • null karşılaştırması: object == null, op.revertOf != null. Ama null bir kökün altına inmek (object.metadata.name) hatadır.
  • Tanınmayan her şey açık hata verir: bilinmeyen değişken, bilinmeyen alan, bilinmeyen fonksiyon, bilinmeyen metot, sözdizimi hatası. Hiçbiri sessizce false'a düşmez — korpusun asıl ölçtüğü şey budur.

Örnekler

Sekiz tam politika. Adlar kurumun kendi ad alanında (kurum.); yerleşik setle çakışmaması için yeterli.

1) Üretim namespace'inde silme yükseltilmiş onay ister

policies:
  - id: kurum.uretim-silme
    description: "Üretim namespace'lerinde silme"
    match: >
      step.action == "delete" &&
      step.target.namespace in ["uretim", "uretim-veri"]
    effect: require
    level: elevated
    caveats:
      - "Üretim namespace'i: değişiklik kaydını açmadan uygulamayın."

İki namespace'te silme yapan her adım için kart elevated'a çıkar — kullanıcı hedefin adını birebir yazmadan uygula düğmesi etkinleşmez. caveats satırı kartta operatörün kendi cümlesi olarak, çevrilmeden görünür.

2) kube-system'e yazmak reddedilir

policies:
  - id: kurum.sistem-namespace-yazma
    description: "kube-system'e YEKE üzerinden yazılmaz"
    match: >
      step.action in ["create", "update", "patch", "delete"] &&
      step.target.namespace == "kube-system"
    effect: deny
    message: "kube-system küme yönetiminin işidir; bu değişiklik YEKE'den geçmez."

Bir adımda tek bir deny bütün planı düşürür; kart uygulanamaz hâlde çizilir. Yerleşik builtin.system-namespace aynı hedefte yalnızca onayı yükseltir — bu politika onu sıkılaştırır, çünkü guardrail'de birleşim daima en kısıtlayıcı olanın lehinedir.

3) Replikayı sıfıra çekmek uyarı düşürür

policies:
  - id: kurum.sifira-olcekleme-uyarisi
    description: "Sıfıra ölçeklemede nöbetçiyi hatırlat"
    match: >
      has(object.spec) && has(object.spec.replicas) &&
      object.spec.replicas == 0
    effect: warn
    message: "Sıfıra ölçekleme nöbet listesine duyurulmalı."

warn onay seviyesine dokunmaz, kartta bir uyarı satırı ekler. Kapsam notu: bu koşul yalnızca ana nesne üstünden yapılan ölçeklemeyi görür. Kanonik yol (scale subresource'u) bir Scale nesnesi taşır ve orada sıfır değeri gövdeden tamamen düşer — o dalı da yakalamak isteyen yerleşik builtin.scale-to-zero'nun iki dallı koşuluna bakabilir. Sıfıra ölçekleme zaten yerleşik olarak elevated onay istiyor; bu politika onun üstüne yalnızca kurumun kendi cümlesini koyar.

4) Kendi tipinizdeki parola alanını maskeleyin

policies:
  - id: kurum.veritabani-parola-maskesi
    description: "Kendi veritabanı tipimizde parola alanları maskelenir"
    match: >
      step.target.group == "ornek.io" &&
      step.target.resource == "veritabanlari"
    effect: redact
    redactPaths:
      - "spec.baglanti.parola"
      - "spec.baglanti.kullanicilar[].parola"
    message: "Parola alanları plan yanıtında ve denetim izinde maskelenir."

Yol biçimi noktayla iner, [] "bu dizinin her elemanı" demektir. Maske değerin yerine anahtarlı bir işaret yazar: değer okunamaz ama iki kaydın aynı değeri taşıyıp taşımadığı görülebilir — "bu alan değişti mi" sorusu maskeleme sonrasında da cevaplanabilir kalır. Secret'ın data/stringData alanları zaten yerleşik olarak maskelidir; bu örnek aynı korumayı kurumun kendi tipine taşır.

Koşulu fiil üstünden değil nesne üstünden yazın. Bir redact politikasına step.action koymak, maskeyi tam da en gerekli olduğu yerde düşürür: silmede istek gövdesi yoktur ve kullanıcının kartta gördüğü tek şey canlı nesnenin tamamıdır.

5) Bir CRD grubundaki her yazma kart açar

policies:
  - id: kurum.ornek-grubu-onay
    description: "ornek.io grubundaki her yazma onay kartı açar"
    match: 'step.target.group == "ornek.io"'
    effect: require
    messageCode: SYSTEM_NAMESPACE

level yazılmadığı için standard: tek kartlık onay, ad yazma yok. Yapısal taban yine de altına inmez — aynı grupta bir delete gelirse kart zaten elevated olur. messageCode kapalı kümeden seçilir ve kartta kullanıcının dilinde çıkar; kümede size uyan bir kod yoksa message ile kendi cümlenizi yazın.

6) Dry-run'ın değiştirdiği yola göre koşul

policies:
  - id: kurum.replika-degisikligi
    description: "Dry-run replika sayısını değiştiriyorsa yükseltilmiş onay"
    match: >
      step.dryRun.status == "ok" &&
      "spec.replicas" in step.dryRun.changedPaths
    effect: require
    level: elevated

Guardrail dry-run'dan sonra koştuğu için changedPaths bir tahmin değil bir ölçümdür: istek o alana dokunuyor görünse bile değer aynıysa yol listede olmaz. status == "ok" koşulu bilinçli — dry-run koşmadıysa (unsupported, skipped) liste boştur ve boş listeye bakan bir kural sessizce hiç eşleşmezdi.

7) Etiketli nesnede silme reddedilir

policies:
  - id: kurum.kritik-etiket-koruma
    description: "kritik=evet etiketli nesne YEKE'den silinemez"
    match: >
      step.action == "delete" &&
      has(oldObject.metadata) && has(oldObject.metadata.labels) &&
      "kritik" in oldObject.metadata.labels &&
      oldObject.metadata.labels["kritik"] == "evet"
    effect: deny
    message: "Bu nesne kritik etiketli; silme kaydı ayrı bir süreçten geçer."

İki korumanın da neden gerektiğine dikkat: has() etiket haritasının varlığını, in ise o haritada anahtarın varlığını sorar. İkincisi olmadan, etiketi olan ama kritik anahtarı olmayan bir nesnede indeksleme hata verir ve adım fail-closed deny olur — yani politika, kastetmediği nesneleri de durdururdu.

8) Kayıt kapalıyken üretimde terminal açılmasın

policies:
  - id: kurum.uretimde-kayitsiz-terminal-yok
    description: "Üretim cluster'larında kayıt kapalıyken terminal açılamaz"
    match: >
      step.action == "stream" &&
      op.cluster.name.startsWith("uretim") &&
      !op.cluster.recordingActive
    effect: deny
    message: "Bu cluster'da terminal oturumu ancak kaydı açıkken açılabilir."

Bu, yerleşik kapalı şablon ops.recording-required'ın kendi ad alanına kopyalanmış hâli. Koşul bilerek recordingActive okuyor, execRecording değil: lisans düştüğünde cluster kaydının duruşu true kalır ama kayıt başlamaz, yani duruşa bakan bir kural o kurulumda sessizce delinirdi.

Etkiler, seviyeler ve kodlar

Bir adıma birden fazla politika eşleşebilir. Sonuçlar birleştirilir; politika sırası korumayı zayıflatmaz.

EtkiNe olur
deny Plan reddedilir. Bir adımda bir deny planın tamamını düşürür. level yazılamaz.
require Onay kartı açılır. level: standard tek onay; level: elevated hedefin adının birebir yazılmasını ister — yazılmadan uygula etkinleşmez.
warn Kartta uyarı olarak görünür; onay seviyesine dokunmaz. Yeni bir kuralı sahada denemenin yolu.
redact redactPathsteki alanların değerleri plan yanıtında ve denetim izinde maskelenir. Bu politika kartın politika listesine hiç girmez — mesajı tele çıkmaz, yalnızca YAML'ı okuyan operatör için durur.
  • Seviye birleşimi maksimumdur: approvalLevel = max(eşleşen require seviyeleri, yapısal taban). Politika tabanı düşüremez.
  • Bayrak, uyarı ve sınıf yükseltmeleri birikir ve geri alınamaz: bir politika adımı destructive'e çektiyse başka bir politika onu geri indiremez.
  • Tek geçiş vardır. Bir politikanın eklediği bayrağa (ör. irreversible) göre başka bir politikanın yeniden eşleşmesi için ikinci tur koşulmaz — sıranın sonucu etkilememesi garantisi buna bağlı.
  • Aynı etkiyi farklı mesajla veren iki politika ikisi birden listelenir. Kart hangi kuralın konuştuğunu gizlemez.

Yazabileceğiniz messageCode değerleri

Kapalı küme — ürünün kendi cümleleri, iki dilde çevrili:

IRREVERSIBLE_STORAGE · NAMESPACE_DELETE · CRD_DELETE · CLUSTER_SCOPED_DELETE · DRY_RUN_UNSUPPORTED · POD_EVICTION · SYSTEM_NAMESPACE · RBAC_BINDING_WRITE · SCALE_TO_ZERO · NL_STRICT · SHELL_STRICT

Yazabileceğiniz caveatCodes değerleri

REVERT_DELETES_CREATED · REVERT_RESTORES_PRIOR · REVERT_RECREATES_OBJECT · SUBRESOURCE_CREATE_NO_TARGET · FINALIZERS_PENDING · FINALIZERS_ON_DELETING · OWNER_MANAGED · ORPHAN_PROPAGATION · FINALIZERS_DRY_RUN · SEQUENCED_IN_PLAN · STORAGE_DATA_LOST · NAMESPACE_CASCADE · CRD_INSTANCES_DELETED · DRY_RUN_UNVERIFIED · EVICTION_DELETES_POD · RBAC_GRANTS_AUTHORITY · SCALE_TO_ZERO_OUTAGE

Kümede karşılığı olmayan bir uyarı için caveats ile kendi cümlenizi yazın. Kod seçmek her zaman daha iyidir — kod çevrilir, serbest metin çevrilmez.

Çift onay, bakım penceresi ve paket modu

Üçü de Enterprise. İlk ikisi politika verisinin içinde yaşar, üçüncüsü politikanın nereden geldiğini değiştirir.

Çift onay alanları

policies:
  - id: kurum.cift-onay
    description: "Üretimde Deployment değişikliği ikinci bir göz ister"
    match: >
      step.action in ["update", "patch"] &&
      step.target.resource == "deployments" &&
      step.target.namespace == "uretim"
    effect: require
    level: elevated
    requireSecondApproval: true
    requiredApproverGroup: "sre-onaycilar"
  • Uygun onaycı kimdir: plan sahibinden farklı, hesabı aktif ve o cluster'da bir kimlik kuralıyla kimliği olan herhangi bir kullanıcı. Politika bir grup verdiyse kullanıcının çözülmüş gruplarında o grubun da bulunması şarttır — grup, kimlik kuralının ürettiği gruplardır, ikinci bir grup kavramı açılmaz.
  • Küme saklanmaz, her seferinde yeniden hesaplanır. Saklanan bir liste bayatlar: hesap pasifleşir, kimlik eşlemesi kalkar, grup daralır.
  • İkinci onaycı yalnız rıza verir, planı yine sahibi uygular. Rıza planın güncel hash'ine bağlıdır; plan tazelenip hash değişince rıza düşer (kayıt silinmez, kapı saymaz) ve yeniden istenir.
  • Varsayılan kapalıdır. Kural yazılmadıkça hiçbir plan ikinci onay istemez — bu, tek yöneticili bir kurulumun kilitlenmemesi için bilinçli bir seçim.
  • requiredApproverGroup tek başına yazılamaz. Daraltılacak bir onay yoksa daraltma sessizce hiçbir şey yapardı; yükleyici bunu açılışta reddeder.

Bakım penceresi — ayrı bir dosya

Takvim politika dosyasında değil, aynı dizindeki ayrı bir dosyada yaşar: üst düzey anahtar freezes:. Aynı dosyada hem policies: hem freezes: bulunması reddedilir — bir dosyanın ne olduğu, açıldığında belli olmalı.

# /etc/yeke/policies/90-takvim.yaml
freezes:
  - id: hafta-sonu
    description: "Hafta sonu değişiklik dondurması"
    timezone: Europe/Istanbul          # ZORUNLU
    weekly:
      - { from: "Fri 17:00", to: "Mon 09:00" }
    dates:
      - { from: "2026-12-29T00:00:00", to: "2027-01-02T09:00:00" }
    scope: { clusters: ["*"] }
  • timezone zorunludur ve bir IANA bölge adıdır. "Cuma 17:00" kimin cuması sorusu bir kurumda gerçek bir sorudur; UTC varsaymak sessiz bir yanlış üretir ve belirtisi "pencere iki saat kaymış" gibi görünür.
  • weekly biçimi "Gün SS:DD" — üç harfli İngilizce gün kısaltması (MonSun) ve 24 saatlik saat.
  • dates yerel duvar saatidir (YYYY-AA-GGTSS:DD:SS), saat dilimi eki yazılmaz: pencerenin kendi timezone'uyla çelişebilecek ikinci bir zaman kaynağı açardı.
  • weekly ve dates ikisi de boş bırakılabilir — hiç eşleşmeyen bir pencere, her zaman kapalı bir pencereden çok daha ucuzdur.
  • scope.clusters pencerenin kapsadığı cluster'lardır; ["*"] hepsi demektir. Pencere içindeki bir apply reddedilir, plan kaydı mutasyonsuz kalır — ayrıntısı Yönetişim sayfasında.
  • Pencere kimlikleri politika kimliklerinden ayrı bir ad alanıdır, ama kendi içinde benzersiz olmak zorundadır: iki pencere aynı adı taşırsa izde "hangi pencere reddetti" sorusunun cevabı belirsizleşirdi.

Paket modu — imzalı, anında yürürlükte

YEKE_POLICY_MODE=central verildiğinde politika seti dizinden değil imzalı bir paketten gelir. Gövde signature alanı olmadan yazılır ve version her yüklemede artmak zorundadır:

{
  "version": 3,
  "policies": [
    {
      "id": "kurum.uretim-silme",
      "match": "step.action == \"delete\" && step.target.namespace == \"uretim\"",
      "effect": "require",
      "level": "elevated"
    }
  ],
  "freezes": [
    {
      "id": "hafta-sonu",
      "timezone": "Europe/Istanbul",
      "weekly": [{ "from": "Fri 17:00", "to": "Mon 09:00" }],
      "scope": { "clusters": ["*"] }
    }
  ]
}

Alanlar dosya kipiyle birebir aynıdır — paket ve dosya aynı derleyiciden geçer, yani dosya modunda reddedilen bir politika pakette de reddedilir. İmzalama kurumun kendi private key'iyle yapılır:

pnpm --filter @yeke/core exec tsx tools/policy-package/sign.ts \
  --private-key policy-private.pem \
  --package paket.json \
  --out paket-imzali.json

Şifreli bir PEM'de (ENCRYPTED PRIVATE KEY başlığı ya da eski Proc-Type: 4,ENCRYPTED) passphrase YEKE_POLICY_KEY_PASSPHRASE ortam değişkeninden ya da gizli girdiden okunur; düz PEM'de bu adım hiç sorulmaz.

İmzalı gövde PUT /api/policy/package ile, admin oturumuyla yüklenir; ekrandan yüklemek için /admin/policy. Yükleme anında yürürlüğe girer, core yeniden başlamaz — ama koşan bir planı etkilemez: plan kaydı sınıflandırıldığı politika sürümünü taşır ve apply o sürümle koşar.

  • İki mod aynı anda olmaz. YEKE_POLICY_MODE=central ile YEKE_POLICY_DIR birlikte verilirse core açık hatayla durur — iki kaynağı birleştirmek "aynı idli iki politika varsa hangisi kazanır" sorusunun sessiz bir cevabını üretirdi.
  • Bozuk imza ya da bayat sürüm yürürlükteki paketi düşürmez. Yükleme reddedilir, önceki sürüm yürürlükte kalır. Aynı ya da küçük bir version da reddedilir.
  • Yerleşik set paket modunda de yüklüdür. Paket operatörün setidir, ürünün kendi politikalarının yerine geçmez.

Anahtar üretimi, yükleme ucunun tamamı ve lisans davranışı Yönetişim sayfasında.

Politikayı test

Önce uyarı üreten bir kuralla test edin. Sonuçları kontrol ettikten sonra engelleme veya ek onay etkisini etkinleştirin.

  • Önce warn ile yazın. Yeni bir kuralı effect: warn ile sahaya alıp kartta gerçekten kastettiğiniz adımlarda çıktığını gördükten sonra require ya da deny'a çevirin. Yanlış yazılmış bir deny, doğru işlemleri de durdurur.
  • Planı kurun, kartı okuyun, uygulamayın. Arayüzden ya da POST /api/clusters/:clusterId/operations ile bir plan kurun; kart eşleşen politikaların id'lerini, mesajlarını, uyarılarını, onay seviyesini ve maskelenmiş alanları gösterir. Sonra planı POST /api/clusters/:clusterId/operations/:opId/cancel ile iptal edin — planı kurmak hiçbir şey uygulamaz, iptal iz bırakır.
  • Açılış günlüğü ne yüklendiğini sayar. Core açılırken uyum korpusunun geçtiğini ve kaç politikanın etkin olduğunu adlarıyla birlikte yazar; bakım penceresi varsa onları da bölgeleriyle listeler. Yazdığınız politikanın adını orada görmüyorsanız ya enabled: false'tur ya da dosya hiç okunmamıştır.
[guardrail] CEL conformance corpus passed (54 expressions)
[guardrail] 12 active policies loaded (2 files): builtin.irreversible-storage, …
[guardrail] 1 change-freeze windows loaded: hafta-sonu (Europe/Istanbul)

Açılışı durduran hatalar

Hata mesajı her zaman politikanın adını ve geldiği dosyayı söyler; core dinlemeye hiç açılmaz.

Policy file is not valid YAML (/etc/yeke/policies/10-uretim.yaml): …
Policy file does not match the schema (/etc/yeke/policies/10-uretim.yaml):
  policies.0.effect: Invalid enum value
Policy id defined twice: 'kurum.uretim-silme'
  (/etc/yeke/policies/10-uretim.yaml and /etc/yeke/policies/20-ek.yaml).
  Which one is valid cannot remain ambiguous.
Policy 'kurum.ornek' (…) could not be compiled: …
  • id çakışması iki dosya arasında da sayılır — ve yerleşik setle de. Bu yüzden kendi politikalarınıza bir ön ek verin.
  • Kapalı politika da derlenir. enabled: false yazılmış bozuk bir politika açılışı yine durdurur; hatayı açtığınız güne ertelemez.
  • Çalışma anı hatası açılışta görünmez. Derleme match'in sözdizimini ve tipini sınar; eksik alan hatası ancak eşleşen bir plan kurulduğunda çıkar ve o adım deny olur. has() disiplini bu yüzden önemli.

Yerleşik politikalar

On yedi kayıt, on dördü açık. Hepsi veri olarak gelir — motor hiçbir kaynak adı bilmez.

PolitikaEtkiNe yapar
builtin.irreversible-storagerequire · elevated PersistentVolume ve PersistentVolumeClaim silme; irreversible bayrağı ekler.
builtin.namespace-deleterequire · elevated Namespace silme — içindeki her şey cascade gider.
builtin.crd-deleterequire · elevated CustomResourceDefinition silme; o tipin tüm örnekleri birlikte silinir.
builtin.cluster-scoped-deleterequire · elevated Cluster kapsamlı bir nesnenin silinmesi.
builtin.dry-run-unsupportedrequire · elevated Dry-run'ın koşamadığı işlem — doğrulanmamış bir değişiklik uygulanıyor.
builtin.pod-evictionrequire · elevated Eviction subresource'u; sınıfı destructive'e yükseltir, çünkü create-only bir istek olmasına rağmen pod siler.
builtin.system-namespacerequire · elevated kube-system, kube-public, kube-node-lease içinde yıkıcı işlem.
builtin.rbac-binding-writerequire · elevated RoleBinding / ClusterRoleBinding yazma — yetki dağıtan nesneler. YEKE'nin kendi "yetkiyi ver" düğmesi de bu kapıdan geçer.
builtin.scale-to-zerorequire · elevated Replika sayısının sıfıra indirilmesi; hem ana nesne hem scale subresource'u dalını kapsar.
builtin.node-cordonwarn Bir node'u cordon etmek (yeni pod yerleşimini kapatmak), cluster'da başka yerleşilebilir node varken. Onay istemez, uyarır.
builtin.node-cordon-last-noderequire · elevated Cluster'ın son yerleşilebilir node'unu cordon etmek; sınıfı destructive'e yükseltir, çünkü yeni pod'lar hiçbir node'a yerleşemez.
builtin.node-cordon-topology-unknownrequire · elevated Bir node'u cordon etmek, yerleşilebilir node sayısı okunamadığında — son node olup olmadığı bilinmediği için onay yükseltilir.
builtin.redact-secretsredact Secret'ın data ve stringData alanları — okumada da yazmada da silmede de.
builtin.redact-env-valuesredact Ortam değişkeni değerleri, PodSpec'in dört yerleşiminde × üç container listesinde. valueFrom bilerek kapsam dışı: içinde değer değil bir referans vardır.
ops.nl-strictkapalı Şablon. Açılırsa sohbetten gelen (op.source == "nl") her yazma yükseltilmiş onay ister.
ops.shell-strictkapalı Şablon. Açılırsa kabuktan gelen her yazma kendi onay kartını açar; oturum onayının yetkilendirdiği yazma yolu devre dışı kalır.
ops.recording-requiredkapalı Şablon. Açılırsa op.cluster.recordingActive kapalıyken stream adımını reddeder — kaydı başlamayacak bir terminal oturumu açılamaz.

Kapatılabilir mi

enabled alanı yerleşik dosyanın kendi içindedir ve o dosya imajla gelir. YEKE_POLICY_DIR'den bir yerleşik politikayı kapatmak ya da ezmek mümkün değildir: aynı id'yi ikinci bir kaynakta tanımlamak core'u açılışta durdurur, ve yerleşik set paket modunda de yüklenir. Operatörün elindeki yol eklemektir — guardrail sıkılaştırır, gevşetmez. Yukarıdaki üç şablonun (ops.nl-strict, ops.shell-strict, ops.recording-required) davranışını istiyorsanız aynı koşulu kendi ad alanınızda kendi politikanız olarak yazın.

Kural veridir, kod değil

Yeni bir CRD hiçbir koda ve hiçbir politikaya dokunmadan güvenli varsayılanla sınıflanır; tipe özgü bilgiyi ekleyen şey sizin yazdığınız dosyadır.