Zweryfikuj Kubernetes YAML pod kątem najlepszych praktyk i zasad

Notatka. przeł.: Wraz z rosnącą liczbą konfiguracji YAML dla środowisk K8s, potrzeba ich automatycznej weryfikacji staje się coraz pilniejsza. Autor tej recenzji nie tylko wybrał istniejące rozwiązania do tego zadania, ale także posłużył się przykładem Deployment, aby zobaczyć, jak one działają. Okazało się to bardzo pouczające dla osób zainteresowanych tym tematem.

Zweryfikuj Kubernetes YAML pod kątem najlepszych praktyk i zasad

TL; DR: w tym artykule porównano sześć statycznych narzędzi do sprawdzania poprawności i oceny plików Kubernetes YAML pod kątem najlepszych praktyk i wymagań.

Obciążenia Kubernetes są zwykle definiowane w formie dokumentów YAML. Jednym z problemów związanych z YAML jest trudność w określeniu ograniczeń lub relacji pomiędzy plikami manifestu.

Co zrobić, jeśli musimy się upewnić, że wszystkie obrazy wdrożone w klastrze pochodzą z zaufanego rejestru?

Jak mogę zapobiec wysyłaniu do klastra wdrożeń, które nie mają PodDisruptionBudgets?

Integracja testów statycznych pozwala na identyfikację błędów i naruszeń zasad już na etapie rozwoju. Zwiększa to gwarancję, że definicje zasobów są prawidłowe i bezpieczne, i zwiększa prawdopodobieństwo, że obciążenia produkcyjne będą zgodne z najlepszymi praktykami.

Ekosystem inspekcji statycznych plików YAML Kubernetes można podzielić na następujące kategorie:

  • Walidatory API. Narzędzia z tej kategorii sprawdzają manifest YAML pod kątem wymagań serwera Kubernetes API.
  • Gotowe testery. Narzędzia z tej kategorii posiadają gotowe testy pod kątem bezpieczeństwa, zgodności z najlepszymi praktykami itp.
  • Niestandardowe walidatory. Przedstawiciele tej kategorii umożliwiają tworzenie niestandardowych testów w różnych językach, na przykład Rego i JavaScript.

W tym artykule opiszemy i porównamy sześć różnych narzędzi:

  1. kubeval;
  2. kube-score;
  3. config-lint;
  4. miedź;
  5. konkurs;
  6. polarny.

Cóż, zaczynajmy!

Sprawdzanie wdrożeń

Zanim zaczniemy porównywać narzędzia, stwórzmy tło, na którym będziemy mogli je przetestować.

W poniższym manifeście znajduje się szereg błędów i niezgodności z dobrymi praktykami: ile ich można znaleźć?

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)

Będziemy używać tego YAML do porównywania różnych narzędzi.

Powyższy manifest base-valid.yaml i inne manifesty z tego artykułu można znaleźć w Repozytoria Git.

Manifest opisuje aplikację internetową, której głównym zadaniem jest udzielenie odpowiedzi komunikatem „Hello World” na porcie 5678. Można ją wdrożyć za pomocą następującego polecenia:

kubectl apply -f hello-world.yaml

I tak - sprawdź pracę:

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

Teraz przejdź do http://localhost:8080 i potwierdź, że aplikacja działa. Ale czy jest to zgodne z najlepszymi praktykami? Sprawdźmy.

1. Kubeval

Sercem kubeval Pomysł jest taki, że wszelka interakcja z Kubernetesem odbywa się poprzez jego API REST. Innymi słowy, możesz użyć schematu API, aby sprawdzić, czy dany YAML jest z nim zgodny. Spójrzmy na przykład.

Instrukcje Instalacji kubeval są dostępne na stronie projektu.

W momencie pisania oryginalnego artykułu dostępna była wersja 0.15.0.

Po zainstalowaniu przekażmy mu powyższy manifest:

$ kubeval base-valid.yaml
PASS - base-valid.yaml contains a valid Deployment (http-echo)
PASS - base-valid.yaml contains a valid Service (http-echo)

Jeśli się powiedzie, kubeval zakończy działanie z kodem wyjścia 0. Możesz to sprawdzić w następujący sposób:

$ echo $?
0

Spróbujmy teraz kubeval z innym 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)

Czy potrafisz dostrzec problem naocznie? Uruchommy:

$ kubeval kubeval-invalid.yaml
WARN - kubeval-invalid.yaml contains an invalid Deployment (http-echo) - selector: selector is required
PASS - kubeval-invalid.yaml contains a valid Service (http-echo)

# проверим код возврата
$ echo $?
1

Zasób nie jest weryfikowany.

Wdrożenia z wykorzystaniem wersji API apps/v1, musi zawierać selektor pasujący do etykiety poda. Powyższy manifest nie zawiera selektora, więc kubeval zgłosił błąd i zakończył działanie z niezerowym kodem.

Zastanawiam się, co się stanie, jeśli to zrobię kubectl apply -f z tym manifestem?

Cóż, spróbujmy:

$ 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

To jest dokładnie ten błąd, przed którym ostrzegał kubeval. Możesz to naprawić, dodając selektor:

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)

Zaletą narzędzi takich jak kubeval jest to, że tego typu błędy można wykryć na wczesnym etapie cyklu wdrażania.

Dodatkowo kontrole te nie wymagają dostępu do klastra, można je przeprowadzić w trybie offline.

Domyślnie kubeval sprawdza zasoby pod kątem najnowszego schematu Kubernetes API. Jednak w większości przypadków może być konieczne sprawdzenie konkretnej wersji Kubernetes. Można to zrobić za pomocą flagi --kubernetes-version:

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

Należy pamiętać, że w formacie należy podać wersję Major.Minor.Patch.

Aby zapoznać się z listą wersji, dla których obsługiwana jest weryfikacja, zobacz Schemat JSON w GitHubie, którego kubeval używa do sprawdzania poprawności. Jeśli chcesz uruchomić Kubeval w trybie offline, pobierz schematy i określ ich lokalną lokalizację za pomocą flagi --schema-location.

Oprócz pojedynczych plików YAML, kubeval może także pracować z katalogami i standardowym wejściem.

Ponadto Kubeval łatwo integruje się z potokiem CI. Tych, którzy chcą przeprowadzić testy przed wysłaniem manifestów do klastra, z pewnością ucieszy informacja, że ​​kubeval obsługuje trzy formaty wyjściowe:

  1. Zwykły tekst;
  2. JSON;
  3. Przetestuj dowolny protokół (TAP).

Dowolnego formatu można użyć do dalszej analizy wyników w celu wygenerowania podsumowania wyników żądanego typu.

Jedną z wad kubeval jest to, że obecnie nie może sprawdzić zgodności z niestandardowymi definicjami zasobów (CRD). Można jednak skonfigurować kubeval Ignoruj ​​ich.

Kubeval to świetne narzędzie do sprawdzania i oceny zasobów; Należy jednak podkreślić, że zdanie testu nie gwarantuje, że zasób jest zgodny z najlepszymi praktykami.

Na przykład za pomocą tagu latest w kontenerze nie jest zgodne z najlepszymi praktykami. Jednak kubeval nie uważa tego za błąd i nie zgłasza go. Oznacza to, że weryfikacja takiego YAML zakończy się bez ostrzeżeń.

Ale co, jeśli chcesz ocenić YAML i zidentyfikować naruszenia, takie jak tag latest? Jak sprawdzić plik YAML pod kątem najlepszych praktyk?

2. Wynik Kube

Wynik Kube'a analizuje manifesty YAML i ocenia je na podstawie wbudowanych testów. Testy te są wybierane w oparciu o wytyczne i najlepsze praktyki dotyczące bezpieczeństwa, takie jak:

  • Uruchamianie kontenera nie jako root.
  • Dostępność kontroli stanu podów.
  • Ustawianie żądań i limitów zasobów.

Na podstawie wyników testu podawane są trzy wyniki: OK, OSTRZEŻENIE и KRYTYCZNY.

Możesz wypróbować Kube-score online lub zainstalować go lokalnie.

W momencie pisania oryginalnego artykułu najnowsza wersja kube-score wynosiła 1.7.0.

Wypróbujmy to w naszym manifeście base-valid.yaml:

$ kube-score score base-valid.yaml

apps/v1/Deployment http-echo
[CRITICAL] Container Image Tag
  · http-echo -> Image with latest tag
      Using a fixed tag is recommended to avoid accidental upgrades
[CRITICAL] Pod NetworkPolicy
  · The pod does not have a matching network policy
      Create a NetworkPolicy that targets this pod
[CRITICAL] Pod Probes
  · Container is missing a readinessProbe
      A readinessProbe should be used to indicate when the service is ready to receive traffic.
      Without it, the Pod is risking to receive traffic before it has booted. It is also used during
      rollouts, and can prevent downtime if a new version of the application is failing.
      More information: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRITICAL] Container Security Context
  · http-echo -> Container has no configured security context
      Set securityContext to run the container in a more secure context.
[CRITICAL] Container Resources
  · http-echo -> CPU limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.cpu
  · http-echo -> Memory limit is not set
      Resource limits are recommended to avoid resource DDOS. Set resources.limits.memory
  · http-echo -> CPU request is not set
      Resource requests are recommended to make sure that the application can start and run without
      crashing. Set resources.requests.cpu
  · http-echo -> Memory request is not set
      Resource requests are recommended to make sure that the application can start and run without crashing.
      Set resources.requests.memory
[CRITICAL] Deployment has PodDisruptionBudget
  · No matching PodDisruptionBudget was found
      It is recommended to define a PodDisruptionBudget to avoid unexpected downtime during Kubernetes
      maintenance operations, such as when draining a node.
[WARNING] Deployment has host PodAntiAffinity
  · Deployment does not have a host podAntiAffinity set
      It is recommended to set a podAntiAffinity that stops multiple pods from a deployment from
      being scheduled on the same node. This increases availability in case the node becomes unavailable.

YAML przechodzi testy kubeval, natomiast kube-score wskazuje na następujące wady:

  • Kontrole gotowości nie są skonfigurowane.
  • Nie ma żadnych żądań ani ograniczeń dotyczących zasobów procesora i pamięci.
  • Budżety na zakłócenia podów nie są określone.
  • Nie ma żadnych zasad separacji (antypowinowactwo) aby zmaksymalizować dostępność.
  • Kontener działa jako root.

To wszystko są ważne uwagi dotyczące niedociągnięć, którymi należy się zająć, aby wdrożenie było bardziej wydajne i niezawodne.

Zespół kube-score wyświetla informacje w formie czytelnej dla człowieka, w tym wszystkie rodzaje naruszeń OSTRZEŻENIE и KRYTYCZNY, co bardzo pomaga podczas rozwoju.

Osoby chcące używać tego narzędzia w potoku CI mogą włączyć bardziej skompresowane dane wyjściowe za pomocą flagi --output-format ci (w tym przypadku wyświetlane są również testy z wynikiem 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 is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory limit is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) CPU request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Memory request is not set
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Image with latest tag
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: The pod does not have a matching network policy
[CRITICAL] http-echo apps/v1/Deployment: Container is missing a readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Container has no configured security context
[CRITICAL] http-echo apps/v1/Deployment: No matching PodDisruptionBudget was found
[WARNING] http-echo apps/v1/Deployment: Deployment does not have a host podAntiAffinity set
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service

Podobnie jak kubeval, kube-score zwraca niezerowy kod zakończenia, gdy test zakończy się niepowodzeniem KRYTYCZNY. Możesz także włączyć podobne przetwarzanie dla OSTRZEŻENIE.

Dodatkowo istnieje możliwość sprawdzenia zasobów pod kątem zgodności z różnymi wersjami API (jak w kubeval). Jednak ta informacja jest zakodowana na stałe w samym kube-score: nie można wybrać innej wersji Kubernetesa. To ograniczenie może stanowić duży problem, jeśli zamierzasz uaktualnić swój klaster lub jeśli masz wiele klastrów z różnymi wersjami K8.

Uwaga! jest już problem z propozycją wykorzystania tej szansy.

Więcej informacji na temat kube-score można znaleźć na stronie Oficjalna strona.

Testy Kube-score są doskonałym narzędziem do wdrażania najlepszych praktyk, ale co jeśli zajdzie potrzeba wprowadzenia zmian w teście lub dodania własnych reguł? Niestety, nie da się tego zrobić.

Kube-score nie jest rozszerzalny: nie można do niego dodawać polityk ani ich dostosowywać.

Jeżeli potrzebujesz napisać niestandardowe testy sprawdzające zgodność z polityką firmy, możesz skorzystać z jednego z czterech narzędzi: config-lint, copper, conftest lub polaris.

3.Konfiguracja-lint

Config-lint to narzędzie do sprawdzania poprawności plików konfiguracyjnych YAML, JSON, Terraform, CSV i manifestów Kubernetes.

Możesz go zainstalować za pomocą instrukcje na stronie internetowej projektu.

Obecna wersja w momencie pisania oryginalnego artykułu to 1.5.0.

Config-lint nie ma wbudowanych testów sprawdzających poprawność manifestów Kubernetes.

Aby przeprowadzić jakiekolwiek testy, należy stworzyć odpowiednie reguły. Są one zapisane w plikach YAML zwanych „zestawami reguł” (zestawy reguł)i mają następującą strukturę:

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:
   # список правил

(rule.yaml)

Przeanalizujmy to bliżej:

  • Pole type określa jakiego typu konfigurację będzie używał config-lint. W przypadku K8 jest to oczywiste zawsze Kubernetes.
  • W polu files Oprócz samych plików możesz określić katalog.
  • Pole rules przeznaczony do ustawiania testów użytkownika.

Załóżmy, że chcesz mieć pewność, że obrazy we wdrożeniu będą zawsze pobierane z zaufanego repozytorium, np my-company.com/myapp:1.0. Reguła config-lint wykonująca taką kontrolę wyglądałaby następująco:

- id: MY_DEPLOYMENT_IMAGE_TAG
  severity: FAILURE
  message: Deployment must use a valid image tag
  resource: Deployment
  assertions:
    - every:
        key: spec.template.spec.containers
        expressions:
          - key: image
            op: starts-with
            value: "my-company.com/"

(rule-trusted-repo.yaml)

Każda reguła musi mieć następujące atrybuty:

  • id — unikalny identyfikator reguły;
  • severity - Może NIEPOWODZENIE, OSTRZEŻENIE и NIEZGODNY;
  • message — w przypadku naruszenia reguły wyświetlana jest zawartość tej linii;
  • resource — rodzaj zasobu, do którego ma zastosowanie ta zasada;
  • assertions — wykaz warunków, które będą oceniane w odniesieniu do tego zasobu.

W powyższym przepisie assertion prawo every sprawdza, czy wszystkie kontenery znajdują się w fazie wdrożenia (key: spec.templates.spec.containers) użyj zaufanych obrazów (tj. zaczynając od my-company.com/).

Kompletny zestaw reguł wygląda następująco:

version: 1
description: Rules for Kubernetes spec files
type: Kubernetes
files:
  - "*.yaml"
rules:

 - id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
    severity: FAILURE
    message: Deployment must use a valid image repository
    resource: Deployment
    assertions:
      - every:
          key: spec.template.spec.containers
          expressions:
            - key: image
              op: starts-with
              value: "my-company.com/"

(ruleset.yaml)

Aby wypróbować test, zapiszmy go jako check_image_repo.yaml. Sprawdźmy plik 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"
  }
]

Kontrola nie powiodła się. Sprawdźmy teraz następujący manifest z poprawnym repozytorium obrazów:

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)

Przeprowadzamy ten sam test z powyższym manifestem. Nie znaleziono problemów:

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

Config-lint to obiecująca platforma, która umożliwia tworzenie własnych testów w celu sprawdzania poprawności manifestów YAML Kubernetes przy użyciu YAML DSL.

Ale co, jeśli potrzebujesz bardziej złożonej logiki i testów? Czy YAML nie jest na to zbyt ograniczony? A co by było, gdybyś mógł tworzyć testy w pełnym języku programowania?

4. Miedź

Miedź V2 to platforma do sprawdzania manifestów przy użyciu niestandardowych testów (podobnie jak config-lint).

Różni się jednak od tego ostatniego tym, że nie używa YAML do opisu testów. Zamiast tego testy można pisać w JavaScript. Miedź udostępnia bibliotekę z kilkoma podstawowymi narzędziami, które pomogą Ci odczytać informacje o obiektach Kubernetes i zgłosić błędy.

Instrukcje instalacji miedzi można znaleźć w oficjalna dokumentacja.

Wersja 2.0.1 to najnowsza wersja tego narzędzia w momencie pisania oryginalnego artykułu.

Podobnie jak config-lint, Copper nie ma wbudowanych testów. Napiszmy jedno. Pozwól mu sprawdzić, czy wdrożenia wykorzystują obrazy kontenerów wyłącznie z zaufanych repozytoriów, takich jak my-company.com.

Utwórz plik check_image_repo.js o następującej treści:

$$.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)
            }
        });
    }
});

Teraz przetestuj nasz manifest base-valid.yaml, użyj polecenia 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
Validation failed

Oczywiste jest, że za pomocą miedzi można wykonać bardziej złożone testy - na przykład sprawdzenie nazw domen w manifestach Ingress lub odrzucenie podów działających w trybie uprzywilejowanym.

Miedź ma wbudowane różne funkcje użytkowe:

  • DockerImage odczytuje określony plik wejściowy i tworzy obiekt z następującymi atrybutami:
    • name - nazwa obrazu,
    • tag - znacznik obrazu,
    • registry - rejestracja obrazu,
    • registry_url - protokół (https://) i rejestracja obrazu,
    • fqin — pełna lokalizacja obrazu.
  • Funkcja findByName pomaga znaleźć zasób według danego typu (kind) i imię (name) z pliku wejściowego.
  • Funkcja findByLabels pomaga znaleźć zasób według określonego typu (kind) i etykiety (labels).

Możesz przeglądać wszystkie dostępne funkcje serwisowe tutaj.

Domyślnie ładuje cały wejściowy plik YAML do zmiennej $$ i udostępnia go do tworzenia skryptów (technika znana osobom z doświadczeniem jQuery).

Główna zaleta Coppera jest oczywista: nie musisz znać specjalistycznego języka i możesz korzystać z różnych funkcji JavaScript, aby tworzyć własne testy, takie jak interpolacja ciągów, funkcje itp.

Należy również zaznaczyć, że aktualna wersja Coppera współpracuje z wersją silnika JavaScript ES5, a nie ES6.

Szczegóły dostępne pod adresem oficjalna strona projektu.

Jeśli jednak nie przepadasz za JavaScriptem i wolisz język specjalnie zaprojektowany do tworzenia zapytań i opisywania polityk, powinieneś zwrócić uwagę na kontrowersje.

5.Konkurs

Conftest to framework do testowania danych konfiguracyjnych. Nadaje się również do testowania/weryfikacji manifestów Kubernetes. Testy są opisywane przy użyciu specjalistycznego języka zapytań Rego.

Możesz zainstalować konkurs za pomocą instrukcjewymienione na stronie internetowej projektu.

W momencie pisania oryginalnego artykułu najnowsza dostępna wersja to 0.18.2.

Podobnie jak config-lint i copper, conftest nie zawiera żadnych wbudowanych testów. Wypróbujmy to i napiszmy własną politykę. Podobnie jak w poprzednich przykładach sprawdzimy, czy obrazy kontenerów pochodzą z wiarygodnego źródła.

Utwórz katalog conftest-checks, a w nim znajduje się plik o nazwie check_image_registry.rego o następującej treści:

package main

deny[msg] {

  input.kind == "Deployment"
  image := input.spec.template.spec.containers[_].image
  not startswith(image, "my-company.com/")
  msg := sprintf("image '%v' doesn't come from my-company.com repository", [image])
}

Teraz przetestujmy base-valid.yaml przez conftest:

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

FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
1 tests, 1 passed, 0 warnings, 1 failure

Test, jak można było przewidzieć, nie powiódł się, ponieważ obrazy pochodziły z niezaufanego źródła.

W pliku Rego definiujemy blok deny. Jej prawdziwość uważana jest za naruszenie. Jeśli bloki deny kilka, kontest sprawdza je niezależnie od siebie, a prawdziwość któregokolwiek z bloków traktowana jest jako naruszenie.

Oprócz domyślnych danych wyjściowych conftest obsługuje format JSON, TAP i tabelę — niezwykle przydatna funkcja, jeśli chcesz osadzić raporty w istniejącym potoku CI. Możesz ustawić żądany format za pomocą flagi --output.

Aby ułatwić debugowanie zasad, konflikt ma flagę --trace. Wyświetla ślad, w jaki sposób Conftest analizuje określone pliki zasad.

Zasady konkursów można publikować i udostępniać w rejestrach OCI (Open Container Initiative) jako artefakty.

Polecenia push и pull umożliwiają publikację artefaktu lub pobranie istniejącego artefaktu ze zdalnego rejestru. Spróbujmy opublikować utworzoną przez siebie politykę w lokalnym rejestrze Dockera za pomocą conftest push.

Uruchom lokalny rejestr Dockera:

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

W innym terminalu przejdź do utworzonego wcześniej katalogu conftest-checks i uruchom następujące polecenie:

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

Jeśli polecenie się powiodło, zobaczysz następujący komunikat:

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

Teraz utwórz katalog tymczasowy i uruchom w nim polecenie conftest pull. Pobierze pakiet utworzony za pomocą poprzedniego polecenia:

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

W katalogu tymczasowym pojawi się podkatalog policyzawierający nasz plik zasad:

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

Testy można uruchomić bezpośrednio z repozytorium:

$ conftest test --update 127.0.0.1:5000/amitsaha/opa-bundle-example:latest base-valid.yaml
..
FAIL - base-valid.yaml - image 'hashicorp/http-echo' doesn't come from my-company.com repository
2 tests, 1 passed, 0 warnings, 1 failure

Niestety DockerHub nie jest jeszcze obsługiwany. Więc uważaj się za szczęściarza, jeśli używasz Rejestr kontenerów platformy Azure (ACR) lub własny rejestr.

Format artefaktu jest taki sam jak Otwórz pakiety agenta zasad (OPA), co pozwala na wykorzystanie konkursu do uruchamiania testów z istniejących pakietów OPA.

Więcej informacji na temat udostępniania zasad i innych funkcji konfiskaty można znaleźć na stronie oficjalna strona projektu.

6. Polaris

Ostatnim narzędziem, które zostanie omówione w tym artykule, jest Polaris. (Jego zeszłoroczne ogłoszenie we już przetłumaczone - około. tłumaczenie)

Polaris można zainstalować w klastrze lub używać w trybie wiersza poleceń. Jak można się domyślić, pozwala na statyczną analizę manifestów Kubernetesa.

Podczas pracy w trybie wiersza poleceń dostępne są wbudowane testy obejmujące takie obszary, jak bezpieczeństwo i najlepsze praktyki (podobnie jak kube-score). Dodatkowo możesz tworzyć własne testy (jak w config-lint, copper i conftest).

Innymi słowy, Polaris łączy zalety obu kategorii narzędzi: z testami wbudowanymi i niestandardowymi.

Aby zainstalować Polaris w trybie wiersza poleceń, użyj instrukcje na stronie projektu.

W chwili pisania oryginalnego artykułu dostępna była wersja 1.0.3.

Po zakończeniu instalacji możesz uruchomić Polaris w manifeście base-valid.yaml za pomocą następującego polecenia:

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

Wygeneruje ciąg znaków w formacie JSON ze szczegółowym opisem przeprowadzonych testów i ich wyników. Dane wyjściowe będą miały następującą strukturę:

{
  "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": [
    /* длинный список */
  ]
}

Dostępna pełna moc wyjściowa tutaj.

Podobnie jak kube-score, Polaris identyfikuje problemy w obszarach, w których manifest nie spełnia najlepszych praktyk:

  • Nie ma żadnych kontroli stanu strąków.
  • Tagi dla obrazów kontenerów nie są określone.
  • Kontener działa jako root.
  • Żądania i limity dotyczące pamięci i procesora nie są określone.

Każdemu testowi, w zależności od jego wyników, przypisywany jest stopień krytyczności: ostrzeżenie lub niebezpieczeństwo. Więcej informacji na temat dostępnych testów wbudowanych znajdziesz w artykule dokumentacja.

Jeśli szczegóły nie są potrzebne, możesz określić flagę --format score. W tym przypadku Polaris wyświetli liczbę z zakresu od 1 do 100 − wynik (tj. ocena):

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

Im wynik jest bliższy 100, tym wyższy stopień zgodności. Jeśli sprawdzisz kod zakończenia polecenia polaris audit, okazuje się, że jest ono równe 0.

siła polaris audit Możesz zakończyć pracę z niezerowym kodem za pomocą dwóch flag:

  • Flaga --set-exit-code-below-score przyjmuje jako argument wartość progową z zakresu 1-100. W takim przypadku polecenie zakończy się z kodem wyjścia 4, jeśli wynik będzie poniżej progu. Jest to bardzo przydatne, gdy masz określoną wartość progową (powiedzmy 75) i musisz otrzymać powiadomienie, jeśli wynik spadnie poniżej.
  • Flaga --set-exit-code-on-danger spowoduje niepowodzenie polecenia z kodem 3, jeśli jeden z testów zagrożeń zakończy się niepowodzeniem.

Spróbujmy teraz utworzyć niestandardowy test, który sprawdzi, czy obraz pochodzi z zaufanego repozytorium. Testy niestandardowe są określone w formacie YAML, a sam test jest opisany przy użyciu schematu JSON.

Poniższy fragment kodu YAML opisuje nowy test o nazwie checkImageRepo:

checkImageRepo:
  successMessage: Image registry is valid
  failureMessage: Image registry is not valid
  category: Images
  target: Container
  schema:
    '$schema': http://json-schema.org/draft-07/schema
    type: object
    properties:
      image:
        type: string
        pattern: ^my-company.com/.+$

Przyjrzyjmy się temu bliżej:

  • successMessage — ta linia zostanie wydrukowana, jeśli test zakończy się pomyślnie;
  • failureMessage — komunikat ten zostanie wyświetlony w przypadku awarii;
  • category — wskazuje jedną z kategorii: Images, Health Checks, Security, Networking и Resources;
  • target--- określa typ obiektu (spec) zastosowano test. Możliwa wartość: Container, Pod lub Controller;
  • Sam test jest określony w obiekcie schema przy użyciu schematu JSON. Kluczowym słowem w tym teście jest pattern służy do porównywania źródła obrazu z wymaganym.

Aby uruchomić powyższy test należy utworzyć następującą konfigurację Polarisa:

checks:
  checkImageRepo: danger
customChecks:
  checkImageRepo:
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(polaris-conf.yaml)

Przeanalizujmy plik:

  • W polu checks wymagane są testy i ich poziom krytyczności. Ponieważ pożądane jest otrzymywanie ostrzeżenia, gdy zdjęcie jest pobierane z niezaufanego źródła, ustawiamy tutaj poziom danger.
  • Sam test checkImageRepo następnie zarejestrowany w obiekcie customChecks.

Zapisz plik jako custom_check.yaml. Teraz możesz biegać polaris audit z manifestem YAML wymagającym weryfikacji.

Przetestujmy nasz manifest base-valid.yaml:

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

Zespół polaris audit uruchomił tylko test użytkownika określony powyżej i zakończył się niepowodzeniem.

Jeśli naprawisz obraz my-company.com/http-echo:1.0, Polaris zakończy się pomyślnie. Manifest zmian już jest repozytoriaabyś mógł sprawdzić poprzednie polecenie w manifeście image-valid-mycompany.yaml.

Teraz pojawia się pytanie: jak uruchomić testy wbudowane razem z niestandardowymi? Łatwo! Wystarczy dodać wbudowane identyfikatory testów do pliku konfiguracyjnego. W rezultacie przybierze następującą postać:

checks:
  cpuRequestsMissing: warning
  cpuLimitsMissing: warning
  # Other inbuilt checks..
  # ..
  # custom checks
  checkImageRepo: danger # !!!
customChecks:
  checkImageRepo:        # !!!
    successMessage: Image registry is valid
    failureMessage: Image registry is not valid
    category: Images
    target: Container
    schema:
      '$schema': http://json-schema.org/draft-07/schema
      type: object
      properties:
        image:
          type: string
          pattern: ^my-company.com/.+$

(config_with_custom_check.yaml)

Dostępny jest przykład kompletnego pliku konfiguracyjnego tutaj.

Sprawdź manifest base-valid.yamlkorzystając z testów wbudowanych i niestandardowych, możesz użyć polecenia:

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

Polaris uzupełnia wbudowane testy niestandardowymi, łącząc w ten sposób to, co najlepsze z obu światów.

Z drugiej strony brak możliwości wykorzystania potężniejszych języków takich jak Rego czy JavaScript może być czynnikiem ograniczającym uniemożliwiającym tworzenie bardziej wyrafinowanych testów.

Więcej informacji o Polarisie można znaleźć na stronie: strona projektu.

Streszczenie

Chociaż dostępnych jest wiele narzędzi do sprawdzania i oceniania plików Kubernetes YAML, ważne jest, aby dobrze zrozumieć, w jaki sposób testy zostaną zaprojektowane i wykonane.

Naprzykład jeśli weźmiesz manifesty Kubernetesa przechodzące przez potok, kubeval może być pierwszym krokiem w takim potoku. Monitoruje, czy definicje obiektów są zgodne ze schematem Kubernetes API.

Po zakończeniu takiego przeglądu można przystąpić do bardziej wyrafinowanych testów, takich jak zgodność ze standardowymi najlepszymi praktykami i określonymi politykami. Tutaj przydadzą się kube-score i Polaris.

Dla tych, którzy mają złożone wymagania i chcą szczegółowo dostosować testy, odpowiednie będą narzędzia copper, config-lint i conftest.

Conftest i config-lint używają YAML do definiowania niestandardowych testów, a Copper zapewnia dostęp do pełnego języka programowania, co czyni go całkiem atrakcyjnym wyborem.

Z drugiej strony, czy warto skorzystać z jednego z tych narzędzi i w związku z tym tworzyć wszystkie testy ręcznie, czy też wolić Polarisa i dodawać tylko to, co jest do niego potrzebne? Na to pytanie nie ma jasnej odpowiedzi.

Poniższa tabela zawiera krótki opis każdego narzędzia:

Narzędzie
Cel
Ograniczenia
Testy użytkowników

kubeval
Sprawdza poprawność manifestów YAML pod kątem określonej wersji schematu API
Nie mogę pracować z CRD
Nie

wynik kube
Analizuje manifesty YAML pod kątem najlepszych praktyk
Nie można wybrać wersji API Kubernetes, aby sprawdzić zasoby
Nie

miedź
Ogólna struktura tworzenia niestandardowych testów JavaScript dla manifestów YAML
Brak wbudowanych testów. Słaba dokumentacja
Tak

config-lint
Ogólny framework do tworzenia testów w języku specyficznym dla domeny osadzony w YAML. Obsługuje różne formaty konfiguracji (np. Terraform)
Nie ma gotowych testów. Wbudowane asercje i funkcje mogą nie wystarczyć
Tak

konkurs
Framework do tworzenia własnych testów z wykorzystaniem Rego (specjalistycznego języka zapytań). Umożliwia udostępnianie polityk poprzez pakiety OCI
Brak wbudowanych testów. Muszę się nauczyć Rego. Docker Hub nie jest obsługiwany podczas publikowania zasad
Tak

Polaris
Przegląda manifesty YAML pod kątem standardowych najlepszych praktyk. Umożliwia tworzenie własnych testów przy użyciu schematu JSON
Możliwości testowe oparte na schemacie JSON mogą nie być wystarczające
Tak

Ponieważ narzędzia te nie opierają się na dostępie do klastra Kubernetes, są łatwe w instalacji. Pozwalają filtrować pliki źródłowe i przekazują szybką informację zwrotną autorom pull requestów w projektach.

PS od tłumacza

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz