Validar Kubernetes YAML frente a las mejores prácticas y políticas

Nota. traducir: Con el creciente número de configuraciones YAML para entornos K8, la necesidad de su verificación automatizada se vuelve cada vez más urgente. El autor de esta revisión no solo seleccionó las soluciones existentes para esta tarea, sino que también utilizó la implementación como ejemplo para ver cómo funcionan. Resultó muy informativo para quienes estén interesados ​​en este tema.

Validar Kubernetes YAML frente a las mejores prácticas y políticas

TL; DR: Este artículo compara seis herramientas estáticas para validar y evaluar archivos YAML de Kubernetes con respecto a las mejores prácticas y requisitos.

Las cargas de trabajo de Kubernetes normalmente se definen en forma de documentos YAML. Uno de los problemas de YAML es la dificultad de especificar restricciones o relaciones entre archivos de manifiesto.

¿Qué sucede si necesitamos asegurarnos de que todas las imágenes implementadas en el clúster provengan de un registro confiable?

¿Cómo puedo evitar que se envíen al clúster implementaciones que no tienen PodDisruptionBudgets?

La integración de pruebas estáticas le permite identificar errores y violaciones de políticas en la etapa de desarrollo. Esto aumenta la garantía de que las definiciones de recursos sean correctas y seguras, y aumenta la probabilidad de que las cargas de trabajo de producción sigan las mejores prácticas.

El ecosistema de inspección de archivos YAML estático de Kubernetes se puede dividir en las siguientes categorías:

  • validadores de API. Las herramientas de esta categoría verifican el manifiesto YAML con los requisitos del servidor API de Kubernetes.
  • Probadores listos. Las herramientas de esta categoría vienen con pruebas listas para usar de seguridad, cumplimiento de las mejores prácticas, etc.
  • Validadores personalizados. Los representantes de esta categoría le permiten crear pruebas personalizadas en varios idiomas, por ejemplo, Rego y Javascript.

En este artículo describiremos y compararemos seis herramientas diferentes:

  1. kubeval;
  2. puntuación kube;
  3. configuración-lint;
  4. cobre;
  5. concurso;
  6. Estrella polar.

Bueno, ¡comencemos!

Comprobación de implementaciones

Antes de comenzar a comparar herramientas, creemos algunos antecedentes para probarlas.

El siguiente manifiesto contiene una serie de errores y de incumplimiento de las mejores prácticas: ¿cuántos de ellos puedes 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 herramientas.

El manifiesto anterior base-valid.yaml y otros manifiestos de este artículo se pueden encontrar en repositorios git.

El manifiesto describe una aplicación web cuya tarea principal es responder con un mensaje "Hola mundo" al puerto 5678. Se puede implementar con el siguiente comando:

kubectl apply -f hello-world.yaml

Y así, revisa el trabajo:

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

Ahora ve a http://localhost:8080 y confirme que la aplicación está funcionando. ¿Pero sigue las mejores prácticas? Vamos a revisar.

1. Kubeval

En el corazón kubeval La idea es que cualquier interacción con Kubernetes se produzca a través de su API REST. En otras palabras, puede utilizar un esquema API para comprobar si un YAML determinado se ajusta a él. Veamos un ejemplo.

Instrucciones de instalación kubeval están disponibles en el sitio web del proyecto.

En el momento de escribir el artículo original, la versión 0.15.0 estaba disponible.

Una vez instalado, alimentémoslo con el manifiesto anterior:

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

Si tiene éxito, kubeval saldrá con el código de salida 0. Puede verificarlo de la siguiente manera:

$ echo $?
0

Probemos ahora kubeval con un manifiesto 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)

¿Puedes detectar el problema a simple vista? Lanzamos:

$ 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

El recurso no está siendo verificado.

Implementaciones utilizando la versión API apps/v1, debe incluir un selector que coincida con la etiqueta del pod. El manifiesto anterior no incluye el selector, por lo que kubeval informó un error y salió con un código distinto de cero.

Me pregunto qué pasará si lo hago kubectl apply -f con este manifiesto?

Bueno, probemos:

$ 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 es exactamente el error sobre el que advirtió kubeval. Puedes solucionarlo agregando un selector:

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)

La ventaja de herramientas como kubeval es que errores como estos pueden detectarse en las primeras etapas del ciclo de implementación.

Además, estas comprobaciones no requieren acceso al clúster; se pueden realizar sin conexión.

De forma predeterminada, kubeval compara los recursos con el esquema de API de Kubernetes más reciente. Sin embargo, en la mayoría de los casos, es posible que deba comparar con una versión específica de Kubernetes. Esto se puede hacer usando la bandera. --kubernetes-version:

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

Tenga en cuenta que la versión debe especificarse en el formato Major.Minor.Patch.

Para obtener una lista de versiones para las que se admite la verificación, consulte Esquema JSON en GitHub, que kubeval utiliza para la validación. Si necesita ejecutar kubeval sin conexión, descargue los esquemas y especifique su ubicación local usando la bandera --schema-location.

Además de los archivos YAML individuales, kubeval también puede trabajar con directorios y stdin.

Además, Kubeval se integra fácilmente en el proceso de CI. Aquellos que deseen ejecutar pruebas antes de enviar manifiestos al clúster estarán encantados de saber que kubeval admite tres formatos de salida:

  1. Texto sin formato;
  2. JSON;
  3. Protocolo de prueba de cualquier cosa (TAP).

Y cualquiera de los formatos se puede utilizar para un mayor análisis de la salida y generar un resumen de los resultados del tipo deseado.

Uno de los inconvenientes de kubeval es que actualmente no puede comprobar el cumplimiento de las definiciones de recursos personalizados (CRD). Sin embargo, es posible configurar kubeval ingnóralos.

Kubeval es una gran herramienta para comprobar y evaluar recursos; Sin embargo, cabe enfatizar que pasar la prueba no garantiza que el recurso cumpla con las mejores prácticas.

Por ejemplo, usando la etiqueta latest en un contenedor no sigue las mejores prácticas. Sin embargo, kubeval no considera que esto sea un error y no lo informa. Es decir, la verificación de dicho YAML se completará sin advertencias.

Pero, ¿qué sucede si desea evaluar YAML e identificar infracciones como la etiqueta latest? ¿Cómo comparo un archivo YAML con las mejores prácticas?

2. Puntuación de Kube

Puntuación de Kube analiza los manifiestos YAML y los evalúa comparándolos con pruebas integradas. Estas pruebas se seleccionan en función de pautas de seguridad y mejores prácticas, tales como:

  • Ejecutar el contenedor no como root.
  • Disponibilidad de controles de estado del pod.
  • Establecimiento de solicitudes y límites de recursos.

Según los resultados de la prueba, se dan tres resultados: OK, ADVERTENCIA и CRÍTICA.

Puedes probar Kube-score en línea o instalarlo localmente.

Al momento de escribir el artículo original, la última versión de kube-score era 1.7.0.

Probémoslo en nuestro manifiesto. 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 pasa las pruebas de kubeval, mientras que kube-score señala las siguientes fallas:

  • Las comprobaciones de preparación no están configuradas.
  • No hay solicitudes ni límites para los recursos de la CPU y la memoria.
  • No se especifican los presupuestos para la interrupción de los pods.
  • No hay reglas de separación. (antiafinidad) para maximizar la disponibilidad.
  • El contenedor se ejecuta como root.

Todos estos son puntos válidos sobre las deficiencias que deben abordarse para que la implementación sea más eficiente y confiable.

Equipo kube-score muestra información en formato legible por humanos, incluidas todo tipo de infracciones ADVERTENCIA и CRÍTICA, lo que ayuda mucho durante el desarrollo.

Aquellos que deseen utilizar esta herramienta dentro del proceso de CI pueden habilitar una salida más comprimida usando la bandera --output-format ci (en este caso también se muestran las pruebas con el resultado 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

Similar a kubeval, kube-score devuelve un código de salida distinto de cero cuando hay una prueba que falla CRÍTICA. También puede habilitar un procesamiento similar para ADVERTENCIA.

Además, es posible verificar que los recursos cumplan con diferentes versiones de API (como en kubeval). Sin embargo, esta información está codificada en el propio kube-score: no puede seleccionar una versión diferente de Kubernetes. Esta limitación puede ser un gran problema si tiene la intención de actualizar su clúster o si tiene varios clústeres con diferentes versiones de K8.

Tenga en cuenta que ya hay un problema con una propuesta para aprovechar esta oportunidad.

Puede encontrar más información sobre kube-score en el sitio web oficial.

Las pruebas de puntuación de Kube son una gran herramienta para implementar las mejores prácticas, pero ¿qué sucede si necesita realizar cambios en la prueba o agregar sus propias reglas? Lamentablemente, esto no se puede hacer.

Kube-score no es extensible: no puede agregarle políticas ni ajustarlas.

Si necesita escribir pruebas personalizadas para verificar el cumplimiento de las políticas de la empresa, puede utilizar una de las siguientes cuatro herramientas: config-lint, copper, conftest o polaris.

3.Configuración-lint

Config-lint es una herramienta para validar archivos de configuración YAML, JSON, Terraform, CSV y manifiestos de Kubernetes.

Puedes instalarlo usando instrucciones en el sitio web del proyecto.

La versión actual al momento de escribir el artículo original es 1.5.0.

Config-lint no tiene pruebas integradas para validar manifiestos de Kubernetes.

Para realizar cualquier prueba, debe crear reglas apropiadas. Están escritos en archivos YAML llamados "conjuntos de reglas". (conjuntos de reglas), y tiene la siguiente estructura:

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

(rule.yaml)

Estudiémoslo más de cerca:

  • Campo type especifica qué tipo de configuración utilizará config-lint. Para los manifiestos K8 esto es siempre Kubernetes.
  • En el campo files Además de los archivos en sí, puede especificar un directorio.
  • Campo rules destinado a configurar pruebas de usuario.

Supongamos que desea asegurarse de que las imágenes en Deployment siempre se descarguen desde un repositorio confiable como my-company.com/myapp:1.0. Una regla de config-lint que realiza dicha verificación se vería así:

- 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 regla debe tener los siguientes atributos:

  • id — identificador único de la regla;
  • severity - quizás FRACASO, ADVERTENCIA и NO_CONFORME;
  • message — si se viola una regla, se muestra el contenido de esta línea;
  • resource — el tipo de recurso al que se aplica esta regla;
  • assertions — una lista de condiciones que serán evaluadas en relación con este recurso.

En la regla anterior assertion intitulado every comprueba que todos los contenedores estén en Despliegue (key: spec.templates.spec.containers) utilizar imágenes confiables (es decir, comenzando con my-company.com/).

El conjunto de reglas completo se ve así:

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 probar la prueba, guardémosla como check_image_repo.yaml. Ejecutemos una verificación del archivo. 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"
  }
]

El cheque falló. Ahora veamos el siguiente manifiesto con el repositorio de imágenes correcto:

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)

Realizamos la misma prueba con el manifiesto anterior. No se encontraron problemas:

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

Config-lint es un marco prometedor que le permite crear sus propias pruebas para validar los manifiestos YAML de Kubernetes utilizando YAML DSL.

Pero, ¿qué pasa si necesitas lógica y pruebas más complejas? ¿No es YAML demasiado limitado para esto? ¿Qué pasaría si pudieras crear pruebas en un lenguaje de programación completo?

4. cobre

Cobre V2 es un marco para validar manifiestos mediante pruebas personalizadas (similar a config-lint).

Sin embargo, se diferencia de este último en que no utiliza YAML para describir pruebas. En su lugar, las pruebas se pueden escribir en JavaScript. Copper proporciona una biblioteca con varias herramientas básicas, que le ayudan a leer información sobre los objetos de Kubernetes e informar errores.

Los pasos para instalar Copper se pueden encontrar en documentación oficial.

2.0.1 es la última versión de esta utilidad en el momento de escribir el artículo original.

Al igual que config-lint, Copper no tiene pruebas integradas. Escribamos uno. Permítale comprobar que las implementaciones utilizan imágenes de contenedores exclusivamente de repositorios confiables como my-company.com.

Crear un archivo check_image_repo.js con el siguiente contenido:

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

Ahora a probar nuestro manifiesto. base-valid.yaml, usa el 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

Está claro que con la ayuda del cobre se pueden realizar pruebas más complejas, por ejemplo, comprobar los nombres de dominio en los manifiestos de Ingress o rechazar los pods que se ejecutan en modo privilegiado.

El cobre tiene varias funciones de utilidad integradas:

  • DockerImage lee el archivo de entrada especificado y crea un objeto con los siguientes atributos:
    • name - nombre de la imagen,
    • tag - etiqueta de imagen,
    • registry - registro de imágenes,
    • registry_url - protocolo (https://) y registro de imágenes,
    • fqin — ubicación completa de la imagen.
  • Función findByName ayuda a encontrar un recurso por un tipo determinado (kind) y nombre (name) del archivo de entrada.
  • Función findByLabels ayuda a encontrar un recurso por un tipo específico (kind) y etiquetas (labels).

Puede ver todas las funciones de servicio disponibles aquí.

De forma predeterminada, carga todo el archivo YAML de entrada en una variable. $$ y lo pone a disposición para secuencias de comandos (una técnica familiar para aquellos con experiencia en jQuery).

La principal ventaja de Copper es obvia: no es necesario dominar un lenguaje especializado y puedes utilizar varias funciones de JavaScript para crear tus propias pruebas, como interpolación de cadenas, funciones, etc.

También cabe señalar que la versión actual de Copper funciona con la versión ES5 del motor JavaScript, no con ES6.

Detalles disponibles en el sitio web oficial del proyecto.

Sin embargo, si no te gusta mucho JavaScript y prefieres un lenguaje diseñado específicamente para crear consultas y describir políticas, debes prestar atención a conftest.

5.Concurso

Conftest es un marco para probar datos de configuración. También es adecuado para probar/verificar manifiestos de Kubernetes. Las pruebas se describen utilizando un lenguaje de consulta especializado. Rego.

Puedes instalar conftest usando instruccionesenumerados en el sitio web del proyecto.

En el momento de escribir el artículo original, la última versión disponible era la 0.18.2.

Al igual que config-lint y copper, conftest viene sin pruebas integradas. Probémoslo y escribamos nuestra propia política. Como en ejemplos anteriores, comprobaremos si las imágenes del contenedor están tomadas de una fuente confiable.

Crear un directorio conftest-checks, y en él hay un archivo llamado check_image_registry.rego con el siguiente contenido:

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

Ahora probemos base-valid.yaml a través de 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

Como era de esperar, la prueba falló porque las imágenes provenían de una fuente no confiable.

En el archivo Rego definimos el bloque deny. Su verdad se considera una violación. si bloques deny varios, conftest los verifica independientemente uno del otro, y la veracidad de cualquiera de los bloques se trata como una violación.

Además de la salida predeterminada, conftest admite formatos JSON, TAP y de tabla, una característica extremadamente útil si necesita incrustar informes en una canalización de CI existente. Puede configurar el formato deseado usando la bandera --output.

Para facilitar la depuración de políticas, conftest tiene una bandera --trace. Genera un rastro de cómo conftest analiza los archivos de políticas especificados.

Las políticas del concurso se pueden publicar y compartir en registros OCI (Open Container Initiative) como artefactos.

Equipos push и pull le permite publicar un artefacto o recuperar un artefacto existente de un registro remoto. Intentemos publicar la política que creamos en el registro local de Docker usando conftest push.

Inicie su registro local de Docker:

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

En otra terminal, vaya al directorio que creó anteriormente conftest-checks y ejecuta el siguiente comando:

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

Si el comando fue exitoso, verá un mensaje como este:

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

Ahora cree un directorio temporal y ejecute el comando en él. conftest pull. Descargará el paquete creado por el comando anterior:

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

Aparecerá un subdirectorio en el directorio temporal. policyque contiene nuestro archivo de póliza:

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

Las pruebas se pueden ejecutar directamente desde el repositorio:

$ 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

Lamentablemente, DockerHub aún no es compatible. Así que considérate afortunado si usas Registro de contenedores de Azure (ACR) o su propio registro.

El formato del artefacto es el mismo que Paquetes de Agente de políticas abiertas (OPA), que le permite utilizar conftest para ejecutar pruebas desde paquetes OPA existentes.

Puede obtener más información sobre el intercambio de políticas y otras características de conftest en el sitio web oficial del proyecto.

6. estrella polar

La última herramienta que se discutirá en este artículo es Polaris. (Su anuncio del año pasado nos ya traducido - aprox. traducción)

Polaris puede instalarse en un clúster o usarse en modo de línea de comandos. Como habrás adivinado, te permite analizar estáticamente los manifiestos de Kubernetes.

Cuando se ejecuta en modo de línea de comandos, hay pruebas integradas disponibles que cubren áreas como seguridad y mejores prácticas (similar a kube-score). Además, puedes crear tus propias pruebas (como en config-lint, copper y conftest).

En otras palabras, Polaris combina los beneficios de ambas categorías de herramientas: con pruebas integradas y personalizadas.

Para instalar Polaris en modo de línea de comando, use instrucciones en el sitio web del proyecto.

Al momento de escribir el artículo original, la versión 1.0.3 está disponible.

Una vez completada la instalación, puede ejecutar Polaris en el manifiesto. base-valid.yaml con el siguiente comando:

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

Generará una cadena en formato JSON con una descripción detallada de las pruebas realizadas y sus resultados. La salida tendrá la siguiente estructura:

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

Salida completa disponible aquí.

Al igual que kube-score, Polaris identifica problemas en áreas donde el manifiesto no cumple con las mejores prácticas:

  • No hay controles de salud para las vainas.
  • No se especifican etiquetas para imágenes de contenedores.
  • El contenedor se ejecuta como root.
  • No se especifican las solicitudes ni los límites de memoria y CPU.

A cada prueba, en función de sus resultados, se le asigna un grado de criticidad: advertencia o peligro. Para obtener más información sobre las pruebas integradas disponibles, consulte documentación.

Si no se necesitan detalles, puede especificar la bandera --format score. En este caso, Polaris generará un número que oscila entre 1 y 100: Puntuación (es decir, evaluación):

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

Cuanto más cerca esté la puntuación de 100, mayor será el grado de acuerdo. Si verifica el código de salida del comando polaris audit, resulta que es igual a 0.

Hacer polaris audit Puede finalizar el trabajo con código distinto de cero usando dos indicadores:

  • Bandera --set-exit-code-below-score toma como argumento un valor umbral en el rango 1-100. En este caso, el comando saldrá con el código de salida 4 si la puntuación está por debajo del umbral. Esto es muy útil cuando tienes un valor umbral determinado (por ejemplo, 75) y necesitas recibir una alerta si la puntuación desciende por debajo.
  • Bandera --set-exit-code-on-danger hará que el comando falle con el código 3 si falla una de las pruebas de peligro.

Ahora intentemos crear una prueba personalizada que verifique si la imagen se tomó de un repositorio confiable. Las pruebas personalizadas se especifican en formato YAML y la prueba en sí se describe mediante el esquema JSON.

El siguiente fragmento de código YAML describe una nueva prueba llamada 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/.+$

Veámoslo más de cerca:

  • successMessage — esta línea se imprimirá si la prueba se completa con éxito;
  • failureMessage — este mensaje se mostrará en caso de fallo;
  • category — indica una de las categorías: Images, Health Checks, Security, Networking и Resources;
  • target--- determina qué tipo de objeto (spec) se aplica la prueba. Valores posibles: Container, Pod o Controller;
  • La prueba en sí está especificada en el objeto. schema utilizando el esquema JSON. La palabra clave en esta prueba es pattern Se utiliza para comparar la fuente de la imagen con la requerida.

Para ejecutar la prueba anterior, debe crear la siguiente configuración de 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)

Analicemos el archivo:

  • En el campo checks Se prescriben las pruebas y su nivel de criticidad. Dado que es deseable recibir una advertencia cuando una imagen se toma de una fuente no confiable, configuramos el nivel aquí danger.
  • La prueba en sí checkImageRepo luego registrado en el objeto customChecks.

Guardar el archivo como custom_check.yaml. Ahora puedes correr polaris audit con un manifiesto YAML que requiere verificación.

Probemos nuestro manifiesto base-valid.yaml:

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

Equipo polaris audit Ejecutó solo la prueba de usuario especificada anteriormente y falló.

Si arreglas la imagen a my-company.com/http-echo:1.0, Polaris se completará con éxito. El manifiesto con los cambios ya está en repositoriospara que puedas verificar el comando anterior en el manifiesto image-valid-mycompany.yaml.

Ahora surge la pregunta: ¿cómo ejecutar pruebas integradas junto con pruebas personalizadas? ¡Fácilmente! Sólo necesita agregar los identificadores de prueba integrados al archivo de configuración. Como resultado, tomará la siguiente forma:

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)

Un ejemplo de un archivo de configuración completo está disponible aquí.

Verificar manifiesto base-valid.yamlAl utilizar pruebas integradas y personalizadas, puede utilizar el comando:

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

Polaris complementa las pruebas integradas con pruebas personalizadas, combinando así lo mejor de ambos mundos.

Por otro lado, la imposibilidad de utilizar lenguajes más potentes como Rego o JavaScript puede ser un factor limitante que impida la creación de pruebas más sofisticadas.

Más información sobre Polaris está disponible en sitio del proyecto.

Resumen

Si bien hay muchas herramientas disponibles para inspeccionar y evaluar archivos YAML de Kubernetes, Es importante tener una comprensión clara de cómo se diseñarán y ejecutarán las pruebas..

Por ejemplo, Si toma los manifiestos de Kubernetes a través de un proceso, kubeval podría ser el primer paso en dicho proceso.. Supervisaría si las definiciones de objetos se ajustan al esquema de la API de Kubernetes.

Una vez que se complete dicha revisión, se podría pasar a pruebas más sofisticadas, como el cumplimiento de las mejores prácticas estándar y políticas específicas. Aquí es donde kube-score y Polaris resultarían útiles.

Para aquellos que tienen requisitos complejos y necesitan personalizar las pruebas en detalle, copper, config-lint y conftest serían adecuados.

Conftest y config-lint usan YAML para definir pruebas personalizadas, y copper le brinda acceso a un lenguaje de programación completo, lo que lo convierte en una opción bastante atractiva.

Por otro lado, ¿merece la pena utilizar una de estas herramientas y, por tanto, crear todas las pruebas manualmente, o preferir Polaris y añadirle sólo lo necesario? No hay una respuesta clara a esta pregunta..

La siguiente tabla proporciona una breve descripción de cada herramienta:

Herramienta
Propósito
Limitaciones
Pruebas de usuario

kubeval
Valida los manifiestos YAML con una versión específica del esquema API.
No puedo trabajar con CRD
No

puntuación de kube
Analiza los manifiestos YAML frente a las mejores prácticas.
No puedo seleccionar la versión de la API de Kubernetes para verificar los recursos
No

cobre
Un marco general para crear pruebas de JavaScript personalizadas para manifiestos YAML
Sin pruebas integradas. Mala documentación

configuración-lint
Un marco general para crear pruebas en un lenguaje de dominio específico integrado en YAML. Admite varios formatos de configuración (por ejemplo, Terraform)
No hay pruebas listas para usar. Las afirmaciones y funciones integradas pueden no ser suficientes

concurso
Un marco para crear sus propias pruebas utilizando Rego (un lenguaje de consulta especializado). Permite compartir políticas a través de paquetes OCI
Sin pruebas integradas. Tengo que aprender Rego. Docker Hub no es compatible al publicar políticas

Polaris
Revisa los manifiestos YAML en comparación con las mejores prácticas estándar. Le permite crear sus propias pruebas utilizando el esquema JSON.
Las capacidades de prueba basadas en el esquema JSON pueden no ser suficientes

Dado que estas herramientas no dependen del acceso al clúster de Kubernetes, son fáciles de instalar. Le permiten filtrar archivos fuente y brindar comentarios rápidos a los autores de solicitudes de extracción en proyectos.

PD del traductor

Lea también en nuestro blog:

Fuente: habr.com

Añadir un comentario