Valide o YAML do Kubernetes em relação às práticas e políticas recomendadas

Observação. trad.: Com o crescente número de configurações YAML para ambientes K8s, a necessidade de sua verificação automatizada torna-se cada vez mais urgente. O autor desta revisão não apenas selecionou soluções existentes para esta tarefa, mas também usou o Deployment como exemplo para ver como elas funcionam. Acabou sendo muito informativo para quem se interessa pelo assunto.

Valide o YAML do Kubernetes em relação às práticas e políticas recomendadas

TL, DR: este artigo compara seis ferramentas estáticas para validar e avaliar arquivos YAML do Kubernetes em relação às melhores práticas e requisitos.

As cargas de trabalho do Kubernetes normalmente são definidas na forma de documentos YAML. Um dos problemas do YAML é a dificuldade de especificar restrições ou relacionamentos entre arquivos de manifesto.

E se precisarmos garantir que todas as imagens implantadas no cluster venham de um registro confiável?

Como posso evitar que implantações que não possuem PodDisruptionBudgets sejam enviadas para o cluster?

A integração de testes estáticos permite identificar erros e violações de políticas na fase de desenvolvimento. Isto aumenta a garantia de que as definições de recursos estão corretas e seguras e aumenta a probabilidade de que as cargas de trabalho de produção sigam as melhores práticas.

O ecossistema de inspeção de arquivos YAML estático do Kubernetes pode ser dividido nas seguintes categorias:

  • Validadores de API. As ferramentas nesta categoria verificam o manifesto YAML em relação aos requisitos do servidor API Kubernetes.
  • Testadores prontos. As ferramentas desta categoria vêm com testes prontos de segurança, conformidade com as melhores práticas, etc.
  • Validadores personalizados. Representantes desta categoria permitem criar testes customizados em diversas linguagens, por exemplo, Rego e Javascript.

Neste artigo iremos descrever e comparar seis ferramentas diferentes:

  1. kubeval;
  2. pontuação kube;
  3. config-lint;
  4. cobre;
  5. concurso;
  6. Polaris.

Bem, vamos começar!

Verificando implantações

Antes de começarmos a comparar ferramentas, vamos criar alguns antecedentes para testá-las.

O manifesto abaixo contém uma série de erros e não conformidades com as melhores práticas: quantos deles você consegue encontrar?

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)

Usaremos este YAML para comparar diferentes ferramentas.

O manifesto acima base-valid.yaml e outros manifestos deste artigo podem ser encontrados em Repositórios Git.

O manifesto descreve uma aplicação web cuja tarefa principal é responder com uma mensagem “Hello World” para a porta 5678. Ela pode ser implantada com o seguinte comando:

kubectl apply -f hello-world.yaml

E então - verifique o trabalho:

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

Agora vá para http://localhost:8080 e confirme se o aplicativo está funcionando. Mas segue as melhores práticas? Vamos checar.

1. Kubeval

No coração kubeval A ideia é que qualquer interação com o Kubernetes ocorra através de sua API REST. Em outras palavras, você pode usar um esquema de API para verificar se um determinado YAML está em conformidade com ele. Vejamos um exemplo.

instruções de instalação kubeval estão disponíveis no site do projeto.

No momento da redação do artigo original, a versão 0.15.0 estava disponível.

Depois de instalado, vamos alimentá-lo com o manifesto acima:

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

Se for bem-sucedido, o kubeval sairá com o código de saída 0. Você pode verificar da seguinte maneira:

$ echo $?
0

Vamos agora tentar o kubeval com um manifesto diferente:

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)

Você consegue identificar o problema a olho nu? Vamos lançar:

$ 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

O recurso não está sendo verificado.

Implantações usando a versão API apps/v1, deve incluir um seletor que corresponda ao rótulo do pod. O manifesto acima não inclui o seletor, então kubeval relatou um erro e saiu com um código diferente de zero.

Eu me pergunto o que acontecerá se eu fizer isso kubectl apply -f com este manifesto?

Bem, vamos tentar:

$ 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

Este é exatamente o erro sobre o qual kubeval alertou. Você pode corrigir isso adicionando um seletor:

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)

A vantagem de ferramentas como o kubeval é que erros como esses podem ser detectados no início do ciclo de implantação.

Além disso, essas verificações não exigem acesso ao cluster; elas podem ser realizadas offline.

Por padrão, o kubeval verifica os recursos em relação ao esquema mais recente da API do Kubernetes. No entanto, na maioria dos casos, pode ser necessário verificar uma versão específica do Kubernetes. Isso pode ser feito usando a bandeira --kubernetes-version:

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

Observe que a versão deve ser especificada no formato Major.Minor.Patch.

Para obter uma lista de versões para as quais a verificação é suportada, consulte Esquema JSON no GitHub, que kubeval usa para validação. Se você precisar executar o kubeval offline, baixe os esquemas e especifique sua localização local usando o sinalizador --schema-location.

Além de arquivos YAML individuais, o kubeval também pode trabalhar com diretórios e stdin.

Além disso, o Kubeval integra-se facilmente ao pipeline de CI. Aqueles que desejam executar testes antes de enviar manifestos ao cluster ficarão satisfeitos em saber que o kubeval oferece suporte a três formatos de saída:

  1. Texto simples;
  2. JSON;
  3. Protocolo Teste Qualquer Coisa (TAP).

E qualquer um dos formatos pode ser usado para análise posterior da saída para gerar um resumo dos resultados do tipo desejado.

Uma das desvantagens do kubeval é que atualmente ele não pode verificar a conformidade com as Definições de Recursos Personalizados (CRDs). No entanto, é possível configurar o kubeval ignore-os.

Kubeval é uma ótima ferramenta para verificar e avaliar recursos; Porém, vale ressaltar que passar no teste não garante que o recurso esteja de acordo com as melhores práticas.

Por exemplo, usando a tag latest em um contêiner não segue as práticas recomendadas. No entanto, o kubeval não considera isso um erro e não o relata. Ou seja, a verificação desse YAML será concluída sem avisos.

Mas e se você quiser avaliar o YAML e identificar violações como a tag latest? Como posso verificar um arquivo YAML em relação às práticas recomendadas?

2. Pontuação Kube

Pontuação Kube analisa manifestos YAML e os avalia em relação a testes integrados. Esses testes são selecionados com base em diretrizes de segurança e práticas recomendadas, como:

  • Executando o contêiner não como root.
  • Disponibilidade de verificações de integridade do pod.
  • Definir solicitações e limites de recursos.

Com base nos resultados do teste, três resultados são fornecidos: OK, ATENÇÃO и CRÍTICA.

Você pode experimentar o Kube-score online ou instalá-lo localmente.

No momento em que este artigo foi escrito, a versão mais recente do kube-score era 1.7.0.

Vamos experimentar em nosso manifesto 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 passa nos testes kubeval, enquanto kube-score aponta para as seguintes falhas:

  • As verificações de prontidão não estão configuradas.
  • Não há solicitações ou limites de recursos de CPU e memória.
  • Os orçamentos de interrupção de pod não são especificados.
  • Não existem regras de separação (anti-afinidade) para maximizar a disponibilidade.
  • O contêiner é executado como root.

Todos estes são pontos válidos sobre deficiências que precisam ser abordadas para tornar a implantação mais eficiente e confiável.

Equipe kube-score exibe informações em formato legível, incluindo todas as violações de tipo ATENÇÃO и CRÍTICA, o que ajuda muito durante o desenvolvimento.

Aqueles que desejam usar esta ferramenta dentro do pipeline de CI podem habilitar uma saída mais compactada usando o sinalizador --output-format ci (neste caso, os testes com o resultado também são exibidos 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

Semelhante ao kubeval, o kube-score retorna um código de saída diferente de zero quando há um teste que falha CRÍTICA. Você também pode ativar processamento semelhante para ATENÇÃO.

Além disso, é possível verificar a conformidade dos recursos com diferentes versões da API (como no kubeval). No entanto, essas informações estão codificadas na própria pontuação do kube: você não pode selecionar uma versão diferente do Kubernetes. Essa limitação pode ser um grande problema se você pretende atualizar seu cluster ou se tiver vários clusters com versões diferentes de K8s.

Note-se que já existe um problema com uma proposta para concretizar esta oportunidade.

Mais informações sobre pontuação kube podem ser encontradas em o site oficial.

Os testes de pontuação Kube são uma ótima ferramenta para implementar práticas recomendadas, mas e se você precisar fazer alterações no teste ou adicionar suas próprias regras? Infelizmente, isso não pode ser feito.

A pontuação do Kube não é extensível: você não pode adicionar políticas ou ajustá-las.

Se precisar escrever testes personalizados para verificar a conformidade com as políticas da empresa, você pode usar uma das quatro ferramentas a seguir: config-lint, cobre, conftest ou polaris.

3.Config-lint

Config-lint é uma ferramenta para validar arquivos de configuração YAML, JSON, Terraform, CSV e manifestos do Kubernetes.

Você pode instalá-lo usando instruções no site do projeto.

A versão atual no momento da redação do artigo original é 1.5.0.

O Config-lint não possui testes integrados para validar manifestos do Kubernetes.

Para realizar qualquer teste, você precisa criar regras apropriadas. Eles são escritos em arquivos YAML chamados "conjuntos de regras" (conjuntos de regras), e tem a seguinte estrutura:

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

(rule.yaml)

Vamos estudá-lo mais de perto:

  • Campo type especifica que tipo de configuração o config-lint usará. Para manifestos K8s, isso é sempre Kubernetes.
  • No files Além dos próprios arquivos, você pode especificar um diretório.
  • Campo rules destinado à configuração de testes de usuário.

Digamos que você queira ter certeza de que as imagens no Deployment sejam sempre baixadas de um repositório confiável como my-company.com/myapp:1.0. Uma regra config-lint que realiza essa verificação seria semelhante a esta:

- 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)

Cada regra deve ter os seguintes atributos:

  • id — identificador único da regra;
  • severity - Talvez FALHA, ATENÇÃO и NÃO_COMPLIANT;
  • message — se uma regra for violada, o conteúdo desta linha será exibido;
  • resource — o tipo de recurso ao qual esta regra se aplica;
  • assertions — uma lista de condições que serão avaliadas em relação a este recurso.

Na regra acima assertion intitulado every verifica se todos os contêineres estão em implantação (key: spec.templates.spec.containers) use imagens confiáveis ​​(ou seja, começando com my-company.com/).

O conjunto de regras completo é assim:

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)

Para testar o teste, vamos salvá-lo como check_image_repo.yaml. Vamos verificar o arquivo 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"
  }
]

A verificação falhou. Agora vamos verificar o seguinte manifesto com o repositório de imagens correto:

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)

Executamos o mesmo teste com o manifesto acima. Não foram encontrados problemas:

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

Config-lint é uma estrutura promissora que permite criar seus próprios testes para validar manifestos YAML do Kubernetes usando o YAML DSL.

Mas e se você precisar de lógica e testes mais complexos? O YAML não é muito limitado para isso? E se você pudesse criar testes em uma linguagem de programação completa?

4. Cobre

Cobre V2 é uma estrutura para validar manifestos usando testes personalizados (semelhante ao config-lint).

No entanto, difere deste último por não usar YAML para descrever testes. Os testes podem ser escritos em JavaScript. Copper fornece uma biblioteca com várias ferramentas básicas, que ajuda você a ler informações sobre objetos do Kubernetes e relatar erros.

As etapas para instalação do Copper podem ser encontradas em documentação oficial.

2.0.1 é a versão mais recente deste utilitário no momento da redação do artigo original.

Assim como o config-lint, o Copper não possui testes integrados. Vamos escrever um. Deixe verificar se as implantações usam imagens de contêiner exclusivamente de repositórios confiáveis, como my-company.com.

Crie um arquivo check_image_repo.js com o seguinte conteúdo:

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

Agora, para testar nosso manifesto base-valid.yaml, use o 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
Validation failed

É claro que com a ajuda do cobre você pode realizar testes mais complexos - por exemplo, verificar nomes de domínio em manifestos do Ingress ou rejeitar pods executados em modo privilegiado.

O cobre possui várias funções utilitárias incorporadas:

  • DockerImage lê o arquivo de entrada especificado e cria um objeto com os seguintes atributos:
    • name - nome da imagem,
    • tag - etiqueta de imagem,
    • registry - registro de imagem,
    • registry_url - protocolo (https://) e registro de imagens,
    • fqin — localização completa da imagem.
  • Função findByName ajuda a encontrar um recurso por um determinado tipo (kind) e nome (name) do arquivo de entrada.
  • Função findByLabels ajuda a encontrar um recurso por um tipo especificado (kind) e rótulos (labels).

Você pode visualizar todas as funções de serviço disponíveis aqui.

Por padrão, ele carrega todo o arquivo YAML de entrada em uma variável $$ e o disponibiliza para scripts (uma técnica familiar para quem tem experiência em jQuery).

A principal vantagem do Copper é óbvia: você não precisa dominar uma linguagem especializada e pode usar vários recursos do JavaScript para criar seus próprios testes, como interpolação de strings, funções, etc.

Deve-se notar também que a versão atual do Copper funciona com a versão ES5 do mecanismo JavaScript, não com ES6.

Detalhes disponíveis em o site oficial do projeto.

No entanto, se você realmente não gosta de JavaScript e prefere uma linguagem projetada especificamente para criar consultas e descrever políticas, preste atenção ao conftest.

5.Concurso

Contest é uma estrutura para testar dados de configuração. Também adequado para testar/verificar manifestos do Kubernetes. Os testes são descritos usando uma linguagem de consulta especializada Rego.

Você pode instalar o conftest usando instruçõeslistado no site do projeto.

No momento da redação do artigo original, a versão mais recente disponível era 0.18.2.

Semelhante ao config-lint e ao cobre, o conftest vem sem nenhum teste integrado. Vamos experimentar e escrever nossa própria política. Como nos exemplos anteriores, verificaremos se as imagens do contêiner são obtidas de uma fonte confiável.

Crie um diretório conftest-checks, e nele há um arquivo chamado check_image_registry.rego com o seguinte conteúdo:

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])
}

Agora vamos testar base-valid.yaml através 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

O teste falhou previsivelmente porque as imagens vieram de uma fonte não confiável.

No arquivo Rego definimos o bloco deny. A sua verdade é considerada uma violação. Se bloquear deny vários, o conftest os verifica independentemente um do outro, e a veracidade de qualquer um dos blocos é tratada como uma violação.

Além da saída padrão, o conftest suporta JSON, TAP e formato de tabela - um recurso extremamente útil se você precisar incorporar relatórios em um pipeline de CI existente. Você pode definir o formato desejado usando o sinalizador --output.

Para facilitar a depuração de políticas, o conftest possui um sinalizador --trace. Ele gera um rastreamento de como o conftest analisa os arquivos de política especificados.

As políticas do concurso podem ser publicadas e compartilhadas nos registros OCI (Open Container Initiative) como artefatos.

Equipes push и pull permitem publicar um artefato ou recuperar um artefato existente de um registro remoto. Vamos tentar publicar a política que criamos no registro local do Docker usando conftest push.

Inicie seu registro Docker local:

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

Em outro terminal, vá para o diretório que você criou anteriormente conftest-checks e execute o seguinte comando:

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

Se o comando foi bem-sucedido, você verá uma mensagem como esta:

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

Agora crie um diretório temporário e execute o comando nele conftest pull. Ele fará o download do pacote criado pelo comando anterior:

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

Um subdiretório aparecerá no diretório temporário policycontendo nosso arquivo de política:

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

Os testes podem ser executados diretamente do repositório:

$ 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

Infelizmente, o DockerHub ainda não é compatível. Então considere-se com sorte se usar Registro de Contêiner do Azure (ACR) ou seu próprio registro.

O formato do artefato é o mesmo que Pacotes de agente de política aberta (OPA), que permite usar conftest para executar testes de pacotes OPA existentes.

Você pode aprender mais sobre o compartilhamento de políticas e outros recursos do conftest em o site oficial do projeto.

6. Polaris

A última ferramenta que será discutida neste artigo é Polaris. (Seu anúncio do ano passado nós já traduzido - Aproximadamente. tradução)

Polaris pode ser instalado em um cluster ou usado no modo de linha de comando. Como você deve ter adivinhado, ele permite analisar estaticamente os manifestos do Kubernetes.

Ao executar no modo de linha de comando, testes integrados estão disponíveis cobrindo áreas como segurança e práticas recomendadas (semelhante ao kube-score). Além disso, você pode criar seus próprios testes (como em config-lint, cobre e conftest).

Em outras palavras, o Polaris combina os benefícios de ambas as categorias de ferramentas: com testes integrados e personalizados.

Para instalar o Polaris no modo de linha de comando, use instruções no site do projeto.

No momento da redação do artigo original, a versão 1.0.3 está disponível.

Assim que a instalação for concluída, você pode executar o polaris no manifesto base-valid.yaml com o seguinte comando:

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

Irá gerar uma string no formato JSON com uma descrição detalhada dos testes realizados e seus resultados. A saída terá a seguinte estrutura:

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

Saída completa disponível aqui.

Assim como o kube-score, o Polaris identifica problemas em áreas onde o manifesto não atende às práticas recomendadas:

  • Não há verificações de integridade para pods.
  • As tags para imagens de contêiner não são especificadas.
  • O contêiner é executado como root.
  • Solicitações e limites de memória e CPU não são especificados.

Cada teste, dependendo de seus resultados, recebe um grau de criticidade: aviso ou perigo. Para saber mais sobre os testes integrados disponíveis, consulte documentação.

Se os detalhes não forem necessários, você poderá especificar o sinalizador --format score. Neste caso, Polaris produzirá um número que varia de 1 a 100 - Ponto (ou seja, avaliação):

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

Quanto mais próxima a pontuação estiver de 100, maior será o grau de concordância. Se você verificar o código de saída do comando polaris audit, acontece que é igual a 0.

Fazer polaris audit Você pode encerrar o trabalho com código diferente de zero usando dois sinalizadores:

  • Bandeira --set-exit-code-below-score toma como argumento um valor limite no intervalo de 1 a 100. Nesse caso, o comando sairá com o código de saída 4 se a pontuação estiver abaixo do limite. Isso é muito útil quando você tem um determinado valor limite (digamos 75) e precisa receber um alerta se a pontuação cair abaixo.
  • Bandeira --set-exit-code-on-danger fará com que o comando falhe com o código 3 se um dos testes de perigo falhar.

Agora vamos tentar criar um teste personalizado que verifique se a imagem foi obtida de um repositório confiável. Os testes personalizados são especificados no formato YAML e o teste em si é descrito usando o esquema JSON.

O seguinte trecho de código YAML descreve um novo teste chamado 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/.+$

Vamos dar uma olhada mais de perto:

  • successMessage — esta linha será impressa se o teste for concluído com sucesso;
  • failureMessage — esta mensagem será mostrada em caso de falha;
  • category — indica uma das categorias: Images, Health Checks, Security, Networking и Resources;
  • target--- determina que tipo de objeto (spec) o teste é aplicado. Valores possíveis: Container, Pod ou Controller;
  • O teste em si é especificado no objeto schema usando o esquema JSON. A palavra-chave neste teste é pattern usado para comparar a fonte da imagem com a necessária.

Para executar o teste acima, você precisa criar a seguinte configuração Polaris:

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)

Vamos analisar o arquivo:

  • No checks testes e seu nível de criticidade são prescritos. Como é desejável receber um aviso quando uma imagem for obtida de uma fonte não confiável, definimos o nível aqui danger.
  • O teste em si checkImageRepo então registrado no objeto customChecks.

Salve o arquivo como custom_check.yaml. Agora você pode correr polaris audit com um manifesto YAML que requer verificação.

Vamos testar nosso manifesto base-valid.yaml:

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

Equipe polaris audit executou apenas o teste do usuário especificado acima e falhou.

Se você corrigir a imagem para my-company.com/http-echo:1.0, o Polaris será concluído com sucesso. O manifesto com as mudanças já está em repositóriospara que você possa verificar o comando anterior no manifesto image-valid-mycompany.yaml.

Agora surge a pergunta: como executar testes integrados junto com testes personalizados? Facilmente! Você só precisa adicionar os identificadores de teste integrados ao arquivo de configuração. Como resultado, assumirá o seguinte formato:

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)

Um exemplo de um arquivo de configuração completo está disponível aqui.

Verifique o manifesto base-valid.yamlusando testes integrados e personalizados, você pode usar o comando:

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

Polaris complementa os testes integrados com testes personalizados, combinando assim o melhor dos dois mundos.

Por outro lado, a impossibilidade de utilizar linguagens mais poderosas como Rego ou JavaScript pode ser um fator limitante que impede a criação de testes mais sofisticados.

Mais informações sobre Polaris estão disponíveis em site do projeto.

Resumo

Embora existam muitas ferramentas disponíveis para inspecionar e avaliar arquivos YAML do Kubernetes, é importante ter uma compreensão clara de como os testes serão projetados e executados.

Por exemplo, se você usar os manifestos do Kubernetes em um pipeline, o kubeval poderá ser a primeira etapa desse pipeline. Ele monitoraria se as definições de objeto estão em conformidade com o esquema da API Kubernetes.

Uma vez concluída essa revisão, pode-se passar para testes mais sofisticados, como a conformidade com as melhores práticas padrão e políticas específicas. É aqui que o kube-score e o Polaris seriam úteis.

Para quem tem requisitos complexos e precisa personalizar os testes detalhadamente, cobre, config-lint e conftest seriam adequados.

Conftest e config-lint usam YAML para definir testes personalizados, e o cobre dá acesso a uma linguagem de programação completa, tornando-o uma escolha bastante atraente.

Por outro lado, vale a pena usar uma dessas ferramentas e, portanto, criar todos os testes manualmente, ou preferir o Polaris e adicionar apenas o necessário? Não há uma resposta clara para esta pergunta.

A tabela abaixo fornece uma breve descrição de cada ferramenta:

Ferramenta
Propósito
Contras:
Testes de usuário

kubeval
Valida manifestos YAML em relação a uma versão específica do esquema da API
Não consigo trabalhar com CRD
Não

pontuação kube
Analisa manifestos YAML em relação às práticas recomendadas
Não é possível selecionar a versão da API do Kubernetes para verificar os recursos
Não

cobre
Uma estrutura geral para criar testes JavaScript personalizados para manifestos YAML
Sem testes integrados. Documentação deficiente
Sim

config-lint
Uma estrutura geral para criar testes em uma linguagem específica de domínio incorporada em YAML. Suporta vários formatos de configuração (por exemplo, Terraform)
Não existem testes prontos. Asserções e funções integradas podem não ser suficientes
Sim

concurso
Uma estrutura para criar seus próprios testes usando Rego (uma linguagem de consulta especializada). Permite o compartilhamento de políticas por meio de pacotes OCI
Sem testes integrados. Tenho que aprender Rego. Docker Hub não é compatível ao publicar políticas
Sim

Polaris
Analisa os manifestos YAML em relação às práticas recomendadas padrão. Permite que você crie seus próprios testes usando JSON Schema
Os recursos de teste baseados no esquema JSON podem não ser suficientes
Sim

Como essas ferramentas não dependem de acesso ao cluster Kubernetes, elas são fáceis de instalar. Eles permitem filtrar arquivos de origem e fornecer feedback rápido aos autores de solicitações pull em projetos.

PS do tradutor

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário