Validace Kubernetes YAML v souladu s nejlepšími praktikami a politikami

Pozn. přek.: S rostoucím počtem YAML konfigurací pro prostředí K8s se stává stále aktuálnější potřeba jejich automatizovaného ověřování. Autor této recenze nejen vybral existující řešení pro tento úkol, ale také na příkladu Deploymentu zkoumá, jak fungují. Výsledkem je velmi informativní text pro ty, které toto téma zajímá.

Validace Kubernetes YAML v souladu s nejlepšími praktikami a politikami

TL;DR: V článku je porovnáváno šest statických nástrojů pro kontrolu a hodnocení YAML souborů Kubernetes z hlediska souladu s nejlepšími praktikami a požadavky.

Pracovní zátěže Kubernetes jsou obvykle definovány ve formě YAML dokumentů. Jedním z problémů s YAML je složitost při stanovení omezení nebo vztahů mezi soubory manifestů.

Co když si chceme být jisti, že všechny obrazy nasazované v clusterech pocházejí z důvěryhodného registru?

Jak zabránit nasazování Deploymentů do clustera, pokud pro ně nejsou nastaveny PodDisruptionBudgets?

Integrace statického testování umožňuje identifikovat chyby a porušení politik již ve fázi vývoje. Tím se zvyšují záruky správnosti a bezpečnosti definic zdrojů a zvyšuje se pravděpodobnost, že produkční zátěže budou dodržovat nejlepší praktiky.

Ekosystém statického ověřování YAML souborů Kubernetes lze rozdělit do následujících kategorií:

  • API validátory. Nástroje v této kategorii kontrolují YAML manifest na soulad s požadavky API serveru Kubernetes.
  • Hotové testery. Nástroje v této kategorii přicházejí s hotovými testy na bezpečnost, dodržování nejlepších praktik atd.
  • Vlastní validátory. Zástupci této kategorie umožňují vytvářet vlastní testy v různých jazycích, například v Regu a Javascriptu.

V tomto článku popíšeme a porovnáme šest různých nástrojů:

  1. kubeval;
  2. kube-score;
  3. config-lint;
  4. copper;
  5. conftest;
  6. Polaris.

Tak pojďme na to!

Kontrola Deploymentů

Než se pustíme do porovnávání nástrojů, pojďme vytvořit nějaký základ, na kterém je budeme testovat.

Níže uvedený manifest obsahuje řadu chyb a nesouladů s nejlepšími praktikami: kolik z nich dokážete najít?

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

Tento YAML použijeme pro porovnání různých nástrojů.

Předchozí manifest base-valid.yaml a další manifesty z tohoto článku najdete v Git-repozitáři.

Manifest popisuje webovou aplikaci, jejíž hlavní úkol je odpovídat zprávou „Hello World“ na portu 5678. Lze ji nasadit následujícím příkazem:

kubectl apply -f hello-world.yaml

A nyní — ověřte, že to funguje:

kubectl port-forward svc/http-echo 8080:5678

Nyní přejděte na http://localhost:8080 a potvrďte, že aplikace funguje. Ale odpovídá to nejlepším praktikám? Zkontrolujme to.

1. Kubeval

Základem kubeval je myšlenka, že veškerá interakce s Kubernetes probíhá přes jeho REST API. Jinými slovy, lze použít API schéma k ověření, zda daný YAML odpovídá. Pojďme se podívat na příklad.

Pokyny k instalaci kubeval jsou k dispozici na stránkách projektu.

V době psaní původního článku byla k dispozici verze 0.15.0.

Po instalaci dejme tomuto nástroji manifest, který jsme uvedli výše:

$ kubeval base-valid.yaml
PASS - base-valid.yaml obsahuje platný Deployment (http-echo)
PASS - base-valid.yaml obsahuje platný Service (http-echo)

V případě úspěchu kubeval skončí s exit kódem 0. Můžete to zkontrolovat následujícím způsobem:

$ echo $?
0

Nyní zkusme kubeval s jiným manifestem:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(kubeval-invalid.yaml)

Můžete na první pohled rozpoznat problém? Spouštíme:

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml obsahuje neplatný Deployment (http-echo) - selector: selector je vyžadován
PASS - kubeval-invalid.yaml obsahuje platný Service (http-echo)

# zkontrolujeme návratový kód
$ echo $?
1

Zdroje neprocházejí kontrolou.

Deploymenty, které používají verzi API apps/v1, musí obsahovat selektor odpovídající značce podu. Výše uvedený manifest neobsahuje selektor, a proto kubeval upozornil na chybu a skončil s nenulovým kódem.

Zajímavé je, co se stane, pokud provedeme kubectl apply -f s tímto manifestem?

No, pojďme to vyzkoušet:

$ kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": error validating data: ValidationError(Deployment.spec):
missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors,
turn validation off with --validate=false

Přesně ta chyba, na kterou kubeval upozorňoval. Opravit ji můžete přidáním selektoru:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:          # !!!
    matchLabels:     # !!!
      app: http-echo # !!!
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo
        args: ["-text", "hello-world"]
        ports:
        - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: http-echo
spec:
  ports:
  - port: 5678
    protocol: TCP
    targetPort: 5678
  selector:
    app: http-echo

(base-valid.yaml)

Výhodou nástrojů jako kubeval je, že tyto chyby lze odhalit v raných fázích nasazení.

Kromě toho pro tyto kontroly není potřeba přístup ke klastru: mohou se provádět offline.

Ve výchozím nastavení kubeval kontroluje zdroje na shodu s nejnovější schématem Kubernetes API. V řadě případů budete ale muset provést kontrolu na shodu se specifickou verzí Kubernetes. Toho lze dosáhnout pomocí příznaku --kubernetes-version:

$ kubeval --kubernetes-version 1.16.1 base-valid.yaml

Všimněte si, že verze musí být uvedena ve formátu Major.Minor.Patch.

Pro zobrazení seznamu verzí, pro které je podpora kontrole, se obraťte na JSON schéma na GitHubu, které kubeval používá pro validaci. Pokud chcete spustit kubeval offline, stáhněte schémata a určete jejich místní umístění pomocí příznaku --schema-location.

Kromě jednotlivých YAML souborů může kubeval také pracovat s adresáři a stdin.

Kromě toho se Kubeval snadno integruje do CI pipeline. Zájemci o provádění testů před odesláním manifestů do klastru potěší, že kubeval podporuje tři formáty výstupu:

  1. Normální text;
  2. JSON;
  3. Test Anything Protocol (TAP).

A jakýkoli z formátů lze použít pro další parsování výstupu, aby se vytvořil souhrn výsledků požadovaného vzhledu.

Jednou z nevýhod kubeval je, že v současnosti neumí kontrolovat na shodu Custom Resource Definitions (CRDs). Lze však kubeval nastavit ignorovat je.

Kubeval je skvělý nástroj pro kontrolu a vyhodnocení zdrojů; je však třeba zdůraznit, že úspěšné absolvování testu nezaručuje, že zdroj splňuje nejlepší praktiky.

Například použití tagu latest v kontejneru není v souladu s nejlepšími postupy. Nicméně kubeval to nepovažuje za chybu a nehlásí ji. To znamená, že kontrola takového YAML proběhne bez varování.

Ale co když je potřeba vyhodnotit YAML a odhalit porušení jako tag latest? Как проверить YAML-файл на соответствие лучшим практикам?

2. Kube-score

Kube-score analyzuje YAML manifesty a hodnotí je na základě integrovaných testů. Tyto testy jsou vybírány na základě doporučení pro bezpečnost a nejlepší praxe, například:

  • Spuštění kontejneru ne pod rootem.
  • Existence kontrol zdraví podů.
  • Stanovení requestů a limitů pro zdroje.

Na základě testu se vydávají tři výsledky: OK, VAROVÁNÍ a KRITICKÉ.

Kube-score si můžete vyzkoušet online nebo si ho nainstalovat lokálně.

V době psaní původního článku byla nejnovější verzí kube-score 1.7.0.

Zkusme to na našem manifestu base-valid.yaml:

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[KRITICKÉ] Tag obrazu kontejneru
  · http-echo -> Obraz s nejnovějším tagem
      Doporučuje se používat pevný tag, aby se zabránilo náhodným aktualizacím
[KRITICKÉ] Politika sítě podu
  · Pod nemá odpovídající síťovou politiku
      Vytvořte NetworkPolicy, která cílí na tento pod
[KRITICKÉ] Zkoušky podu
  · Kontejner postrádá readinessProbe
      ReadinessProbe by měl být použit k indikaci, kdy je služba připravena přijímat provoz.
      Bez toho má pod riziko, že obdrží provoz dříve, než se spustí. Také se používá během
      nasazení a může zabránit prostoji, pokud nová verze aplikace selže.
      Více informací: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[KRITICKÉ] Bezpečnostní kontext kontejneru
  · http-echo -> Kontejner nemá nakonfigurovaný bezpečnostní kontext
      Nastavte securityContext pro provoz kontejneru v bezpečnějším kontextu.
[KRITICKÉ] Zdroje kontejneru
  · http-echo -> Limit CPU není nastaven
      Doporučuje se nastavit limity zdrojů, abyste předešli DDOS zdrojů. Nastavte resources.limits.cpu
  · http-echo -> Limit paměti není nastaven
      Doporučuje se nastavit limity zdrojů, abyste předešli DDOS zdrojů. Nastavte resources.limits.memory
  · http-echo -> Požadavek na CPU není nastaven
      Doporučuje se nastavit požadavky na zdroje, aby se zajistilo, že aplikace může začít a fungovat bez
      selhání. Nastavte resources.requests.cpu
  · http-echo -> Požadavek na paměť není nastaven
      Doporučuje se nastavit požadavky na zdroje, aby se zajistilo, že aplikace může začít a fungovat bez selhání.
      Nastavte resources.requests.memory
[KRITICKÉ] Nasazení má PodDisruptionBudget
  · Nebyl nalezen odpovídající PodDisruptionBudget
      Doporučuje se definovat PodDisruptionBudget, aby se předešlo neočekávaným výpadkům během údržby Kubernetes,
      například při vypouštění uzlu.
[VAROVÁNÍ] Nasazení má hostitelský PodAntiAffinity
  · Nasazení nemá nastaveno podAntiAffinity pro hostitele
      Doporučuje se nastavit podAntiAffinity, aby se zabránilo plánování více podů z nasazení
      na stejný uzel. To zvyšuje dostupnost v případě, že uzel se stane nedostupným.

YAML prochází kontrolami kubeval, zatímco kube-score ukazuje na následující nedostatky:

  • Nastavení readiness probes není nakonfigurováno.
  • Chybí požadavky a limity pro zdroje CPU a paměť.
  • Nebyla stanovena podpora pro rozpočty narušení podů.
  • Chybí pravidla pro anti-affinity (anti-affinity) pro maximalizaci dostupnosti.
  • Kontejner běží pod root‘em.

To vše jsou rozumné připomínky k nedostatkům, které je třeba odstranit, aby bylo nasazení efektivnější a spolehlivější.

Tým kube-score vypisuje informace ve snadno čitelné podobě se zahrnutím všech porušení typu VAROVÁNÍ a KRITICKÉ, což velmi pomáhá během vývoje.

Ti, kteří chtějí použít tento nástroj v rámci CI pipeline, mohou zapnout kompaktnější výstup pomocí flagu --output-format ci (v tomto případě se také zobrazují testy s výsledkem OK):

$ kube-score score base-valid.yaml --output-format ci

[OK] http-echo apps/v1/Deployment
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Cpu limit není nastaven
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Paměťový limit není nastaven
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Cpu request není nastaven
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Paměťový request není nastaven
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Obraz s poslední značkou
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: Pod nemá odpovídající síťovou politiku
[CRITICAL] http-echo apps/v1/Deployment: Kontejner postrádá readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Kontejner nemá nastavený bezpečnostní kontext
[CRITICAL] http-echo apps/v1/Deployment: Nebyla nalezena odpovídající PodDisruptionBudget
[WARNING] http-echo apps/v1/Deployment: Nasazení nemá nastavený host podAntiAffinity
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

Podobně jako kubeval, kube-score vrací nenulový kód výstupu, pokud existuje test, který selhal. KRITICKÉTaké lze zapnout podobné zpracování i pro VAROVÁNÍ.

Navíc existuje možnost kontroly zdrojů na shodu s různými verzemi API (stejně jako v kubeval). Avšak tyto informace jsou 'hardcoded' přímo v kube-score: nelze si vybrat jinou verzi Kubernetes. Takové omezení může představovat velký problém, pokud plánujete aktualizovat cluster nebo máte několik clusterů s různými verzemi K8s.

Všimněte si, že už existuje issue s návrhem realizovat tuto možnost.

Více o kube-score se můžete dozvědět na oficiálním webu.

Testy kube-score jsou skvělým nástrojem pro implementaci nejlepších praktik, ale co když je třeba provést změny v testu nebo přidat vlastní pravidla? Bohužel, to není možné.

Kube-score není rozšiřitelný: nelze přidat politiky ani je přizpůsobit.

Pokud je potřeba psát vlastní testy na shodu s politikami přijatými ve společnosti, lze použít některý z následujících čtyř nástrojů: config-lint, copper, conftest nebo polaris.

3. Config-lint

Config-lint je nástroj pro validaci konfiguračních souborů formátu YAML, JSON, Terraform, CSV a manifestů Kubernetes.

Nainstalovat ho lze pomocí pokynů na stránkách projektu.

Aktuální verze v době psaní původního článku je 1.5.0.

Config-lint neobsahuje vestavěné testy pro kontrolu manifestů Kubernetes.

Pro provádění jakýchkoli testů je nutné vytvářet příslušná pravidla. Ta jsou zapisována do YAML souborů nazývaných „sady pravidel“ (rulesets), a mají následující strukturu:

verze: 1
description: Pravidla pro Kubernetes spec soubory
type: Kubernetes
files:
  - "*.yaml"
rules:
   # seznam pravidel

(rule.yaml)

Pojďme se na ně podívat podrobněji:

  • Pole type určuje, jaký typ konfigurace bude config-lint používat. Pro manifesty K8s je to vždy Kubernetes.
  • V poli files můžete kromě samotných souborů uvést také adresář.
  • Pole rules slouží k definici uživatelských testů.

Představte si, že chcete zajistit, aby obrazy v nasazení byly vždy stahovány z důvěryhodného repozitáře, jako je my-company.com/myapp:1.0. Pravidlo pro config-lint, které provede tuto kontrolu, by vypadalo takto:

- id: MY_DEPLOYMENT_IMAGE_TAG
  závažnost: SELHÁNÍ
  zpráva: Nasazení musí používat platný tag obrazu
  zdroj: Nasazení
  aserce:
    - každý:
        klíč: spec.template.spec.containers
        výrazy:
          - klíč: image
            operace: začíná-s
            hodnota: "my-company.com/"

(rule-trusted-repo.yaml)

Pro každé pravidlo musí být uvedeny následující atributy:

  • id — jedinečný identifikátor pravidla;
  • závažnost — může být SELHÁNÍ, VAROVÁNÍ a NEKOMPETENTNÍ;
  • zpráva — pokud je pravidlo porušeno, zobrazí se obsah tohoto řádku;
  • zdroj — typ zdroje, na který se toto pravidlo vztahuje;
  • aserce — seznam podmínek, které budou hodnoceny vůči tomuto zdroji.

V pravidle výše asercí nazvanou každý kontroluje, že všechny kontejnery v nasazení (klíč: spec.templates.spec.containers) používají důvěryhodné obrazy (tj. začínající s my-company.com/).

Celá sada pravidel vypadá takto:

verze: 1
description: Pravidla pro Kubernetes spec soubory
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    závažnost: SELHÁNÍ
    zpráva: Nasazení musí používat platný repozitář obrazu
    zdroj: Nasazení
    aserce:
      - každý:
          klíč: spec.template.spec.containers
          výrazy:
            - klíč: image
              operace: začíná-s
              hodnota: "my-company.com/"

(ruleset.yaml)

Abychom otestovali test, uložme ho jako check_image_repo.yaml. Spustíme kontrolu nad souborem base-valid.yaml:

$ config-lint -rules check_image_repo.yaml base-valid.yaml

[
  {
  "AssertionMessage": "Every expression fails: And expression fails: image does not start with my-company.com/",
  "Category": "",
  "CreatedAt": "2020-06-04T01:29:25Z",
  "Filename": "test-data/base-valid.yaml",
  "LineNumber": 0,
  "ResourceID": "http-echo",
  "ResourceType": "Deployment",
  "RuleID": "DEPLOYMENT_IMAGE_REPOSITORY",
  "RuleMessage": "Deployment must use a valid image repository",
  "Status": "FAILURE"
  }
]

Ověření selhalo. Nyní zkontrolujeme další manifest se správným repozitářem obrazů:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: http-echo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: http-echo
  template:
    metadata:
      labels:
        app: http-echo
    spec:
      containers:
      - name: http-echo
         image: my-company.com/http-echo:1.0 # !!!
         args: ["-text", "hello-world"]
         ports:
         - containerPort: 5678

(image-valid-mycompany.yaml)

Spouštíme stejný test se výše uvedeným manifestem. Nebyly zjištěny žádné problémy:

$ config-lint -rules check_image_repo.yaml image-valid-mycompany.yaml
[]

Config-lint je perspektivní rámec, který umožňuje vytvářet vlastní testy pro ověřování YAML manifestů Kubernetes pomocí YAML DSL.

Ale co když je potřeba složitější logika a testy? Není YAML příliš omezený pro to? Co kdybychom mohli vytvářet testy v plnohodnotném programovacím jazyce?

4. Copper

Copper V2 je rámec pro validaci manifestů pomocí vlastních testů (podobně jako config-lint).

Rozdíl oproti tomu poslednímu je, že pro popis testů nepoužívá YAML. Místo toho mohou být testy vytvořeny v JavaScriptu. Copper poskytuje knihovnu s několika základními nástroji, které usnadňují čtení informací o objektech Kubernetes a hlášení chyb.

Postup pro instalaci Copper naleznete v oficiální dokumentaci.

2.0.1 je nejnovější vydání této utility v době psaní původního článku.

Stejně jako config-lint, také Copper nemá vestavěné testy. Pojďme napsat jeden. Nechť ověřuje, že deploymenty používají kontejnerové obrazy pouze z důvěryhodných repozitářů, jako je my-company.com.

Vytvořte soubor check_image_repo.js s následujícím obsahem:

$$.forEach(function($){
    if ($.kind === 'Deployment') {
        $.spec.template.spec.containers.forEach(function(container) {
            var image = new DockerImage(container.image);
            if (image.registry.lastIndexOf('my-company.com/') != 0) {
                errors.add_error('no_company_repo',"Image " + $.metadata.name + " is not from my-company.com repo", 1)
            }
        });
    }
});

Nyní, abychom ověřili náš manifest base-valid.yaml, použijte příkaz copper validate:

$ copper validate --in=base-valid.yaml --validator=check_image_tag.js

Kontrola no_company_repo selhala s vážností 1 kvůli obrazovému tagu http-echo, který není z repozitáře my-company.com
Validace selhala

Je jasné, že pomocí copper lze provádět složitější testy – například kontrolovat doménová jména v manifestech Ingress nebo odmítat pod’y, které běží v privilegovaném režimu.

V Copper jsou integrovány různé pomocné funkce:

  • DockerImage načítá zadaný vstupní soubor a vytváří objekt s následujícími atributy:
    • name – název obrazu,
    • tag – tag obrazu,
    • registry – registry obrazů,
    • registry_url – protokol (https://) a registry obrazů,
    • fqin – úplná adresa obrazu.
  • Funkce findByName pomáhá najít zdroj podle zadaného typu (kind) a názvu (name) ze vstupního souboru.
  • Funkce findByLabels pomáhá najít zdroj podle zadaného typu (kind) a štítků (labels).

Se všemi dostupnými pomocnými funkcemi se můžete seznámit zde.

Ve výchozím nastavení načítá celý vstupní YAML soubor do proměnné $$ a zpřístupňuje ho skriptům (známá metoda pro ty, kdo mají zkušenosti s jQuery).

Hlavní výhoda Copper je zřejmá: nemusíte se učit specializovaný jazyk a můžete používat různé funkce JavaScriptu pro vytváření vlastních testů, jako jsou interpolace řetězců, funkce atd.

Je také třeba poznamenat, že aktuální verze Copper pracuje se verzí ES5 JavaScriptového enginu, nikoli s ES6.

Podrobnosti jsou k dispozici na oficiálních stránkách projektu.

Nicméně, pokud nemáte rádi JavaScript a upřednostňujete jazyk speciálně určený k vytváření dotazů a popisu politik, měli byste si všímat conftest.

5. Conftest

Conftest je rámec pro kontrolu konfiguračních dat. Je vhodný i pro testování/verifikaci manifestů Kubernetes. Testy jsou popsány pomocí specializovaného dotazovacího jazyka Rego.

Conftest lze nainstalovat pomocí pokynů, uvedených na stránkách projektu.

V době psaní původního článku byla nejnovější dostupná verze 0.18.2.

Podobně jako config-lint a copper, conftest přichází bez jakýchkoliv vestavěných testů. Zkusme jej a napišme vlastní politiku. Jak v předchozích příkladech, budeme kontrolovat, zda jsou obrazy kontejnerů nabírány z důvěryhodného zdroje.

Vytvořte adresář conftest-checks, a v něm soubor s názvem check_image_registry.rego s následujícím obsahem:

balíček hlavní

deny[msg] {

  input.kind == "Deployment"
  image := input.spec.template.spec.containers[_].image
  ne začíná(image, "my-company.com/")
  msg := sprintf("obrázek '%v' nepochází z repozitáře my-company.com", [image])
}

Teď otestujeme base-valid.yaml přes conftest:

$ conftest test --policy ./conftest-checks base-valid.yaml

NEÚSPĚCH - base-valid.yaml - obrázek 'hashicorp/http-echo' nepochází z repozitáře my-company.com
1 testy, 1 úspěšné, 0 varování, 1 selhání

Test očekávaně selhal, protože obrazy pocházejí z nedůvěryhodného zdroje.

Ve souboru Rego definujeme blok deny. Jeho pravdivost se považuje za porušení. Pokud je bloků deny víc, conftest je kontroluje nezávisle na sobě, a pravdivost jakéhokoli bloku se vykládá jako porušení.

Kromě výchozího výstupu conftest podporuje JSON, TAP a tabulkový formát — velmi užitečná funkce, pokud potřebujete začlenit zprávy do stávajícího CI pipeline. Správný formát lze zadat pomocí příznaku --output.

Pro usnadnění ladění politik v conftest je k dispozici příznak --trace. Vypisuje trasování toho, jak conftest analyzuje zadané soubory politik.

Politiky conftest lze publikovat a sdílet v OCI registrech (Open Container Initiative) ve formě artefaktů.

Příkazy push a pull umožňují publikovat artefakt nebo extrahovat existující artefakt z vzdáleného registru. Zkusme publikovat naši vytvořenou politiku do místního Docker registru pomocí conftest push.

Spusťte místní Docker registr:

$ docker run -it --rm -p 5000:5000 registry

V jiném terminálu přejděte do dříve vytvořené složky conftest-checks a spusťte následující příkaz:

$ conftest push 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

Pokud příkaz proběhl úspěšně, zobrazí se zpráva následujícího typu:

2020/06/10 14:25:43 publikováno balíček s digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609c

Nyní vytvořte dočasnou složku a spusťte v ní příkaz conftest pull. Stáhne do ní balíček, který vytvořil předchozí příkaz:

$ cd $(mktemp -d)
$ conftest pull 127.0.0.1:5000/amitsaha/opa-bundle-example:latest

Ve dočasné složce se vytvoří podsložka policy, obsahující náš soubor s politikou:

$ tree
.
└── policy
  └── check_image_registry.rego

Testy lze provádět přímo z repozitáře:

$ conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
NEÚSPĚCH - base-valid.yaml - obrázek 'hashicorp/http-echo' nepochází z repozitáře my-company.com
2 testy, 1 úspěšné, 0 varování, 1 selhání

Bohužel, DockerHub zatím není podporován. Takže se považujte za šťastné, pokud používáte Azure Container Registry (ACR) nebo svůj vlastní registr.

Formát artefaktů je stejný jako u balíčků Open Policy Agent (OPA), které umožňuje používat conftest pro spouštění testů z existujících balíčků OPA.

Více o sdílení politik a dalších možnostech conftest se lze dozvědět na oficiálních stránkách projektu.

6. Polaris

Poslední nástroj, o kterém bude řeč v tomto článku, je Polaris. (Jeho loňskou prezentaci jsme už přeložili — pozn. přek.)

Polaris lze nainstalovat do cloudu nebo použít v příkazovém řádku. Jak už jste asi uhodli, umožňuje statickou analýzu manifestů Kubernetes.

Při práci v příkazovém řádku jsou k dispozici vestavěné testy, které pokrývají oblasti jako jsou zabezpečení a osvědčené postupy (podobně jako kube-score). Navíc lze vytvářet vlastní testy (jako v config-lint, copper a conftest).

Jinými slovy, Polaris kombinuje výhody obou kategorií nástrojů: s vestavěnými i uživatelskými testy.

Pro instalaci Polaris v příkazovém řádku použijte pokyny na webu projektu.

K okamžiku psaní původního článku byla k dispozici verze 1.0.3.

Po dokončení instalace můžete spustit polaris na manifestě base-valid.yaml pomocí následujícího příkazu:

$ polaris audit --audit-path base-valid.yaml

Ten vygeneruje řetězec ve formátu JSON s podrobným popisem provedených testů a jejich výsledky. Výstup bude mít následující strukturu:

{
  "PolarisOutputVersion": "1.0",
  "AuditTime": "0001-01-01T00:00:00Z",
  "SourceType": "Path",
  "SourceName": "test-data/base-valid.yaml",
  "DisplayName": "test-data/base-valid.yaml",
  "ClusterInfo": {
    "Version": "unknown",
    "Nodes": 0,
    "Pods": 2,
    "Namespaces": 0,
    "Controllers": 2
  },
  "Results": [
    /* dlouhý seznam */
  ]
}

Úplný výstup je k dispozici zde.

Podobně jako kube-score, Polaris odhaluje problémy v oblastech, kde manifest nesplňuje osvědčené postupy:

  • Není nastavena kontrola zdraví podů.
  • Nejsou stanoveny tagy pro kontejnerové obrazy.
  • Kontejner běží pod root‘em.
  • Nejsou definovány požadavky a limity pro paměť a CPU.

Každému testu je v závislosti na jeho výsledcích přidělena míra závažnosti: warning nebo danger. Pro více informací o dostupných vestavěných testech se obraťte na dokumentaci.

Pokud nejsou podrobnosti potřeba, můžete nastavit přepínač --format score. V tomto případě Polaris vypíše číslo v rozmezí od 1 do 100 — score (tzn. hodnocení):

$ polaris audit --audit-path test-data/base-valid.yaml --format score
68

Čím je hodnocení blíže 100, tím vyšší je míra shody. Pokud zkontrolujete exit-kód příkazu polaris audit, zjistíte, že je roven 0.

Přinutit polaris audit program ukončit s nenulovým kódem lze pomocí dvou přepínačů:

  • Přepínač --set-exit-code-below-score přijímá jako argument prahovou hodnotu v rozmezí 1-100. V tomto případě se příkaz ukončí s exit kódem 4, pokud hodnocení klesne pod tuto prahovou hodnotu. To je velmi užitečné, pokud máte nějakou prahovou hodnotu (řekněme 75) a potřebujete dostat upozornění, pokud hodnocení klesne pod tuto hodnotu.
  • Přepínač --set-exit-code-on-danger způsobí, že se příkaz ukončí s kódem 3, pokud jeden z testů na nebezpečí selže.

Nyní se podívejme na vytvoření vlastního testu, který kontroluje, zda je obraz získáván z důvěryhodného repozitáře. Vlastní testy jsou definovány ve formátu YAML a samotný test je popsán pomocí JSON schématu.

Následující fragment kódu YAML popisuje nový test s názvem checkImageRepo:

checkImageRepo:
  successMessage: Registr obrazů je platný
  failureMessage: Registr obrazů není platný
  category: Obrázky
  target: Kontejner
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

Podívejme se na něj blíže:

  • successMessage — tento řetězec se zobrazí, pokud test proběhne úspěšně;
  • failureMessage — tato zpráva se zobrazí v případě selhání;
  • category — označuje jednu z kategorií: Obrázky, Kontroly zdraví, Bezpečnost, Síťování a Zdroje;
  • target— určuje, na jaký typ objektu (spec) se test vztahuje. Možné hodnoty: Kontejner, Pod nebo Ovladač;
  • Samotný test je definován v objektu schema pomocí JSON schématu. V tomto testu je klíčové slovo pattern použito k porovnání zdroje obrazu s požadovaným.

Pro spuštění výše uvedeného testu je třeba vytvořit následující konfiguraci Polaris:

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Registr obrazů je platný
    failureMessage: Registr obrazů není platný
    category: Obrázky
    target: Kontejner
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(polaris-conf.yaml)

Analyzujme soubor:

  • V poli checks vníma testy a jejich úroveň kritičnosti. Jelikož je žádoucí dostávat upozornění, když je obraz získáván z nedůvěryhodného zdroje, nastavujeme zde úroveň danger.
  • Samotný test checkImageRepo se poté definuje v objektu customChecks.

Uložte soubor jako custom_check.yaml. Nyní je možné spustit polaris audit s YAML manifestem, který vyžaduje kontrolu.

Otestujeme náš manifest base-valid.yaml:

$ polaris audit --config custom_check.yaml --audit-path base-valid.yaml

Tým polaris audit provedl pouze uživatelský test, který byl výše stanoven, a ten nebyl úspěšný.

Pokud opravíte obraz na my-company.com/http-echo:1.0, Polaris proběhne úspěšně. Manifest s úpravami již existuje v repozitáře, takže můžete zkontrolovat předchozí příkaz v manifestu image-valid-mycompany.yaml.

Teď je otázka: jak spouštět vestavěné testy spolu s uživatelskými? Snadno! Stačí přidat identifikátory vestavěných testů do konfiguračního souboru. Výsledkem bude mít následující podobu:

checks:
  cpuRequestsMissing: varování
  cpuLimitsMissing: varování
  # Další vestavěné kontroly..
  # ..
  # vlastní kontroly
  checkImageRepo: nebezpečí # !!!
customChecks:
  checkImageRepo:        # !!!
    successMessage: Registr obrázků je platný
    failureMessage: Registr obrázků není platný
    category: Obrázky
    target: Kontejner
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^moje-firma.com/.+$

(config_with_custom_check.yaml)

Příklad úplného konfiguračního souboru je k dispozici zde.

Zkontrolovat manifest base-valid.yaml, použitím vestavěných a uživatelských testů lze pomocí příkazu:

$ polaris audit --config config_with_custom_check.yaml --audit-path base-valid.yaml

Polaris doplňuje vestavěné testy o uživatelské, čímž spojuje to nejlepší z obou světů.

Na druhou stranu, nemožnost používat mocnější jazyky, jako jsou Rego nebo JavaScript, může být omezením, které brání vytváření sofistikovanějších testů.

Další informace o Polaris jsou k dispozici na stránkách projektu.

Shrnutí

I když existuje mnoho nástrojů pro kontrolu a hodnocení YAML souborů Kubernetes, je důležité mít jasnou představu o tom, jak budou testy navrženy a prováděny.

Například, pokud bychom vzali manifesty Kubernetes procházející pipeline, kubeval by mohl být prvním krokem v takovém pipeline. Bude hlídat, zda definice objektů odpovídají API schématu Kubernetes.

Po dokončení takové kontroly by bylo možné přejít k sofistikovanějším testům, jako je shoda s osvědčenými postupy a specifickými politikami. A zde by se hodily kube-score a Polaris.

Ti, kteří mají složité požadavky a potřebují detailně konfigurovat testy, by mohli použít copper, config-lint a conftest.

Conftest a config-lint používají YAML pro zadávání uživatelských testů, zatímco copper poskytuje přístup k plnohodnotnému programovacímu jazyku, což z něj dělá docela atraktivní volbu.

Na druhou stranu, má smysl použít jeden z těchto nástrojů a tím pádem vytvářet všechny testy ručně, nebo raději zvolit Polaris a dopsat do něj jen to, co je potřeba? Na tuto otázku neexistuje jednoznačná odpověď.

Níže uvedená tabulka obsahuje stručný popis každého nástroje:

Náklad
Účel
Nevýhody
Uživatelské testy

kubeval
Kontroluje YAML manifesty na shodu s určitou verzí API schématu
Nemůže pracovat s CRD
Ne

kube-score
Analyzuje YAML manifesty na shodu s nejlepšími praktikami
Nelze vybrat svou verzi API Kubernetes pro kontrolu zdrojů
Ne

copper
Obecný rámec pro vytváření vlastních JavaScript testů pro YAML manifesty
Není vestavěné testování. Chudá dokumentace
Ano

config-lint
Obecný rámec pro vytváření testů v doménově orientovaném jazyce zabudovaném do YAML. Podporuje různé formáty konfigurací (např. Terraform)
Není dostupné hotové testování. Vestavěné assertions a funkce mohou být nedostatečné
Ano

conftest
Rámec pro vytváření vlastních testů v Rego (specializovaný dotazovací jazyk). Umožňuje sdílení politik prostřednictvím OCI bundle
Není vestavěné testování. Je nutné studovat Rego. Docker Hub není podporován při publikaci politik
Ano

Polaris
Analyzuje YAML manifesty na shodu s standardními nejlepšími praktikami. Umožňuje vytvářet vlastní testy pomocí JSON Schema
Možnosti testování založené na JSON Schema mohou být nedostatečné
Ano

Vzhledem k tomu, že tyto nástroje nezávisí na přístupu do Kubernetes clusteru, jsou snadno instalovatelné. Umožňují filtrovat vstupní soubory a poskytují rychlou zpětnou vazbu autorům pull requestů v projektech.

P.S. od překladatele

Přečtěte si také náš blog:

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster