Validazione YAML di Kubernetes secondo le migliori pratiche e politiche

Nota del traduttore.: Con l'aumento del numero di configurazioni YAML per gli ambienti K8s, cresce la necessità di una verifica automatizzata. L'autore di questa recensione non solo ha selezionato le soluzioni esistenti per questo compito, ma ha anche esaminato, utilizzando un esempio di Deployment, come funzionano. Risultando molto informativo per chi è interessato a questo tema.

Validazione YAML di Kubernetes secondo le migliori pratiche e politiche

TL;DR: L'articolo compara sei strumenti statici di verifica e valutazione dei file YAML di Kubernetes rispetto alle migliori pratiche e ai requisiti.

I carichi di lavoro di Kubernetes sono generalmente definiti in forma di documenti YAML. Uno dei problemi con YAML è la complessità nel definire vincoli o relazioni tra i file di manifest.

E se avessimo bisogno di assicurarci che tutte le immagini distribuite nel cluster provengano da un registro fidato?

Come evitare l'invio nel cluster di Deployment per i quali non sono stati impostati i PodDisruptionBudgets?

L'integrazione del testing statico consente di individuare errori e violazioni delle politiche già nella fase di sviluppo. In questo modo, aumentano le garanzie di correttezza e sicurezza delle definizioni delle risorse e aumenta la probabilità che i carichi di produzione seguano le migliori pratiche.

L'ecosistema di controllo statico dei file YAML di Kubernetes può essere suddiviso nelle seguenti categorie:

  • Validatori API. Gli strumenti in questa categoria verificano il manifesto YAML rispetto ai requisiti del server API di Kubernetes.
  • Tester pronti all'uso. Gli strumenti di questa categoria vengono forniti con test già pronti per la sicurezza, la conformità alle migliori pratiche, ecc.
  • Validatori personalizzati. I rappresentanti di questa categoria consentono di creare test personalizzati in vari linguaggi, come Rego e Javascript.

In questo articolo descriveremo e confronteremo sei diversi strumenti:

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

Bene, iniziamo!

Verifica dei Deployment

Prima di procedere al confronto degli strumenti, creiamo una base su cui testarli.

Il manifesto qui sotto contiene una serie di errori e discrepanze rispetto alle migliori pratiche: quanti ne riuscirete a trovare?

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)

Utilizzeremo questo YAML per confrontare vari strumenti.

Il manifesto sopra riportato base-valid.yaml e altri manifesti di questo articolo possono essere trovati in repository Git pubblico..

Il manifesto descrive un'applicazione web il cui compito principale è rispondere con il messaggio «Hello World» sulla porta 5678. Può essere distribuito con il seguente comando:

kubectl apply -f hello-world.yaml

E così — controlla il funzionamento:

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

Ora vai su http://localhost:8080 e conferma che l'applicazione funziona. Ma segue le migliori pratiche? Controlliamo.

1. Kubeval

Alla base kubeval L'idea di fondo è che ogni interazione con Kubernetes avvenga attraverso la sua REST API. In altre parole, è possibile utilizzare lo schema API per verificare se un determinato YAML è conforme. Analizziamo un esempio.

Istruzioni per l'installazione kubeval è disponibile sul sito del progetto.

Al momento della scrittura dell'articolo originale, era disponibile la versione 0.15.0.

Dopo averlo installato, «nutriamo» il manifesto sopra riportato:

$ kubeval base-valid.yaml
PASS - base-valid.yaml contiene un Deployment valido (http-echo)
PASS - base-valid.yaml contiene un Service valido (http-echo)

In caso di successo, kubeval terminerà con il codice di uscita 0. Puoi verificarlo come segue:

$ echo $?
0

Adesso proviamo kubeval con un altro manifesto:

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)

Puoi identificare il problema ad occhio? Eseguiamo:

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contiene un Deployment non valido (http-echo) - selector: il selettore è obbligatorio
PASS - kubeval-invalid.yaml contiene un Service valido (http-echo)

# verifichiamo il codice di ritorno
$ echo $?
1

La risorsa non supera la convalida.

I Deployment che utilizzano la versione API apps/v1, devono includere un selettore che corrisponda all'etichetta del pod. Il manifesto sopra non include un selettore, quindi kubeval ha segnalato un errore ed è uscito con un codice non zero.

Chissà cosa succederebbe se eseguissi kubectl apply -f con questo manifesto?

Bene, proviamoci:

$ kubectl apply -f kubeval-invalid.yaml
error: error validating "kubeval-invalid.yaml": error validating data: ValidationError(Deployment.spec):
manca il campo richiesto "selector" in io.k8s.api.apps.v1.DeploymentSpec; se scegli di ignorare questi errori,
 disabilita la convalida con --validate=false

Esattamente l'errore di cui ha avvertito kubeval. Può essere corretto aggiungendo un selettore:

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)

Il vantaggio di strumenti come kubeval è che tali errori possono essere intercettati nelle fasi iniziali del ciclo di distribuzione.

Inoltre, per queste convalide non è necessario avere accesso al cluster: possono essere eseguite offline.

Per impostazione predefinita, kubeval controlla le risorse per la conformità all'ultima schema API di Kubernetes. Tuttavia, nella maggior parte dei casi, potrebbe essere necessario verificare la conformità a una specifica versione di Kubernetes. Questo può essere fatto utilizzando l'opzione --kubernetes-version:

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

Si noti che la versione deve essere specificata nel formato Major.Minor.Patch.

Per visualizzare un elenco delle versioni supportate, consultare la scheda JSON su GitHub, utilizzata da kubeval per la convalida. Se è necessario eseguire kubeval offline, scaricare gli schemi e specificare la loro posizione locale utilizzando l'opzione --schema-location.

Oltre ai singoli file YAML, kubeval può anche funzionare con directory e stdin.

Inoltre, Kubeval si integra facilmente nei pipeline CI. Coloro che desiderano eseguire test prima di inviare i manifesti al cluster saranno lieti di sapere che kubeval supporta tre formati di output:

  1. Testo normale;
  2. JSON;
  3. Test Anything Protocol (TAP).

E ciascuno dei formati può essere utilizzato per ulteriori analisi dell'output, per creare un riepilogo dei risultati desiderato.

Uno degli svantaggi di kubeval è che attualmente non può controllare la conformità delle Custom Resource Definitions (CRD). Tuttavia, è possibile configurare kubeval per ignorarle.

Kubeval è un ottimo strumento per verificare e valutare le risorse; tuttavia, è importante sottolineare che il superamento del test non garantisce che la risorsa aderisca alle migliori pratiche.

Ad esempio, l'uso del tag latest all'interno del contenitore non è conforme alle migliori pratiche. Tuttavia, kubeval non lo considera un errore e non lo segnala. Quindi, il controllo di tale YAML si concluderà senza avvertimenti.

Ma cosa fare se è necessario valutare il YAML e identificare le violazioni come il tag latest? Как проверить YAML-файл на соответствие лучшим практикам?

2. Kube-score

Kube-score analizza i manifesti YAML e li valuta in base a test incorporati. Questi test vengono selezionati in base alle raccomandazioni di sicurezza e alle migliori pratiche, ad esempio:

  • Eseguire il contenitore non come root.
  • Presenza di controlli di salute per i pod.
  • Impostare le richieste e i limiti delle risorse.

Al termine del test, vengono forniti tre risultati: OK, WARNING e CRITICAL.

Kube-score può essere provato online oppure installato localmente.

Al momento della scrittura dell'articolo originale, l'ultima versione di kube-score era la 1.7.0.

Mettiamolo alla prova sul nostro manifesto base-valid.yaml:

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[CRITICAL] Tag dell'immagine del container
  · http-echo -> Immagine con etichetta latest
      È consigliato utilizzare un'etichetta fissa per evitare aggiornamenti accidentali.
[CRITICAL] NetworkPolicy del Pod
  · Il pod non ha una policy di rete corrispondente
      Crea una NetworkPolicy che miri a questo pod.
[CRITICAL] Probe del Pod
  · Il container è privo di una readinessProbe
      Una readinessProbe dovrebbe essere usata per indicare quando il servizio è pronto a ricevere traffico.
      Senza di essa, il Pod rischia di ricevere traffico prima di essere avviato. Viene utilizzata anche durante
      i rollout e può prevenire tempi di inattività se una nuova versione dell'applicazione non riesce.
      Maggiori informazioni: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITICAL] Contesto di sicurezza del container
  · http-echo -> Container non ha un contesto di sicurezza configurato
      Imposta securityContext per eseguire il container in un contesto più sicuro.
[CRITICAL] Risorse del container
  · http-echo -> Limite della CPU non è impostato
      È consigliato impostare limiti di risorse per evitare DDOS di risorse. Imposta resources.limits.cpu
  · http-echo -> Limite della memoria non è impostato
      È consigliato impostare limiti di risorse per evitare DDOS di risorse. Imposta resources.limits.memory
  · http-echo -> Richiesta della CPU non è impostata
      È consigliato impostare richieste di risorse per assicurarsi che l'applicazione possa avviarsi e funzionare senza
      arresti anomali. Imposta resources.requests.cpu
  · http-echo -> Richiesta della memoria non è impostata
      È consigliato impostare richieste di risorse per assicurarsi che l'applicazione possa avviarsi e funzionare senza arresti anomali.
      Imposta resources.requests.memory
[CRITICAL] Il deployment ha PodDisruptionBudget
  · Nessun PodDisruptionBudget corrispondente è stato trovato
      È consigliato definire un PodDisruptionBudget per evitare inattività imprevista durante le operazioni di
      manutenzione di Kubernetes, come quando si svuota un nodo.
[WARNING] Il deployment ha host PodAntiAffinity
  · Il deployment non ha impostata una podAntiAffinity host
      È consigliato impostare una podAntiAffinity per evitare che più pod di un deployment vengano
      programmati sullo stesso nodo. Questo aumenta la disponibilità nel caso in cui il nodo diventi non disponibile.

YAML supera i controlli di kubeval, mentre kube-score indica le seguenti criticità:

  • Controlli di prontezza non configurati.
  • Mancano richieste e limiti per le risorse CPU e memoria.
  • Non sono stati definiti budget di interruzione dei Pod.
  • Mancano le regole di anti-affinità (anti-affinity) per massimizzare la disponibilità.
  • Il contenitore gira con root.

Tutti questi sono commenti legittimi sulle criticità da affrontare per rendere il Deployment più efficace e affidabile.

Team kube-score fornisce informazioni in un formato leggibile includendo tutte le violazioni del tipo WARNING e CRITICAL, il che è molto utile durante lo sviluppo.

Coloro che desiderano utilizzare questo strumento all'interno di una pipeline CI possono abilitare un'uscita più concisa usando il flag --output-format ci (in questo caso vengono mostrati anche i test con il risultato 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) Limite CPU non impostato
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Limite di memoria non impostato
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Richiesta CPU non impostata
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Richiesta di memoria non impostata
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Immagine con tag latest
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: Il pod non ha una policy di rete corrispondente
[CRITICAL] http-echo apps/v1/Deployment: Il contenitore manca di un readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Contenitore privo di security context configurato
[CRITICAL] http-echo apps/v1/Deployment: Nessun PodDisruptionBudget corrispondente trovato
[WARNING] http-echo apps/v1/Deployment: Il deployment non ha impostazioni podAntiAffinity del host
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

Analogamente a kubeval, kube-score restituisce un codice di uscita diverso da zero in caso di test concluso con errore CRITICAL. È possibile attivare una gestione simile anche per WARNING.

Inoltre, è possibile controllare le risorse per verificare la conformità a diverse versioni API (come in kubeval). Tuttavia, queste informazioni sono ‘hardcode’ nel kube-score: non è possibile selezionare un'altra versione di Kubernetes. Questa limitazione può diventare un grosso problema se si intende aggiornare il cluster o se si hanno più cluster con versioni diverse di K8s.

Nota che c'è già un issue con una proposta per implementare questa funzione.

Per maggiori dettagli su kube-score, puoi visitare sito ufficiale.

I test di kube-score sono un ottimo strumento per implementare le migliori pratiche, ma cosa fare se è necessario modificare un test o aggiungere regole personalizzate? Purtroppo, non è possibile farlo.

Kube-score non è espandibile: non è possibile aggiungere o adattare criteri.

Se è necessario scrivere test personalizzati per verifiche di conformità alle politiche adottate in azienda, è possibile utilizzare uno dei seguenti quattro strumenti: config-lint, copper, conftest o polaris.

3. Config-lint

Config-lint è uno strumento per la validazione di file di configurazione in formato YAML, JSON, Terraform, CSV e manifesti Kubernetes.

Puoi installarlo seguendo le istruzioni sul sito del progetto.

L'attuale rilascio, al momento della scrittura dell'articolo originale, è 1.5.0.

Config-lint non contiene test integrati per la verifica dei manifesti Kubernetes.

Per eseguire qualsiasi test, è necessario creare regole appropriate. Queste vengono scritte in file YAML, chiamati "set di regole" (rulesets), e hanno la seguente struttura:

version: 1
descrizione: Regole per i file di specifica Kubernetes
tipo: Kubernetes
files:
  - "*.yaml"
rules:
   # elenco delle regole

(rule.yaml)

Esploriamo più da vicino:

  • Campo type indica quale tipo di configurazione utilizzerà config-lint. Per i manifesti K8s, è sempre Kubernetes.
  • Nel campo files oltre ai file stessi, è possibile specificare una directory.
  • Campo rules è destinato a impostare test personalizzati.

Supponiamo che tu voglia assicurarti che le immagini nel Deployment vengano sempre scaricate da un repository fidato come my-company.com/myapp:1.0. La regola per config-lint che esegue tale controllo sarà la seguente:

- id: MY_DEPLOYMENT_IMAGE_TAG
  severity: FAILURE
  message: Il Deployment deve utilizzare un tag immagine valido
  resource: Deployment
  assertions:
    - every:
        key: spec.template.spec.containers
        expressions:
          - key: image
            op: starts-with
            value: "my-company.com/"

(rule-trusted-repo.yaml)

Per ogni regola devono essere specificati i seguenti attributi:

  • id — identificatore unico della regola;
  • severity — può essere FAILURE, WARNING e NON_COMPLIANT;
  • message — quando la regola viene violata, viene visualizzato il contenuto di questa riga;
  • resource — tipo di risorsa a cui si applica questa regola;
  • assertions — elenco di condizioni che verranno valutate rispetto a questa risorsa.

Nella regola sopra assertion chiamata every verifica che tutti i contenitori nel Deployment (key: spec.templates.spec.containers) utilizzino immagini fidate (cioè, che iniziano con my-company.com/).

Il set completo delle regole è il seguente:

version: 1
description: Regole per i file di specifica Kubernetes
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    severity: FAILURE
    message: Il deployment deve utilizzare un repository di immagini valido
    resource: Deployment
    assertions:
      - every:
          key: spec.template.spec.containers
          expressions:
            - key: image
              op: starts-with
              value: "my-company.com/"

(ruleset.yaml)

Per eseguire il test, salviamolo come check_image_repo.yaml. Eseguiamo la verifica sul file base-valid.yaml:

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

[
  {
  "AssertionMessage": "Ogni espressione fallisce: L'espressione And fallisce: l'immagine non inizia con 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": "Il deployment deve utilizzare un repository di immagini valido",
  "Status": "FAILURE"
  }
]

La verifica è fallita. Ora verifichiamo il prossimo manifesto con un repository di immagini corretto:

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)

Eseguiamo lo stesso test con il manifesto sopra riportato. Nessun problema riscontrato:

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

Config-lint è un framework promettente che consente di creare test personalizzati per verificare i manifest YAML di Kubernetes utilizzando YAML DSL.

Ma cosa fare se è necessaria una logica e dei test più complessi? Non sono le capacità di YAML troppo limitate per questo? E se fosse possibile creare test in un linguaggio di programmazione completo?

4. Copper

Copper V2 è un framework per la validazione dei manifest tramite test personalizzati (simile a config-lint).

Tuttavia, a differenza dell'ultimo, non utilizza YAML per descrivere i test. Invece, i test possono essere creati in JavaScript. Copper fornisce una libreria con diversi strumenti di base, utili per leggere informazioni sugli oggetti Kubernetes e segnalare errori.

La sequenza di passaggi per installare Copper può essere trovata in documentazione ufficiale.

2.0.1 — l'ultima versione di questo strumento al momento della scrittura dell'articolo originale.

Come config-lint, anche Copper non ha test integrati. Scriviamone uno. Dovrebbe verificare che i deployment utilizzino immagini di contenitore esclusivamente da repository fidati come my-company.com.

Crea un file check_image_repo.js con il seguente contenuto:

$$.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',"L'immagine " + $.metadata.name + " non proviene dal repository di my-company.com", 1)
            }
        });
    }
});

Ora, per controllare il nostro manifesto base-valid.yaml, usa il comando copper validate:

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

Check no_company_repo failed with severity 1 due to Image http-echo is not from my-company.com repo
Validazione fallita

È chiaro che con copper è possibile eseguire test più complessi, ad esempio verificare i nomi di dominio nei manifesti Ingress o rifiutare i pod che funzionano in modalità privilegiata.

Copper include diverse funzioni di utilità:

  • DockerImage legge il file di input specificato e crea un oggetto con i seguenti attributi:
    • name — nome dell'immagine,
    • tag — tag dell'immagine,
    • registry — registro delle immagini,
    • registry_url — protocollo (https://) e registro delle immagini,
    • fqin — posizione completa dell'immagine.
  • Funzione findByName aiuta a trovare una risorsa per tipo di risorsa (kind) e nome (name) dal file di input.
  • Funzione findByLabels aiuta a trovare una risorsa per tipo (kind) e etichette (etichette).

È possibile consultare tutte le funzioni di utilità disponibili qui.

Per impostazione predefinita, carica l'intero file YAML di input nella variabile $$ e la rende accessibile per gli script (metodo familiare per chi ha esperienza con jQuery).

Il principale vantaggio di Copper è chiaro: non è necessario apprendere un linguaggio specialistico e si possono utilizzare varie possibilità di JavaScript per creare i propri test, come l'interpolazione delle stringhe, funzioni, ecc.

Va inoltre notato che l'attuale versione di Copper funziona con la versione ES5 del motore JavaScript, non con ES6.

Ulteriori dettagli sono disponibili su sito ufficiale del progetto.

Tuttavia, se non ami molto JavaScript e preferisci un linguaggio specificamente progettato per creare richieste e descrivere politiche, dovresti dare un'occhiata a conftest.

5. Conftest

Conftest è un framework per la verifica dei dati di configurazione. È adatto anche per testare/verificare i manifesti Kubernetes. I test sono descritti utilizzando un linguaggio di query specializzato Rego.

È possibile installare conftest utilizzando istruzioni, disponibili sul sito del progetto.

Al momento della stesura dell'articolo originale, l'ultima versione disponibile era 0.18.2.

Analogamente a config-lint e copper, conftest non include test integrati. Proviamolo e scriviamo la nostra politica. Come negli esempi precedenti, verificheremo se le immagini dei container provengono da una fonte affidabile.

Crea una directory conftest-checks, e al suo interno un file di nome check_image_registry.rego con il seguente contenuto:

package main

deny[msg] {

  input.kind == "Deployment"
  image := input.spec.template.spec.containers[_].image
  not startswith(image, "my-company.com/")
  msg := sprintf("l'immagine '%v' non proviene dal repository di my-company.com", [image])
}

Ora testiamo base-valid.yaml tramite conftest:

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

FAIL - base-valid.yaml - l'immagine 'hashicorp/http-echo' non proviene dal repository di my-company.com
1 test, 1 passato, 0 avvisi, 1 errore

Il test è fallito come previsto, poiché le immagini provengono da una fonte non affidabile.

Nel file Rego definiamo un blocco deny. La sua verità è considerata una violazione. Se ci sono più blocchi, conftest li verifica indipendentemente l'uno dall'altro e la verità di uno qualsiasi dei blocchi è interpretata come una violazione. deny Alcuni, conftest verifica ciascuno in modo indipendente, e la verità di uno qualsiasi dei blocchi è considerata una violazione.

Oltre all'uscita predefinita, conftest supporta JSON, TAP e il formato tabellare — un'opzione estremamente utile se è necessario integrare i report in un pipeline CI esistente. È possibile impostare il formato desiderato utilizzando il flag --output.

Per semplificare il debug delle politiche, in conftest è presente un flag --trace. Questo mostra la tracciatura di come conftest analizza i file di politiche specificati.

Le politiche di conftest possono essere pubblicate e condivise in registri OCI (Open Container Initiative) come artefatti.

Comandi push e pull consentono di pubblicare un artefatto o estrarre un artefatto esistente da un registro remoto. Proviamo a pubblicare la nostra politica nel registro Docker locale usando conftest push.

Avvia il registro Docker locale:

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

In un altro terminale, vai nella directory creata in precedenza conftest-checks e digita il seguente comando:

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

Se il comando è andato a buon fine, vedrai un messaggio del tipo:

2020/06/10 14:25:43 pushed bundle with digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609c

Ora crea una directory temporanea ed esegui il comando al suo interno conftest pull. Questo scaricherà il pacchetto creato dal comando precedente:

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

Nella directory temporanea apparirà una sottodirectory policy, contenente il nostro file di politica:

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

I test possono essere eseguiti direttamente dal repository:

$ conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
FAIL - base-valid.yaml - l'immagine 'hashicorp/http-echo' non proviene dal repository my-company.com
2 test, 1 passato, 0 avvisi, 1 fallimento

Sfortunatamente, DockerHub non è ancora supportato. Quindi consideratevi fortunati se state utilizzando Azure Container Registry (ACR) o il vostro repository personale.

Il formato degli artefatti è lo stesso dei pacchetti Open Policy Agent (OPA), il che consente di utilizzare conftest per eseguire test da pacchetti OPA esistenti.

Maggiori informazioni sulla condivisione delle politiche e altre funzionalità di conftest possono essere trovate su sito ufficiale del progetto.

6. Polaris

L'ultimo strumento di cui parleremo in questo articolo è Polaris. (La sua annuncio dell'anno scorso è stato già tradottonota del traduttore.)

Polaris può essere installato in un cluster o utilizzato in modalità da riga di comando. Come avrete già indovinato, permette di analizzare staticamente i manifesti Kubernetes.

Quando si lavora in modalità da riga di comando, sono disponibili test integrati che coprono aree come la sicurezza e le migliori pratiche (simile a kube-score). Inoltre, è possibile creare test personalizzati (come in config-lint, copper e conftest).

In altre parole, Polaris combina i vantaggi di entrambe le categorie di strumenti: con test integrati e personalizzati.

Per installare Polaris in modalità da riga di comando, segui le istruzioni sul sito del progetto.

Al momento della stesura dell'articolo originale, è disponibile la versione 1.0.3.

Una volta completata l'installazione, puoi avviare polaris sul manifesto base-valid.yaml utilizzando il seguente comando:

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

Genererà una stringa in formato JSON con una descrizione dettagliata dei test eseguiti e dei loro risultati. L'output avrà la seguente struttura:

{
  "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": [
    /* lunga lista */
  ]
}

L'output completo è disponibile qui.

Come kube-score, Polaris identifica problemi nelle aree in cui il manifesto non è in linea con le migliori pratiche:

  • Mancano controlli sulla salute dei pod.
  • Non sono specificate le etichette per le immagini dei container.
  • Il contenitore gira con root.
  • Non sono specificati i request e i limit per memoria e CPU.

Ogni test viene assegnato un livello di criticità in base ai suoi risultati: warning o danger. Per saperne di più sui test integrati disponibili, contattare documentazione.

Se non sono necessari dettagli, è possibile specificare il flag --format score. In questo caso, Polaris restituirà un numero compreso tra 1 e 100 — score (cioè la valutazione):

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

Più la valutazione è vicina a 100, maggiore è il grado di conformità. Se si verifica il codice di uscita del comando polaris audit, si scoprirà che è pari a 0.

Forzare polaris audit a terminare con un codice non nullo può essere fatto con due flag:

  • Flag --set-exit-code-below-score accetta come argomento un valore soglia compreso tra 1 e 100. In questo caso, il comando terminerà con un codice di uscita 4 se la valutazione è inferiore alla soglia. Questo è molto utile quando si ha un certo valore soglia (diciamo, 75) e si desidera ricevere un avviso se la valutazione scende al di sotto.
  • Flag --set-exit-code-on-danger causerà che il comando termini con codice 3 se uno dei test di pericolo fallisce.

Ora proviamo a creare un test personalizzato che controlla se l'immagine proviene da un repository fidato. I test personalizzati sono definiti in formato YAML e il test stesso è descritto utilizzando JSON Schema.

Il seguente frammento di codice YAML descrive un nuovo test chiamato checkImageRepo:

checkImageRepo:
  successMessage: Il registro delle immagini è valido
  failureMessage: Il registro delle immagini non è valido
  category: Immagini
  target: Contenitore
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

Esaminiamolo più da vicino:

  • successMessage — questa stringa verrà visualizzata se il test ha avuto successo;
  • failureMessage — questo messaggio verrà mostrato in caso di fallimento;
  • category — indica una delle categorie: Immagini, Health Checks, Sicurezza, Networking e Risorse;
  • target—- definisce il tipo di oggetto a cui si applica il test (spec) possibile valori: Contenitore, Pod o Controller;
  • Il test stesso è definito all'interno dell'oggetto schema usando JSON schema. In questo test la parola chiave pattern è utilizzata per confrontare la sorgente dell'immagine con quella richiesta.

Per eseguire il test sopra descritto, è necessario creare la seguente configurazione di Polaris:

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Il registro delle immagini è valido
    failureMessage: Il registro delle immagini non è valido
    category: Immagini
    target: Contenitore
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(polaris-conf.yaml)

Analizziamo il file:

  • Nel campo checks si definiscono i test e il loro livello di criticità. Poiché è preferibile ricevere un avviso quando un'immagine proviene da una fonte non affidabile, impostiamo qui il livello danger.
  • Il test stesso checkImageRepo quindi viene definito nell'oggetto customChecks.

Salva il file come custom_check.yaml. Ora puoi eseguire polaris audit con il manifesto YAML che richiede una verifica.

Testeremo il nostro manifesto base-valid.yaml:

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

Team polaris audit ha eseguito solo il test personalizzato di cui sopra, e non ha avuto successo.

Se correggi l'immagine in my-company.com/http-echo:1.0, Polaris terminerà con successo. Il manifesto con le modifiche è già presente in repository, quindi puoi verificare il comando precedente sul manifesto image-valid-mycompany.yaml.

Ora la domanda è: come eseguire i test integrati insieme a quelli personalizzati? Facile! Basta aggiungere gli identificatori dei test integrati nel file di configurazione. Di conseguenza, assumerà il seguente aspetto:

verifiche:
  cpuRequestsMissing: avviso
  cpuLimitsMissing: avviso
  # Altre verifiche integrate..
  # ..
  # controlli personalizzati
  checkImageRepo: pericolo # !!!
controlliPersonalizzati:
  checkImageRepo:        # !!!
    successMessage: Il registro delle immagini è valido
    failureMessage: Il registro delle immagini non è valido
    category: Immagini
    target: Contenitore
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(config_with_custom_check.yaml)

Un esempio completo di file di configurazione è disponibile qui.

Controlla il manifesto base-valid.yaml, utilizzando test integrati e personalizzati, è possibile attraverso il comando:

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

Polaris arricchisce i test integrati con quelli personalizzati, combinando il meglio di entrambi i mondi.

D'altra parte, la mancata possibilità di utilizzare lingue più potenti come Rego o JavaScript può diventare un fattore limitante, ostacolando la creazione di test più sofisticati.

Ulteriori informazioni su Polaris sono disponibili su sito del progetto.

Riepilogo

Sebbene esistano numerosi strumenti per controllare e valutare i file YAML di Kubernetes, è importante avere una chiara comprensione di come i test saranno progettati ed eseguiti.

Ad esempio, se si considerano i manifesti Kubernetes che passano attraverso la pipeline, kubeval potrebbe essere il primo passo in tale pipeline. Si assicurerà che le definizioni degli oggetti siano conformi allo schema API di Kubernetes.

Una volta completato questo tipo di verifica, si potrebbe passare a test più avanzati, come la conformità alle migliori pratiche standard e a politiche specifiche. Qui sarebbero utili kube-score e Polaris.

Coloro che hanno requisiti complessi e necessità di configurare i test in dettaglio troverebbero utili copper, config-lint e conftest..

Conftest e config-lint utilizzano YAML per definire i test personalizzati, mentre copper fornisce accesso a un vero e proprio linguaggio di programmazione, rendendolo una scelta piuttosto attraente.

D'altra parte, è meglio utilizzare uno di questi strumenti e quindi creare tutti i test manualmente, oppure optare per Polaris e aggiungere solo ciò di cui si ha bisogno? Non esiste una risposta definitiva a questa domanda..

La tabella qui sotto fornisce una breve descrizione di ogni strumento:

Strumento
Scopo
Svantaggi
Test personalizzati

kubeval
Verifica i manifesti YAML per la conformità a una determinata versione dello schema API
Non può lavorare con CRD
No

kube-score
Analizza i manifesti YAML per la conformità alle migliori pratiche
Non è possibile scegliere una propria versione dell'API Kubernetes per il controllo delle risorse.
No

copper
Un framework generale per creare test JavaScript personalizzati per manifesti YAML
Nessun test integrato. Documentazione scarsa

config-lint
Un framework generale per creare test in un linguaggio orientato agli oggetti, incorporato in YAML. Supporta vari formati di configurazione (ad esempio, Terraform)
Nessun test predefinito. Potrebbero mancare assertions e funzioni incorporate

conftest
Framework per la creazione di test personalizzati in Rego (un linguaggio di query specializzato). Consente di condividere politiche tramite OCI bundles
Nessun test integrato. Necessità di apprendere Rego. Docker Hub non è supportato per la pubblicazione delle politiche

Polaris
Analizza i manifesti YAML per conformità alle migliori pratiche standard. Permette di creare test personalizzati utilizzando JSON Schema
Le funzionalità dei test basati su JSON Schema potrebbero non essere sufficienti

Poiché questi strumenti non dipendono dall'accesso al cluster Kubernetes, sono facili da installare. Permettono di filtrare i file sorgente e forniscono un rapido feedback agli autori delle pull request nei progetti.

P.S. dal traduttore

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster