Nota de traducción.: Con el aumento del número de configuraciones YAML para entornos K8s, se hace cada vez más relevante la necesidad de su verificación automatizada. El autor de esta revisión no solo ha seleccionado soluciones existentes para esta tarea, sino que también ha explorado, mediante el ejemplo de un Deployment, cómo funcionan. Resultó ser bastante informativo para aquellos a quienes les interesa este tema.

TL;DR: El artículo compara seis herramientas estáticas de verificación y evaluación de archivos YAML de Kubernetes en relación con las mejores prácticas y requisitos.
Las cargas de trabajo de Kubernetes se definen generalmente en forma de documentos YAML. Uno de los problemas con YAML es la complejidad de establecer restricciones o relaciones entre los archivos de manifiestos.
¿Qué pasa si necesitamos asegurarnos de que todas las imágenes desplegadas en el clúster provienen de un registro de confianza?
¿Cómo prevenir el envío de Deployments al clúster para los cuales no se han establecido PodDisruptionBudgets?
La integración de pruebas estáticas permite identificar errores y violaciones de políticas aún en la fase de desarrollo. De este modo, se incrementan las garantías de corrección y seguridad de las definiciones de recursos y se aumenta la probabilidad de que las cargas de producción sigan las mejores prácticas.
El ecosistema de verificación estática de archivos YAML de Kubernetes se puede dividir en las siguientes categorías:
- Validadores de API. Las herramientas en esta categoría validan el manifiesto YAML en conformidad con los requisitos del servidor API de Kubernetes.
- Testers predefinidos. Las herramientas de esta categoría vienen con pruebas listas sobre seguridad, conformidad con las mejores prácticas, etc.
- Validadores personalizados. Los representantes de esta categoría permiten crear pruebas personalizadas en varios lenguajes, como Rego y JavaScript.
En este artículo describiremos y compararemos seis herramientas diferentes:
- kubeval;
- kube-score;
- config-lint;
- copper;
- conftest;
- Polaris.
¡Bien, comencemos!
Verificación de Deployments
Antes de proceder a la comparación de las herramientas, establezcamos una base sobre la cual las probaremos.
El siguiente manifiesto contiene varios errores y discrepancias con las mejores prácticas: ¿cuántos de ellos podrás 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)
Vamos a utilizar este YAML para comparar diversas herramientas.
El manifiesto anterior
base-valid.yamly otros manifiestos de este artículo se pueden encontrar en .
El manifiesto describe una aplicación web cuya tarea principal es responder con el mensaje «Hello World» en el puerto 5678. Se puede desplegar con el siguiente comando:
kubectl apply -f hello-world.yamlY así se prueba su funcionamiento:
kubectl port-forward svc/http-echo 8080:5678Ahora, visita y confirma que la aplicación está funcionando. Pero, ¿sigue las mejores prácticas? Vamos a comprobarlo.
1. Kubeval
La base de es la idea de que cualquier interacción con Kubernetes se realiza a través de su API REST. En otras palabras, se puede utilizar el esquema API para validar si el YAML dado cumple con él. Veamos un ejemplo.
kubeval están disponibles en el sitio del proyecto.
En el momento de redactar el artículo original, estaba disponible la versión 0.15.0.
Después de la instalación, vamos a ‘alimentarle’ el manifiesto mencionado anteriormente:
$ kubeval base-valid.yaml
PASS - base-valid.yaml contains a valid Deployment (http-echo)
PASS - base-valid.yaml contains a valid Service (http-echo)En caso de éxito, kubeval terminará con un código de salida 0. Se puede verificar de la siguiente manera:
$ echo $?
0Ahora intentemos kubeval con otro manifiesto:
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 identificar el problema a simple vista? Ejecutamos:
$ 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)
# verifiquemos el código de retorno
$ echo $?
1El recurso no pasa la validación.
Los Deployments que utilizan la versión API apps/v1, deben incluir un selector que coincida con la etiqueta del pod. El manifiesto anterior no incluye un selector, por lo que kubeval informó de un error y terminó con un código diferente de cero.
Es interesante, ¿qué pasará si ejecutamos kubectl apply -f con este manifiesto?
Bueno, intentémoslo:
$ 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=falseExactamente el error que advirtió kubeval. Se puede corregir añadiendo 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 se pueden detectar estos errores en las primeras etapas del ciclo de despliegue.
Además, para estas verificaciones no se necesita acceso al clúster: se pueden realizar sin conexión.
Por defecto, kubeval verifica los recursos para cumplir con el esquema más reciente de Kubernetes API. Sin embargo, en la mayoría de los casos, es posible que necesite realizar una verificación contra una versión específica de Kubernetes. Esto se puede hacer utilizando el flag --kubernetes-version:
$ kubeval --kubernetes-version 1.16.1 base-valid.yamlTenga en cuenta que la versión debe especificarse en el formato Major.Minor.Patch.
Para ver la lista de versiones para las que se admite la verificación, consulte , que kubeval utiliza para la validación. Si necesita ejecutar kubeval sin conexión, descargue los esquemas y especifique su ubicación local usando el flag --schema-location.
Además de archivos YAML individuales, kubeval también puede trabajar con directorios y stdin.
Además, Kubeval se integra fácilmente en pipelines de CI. Los interesados en realizar pruebas antes de enviar manifiestos al clúster se alegrarán de saber que kubeval admite tres formatos de salida:
- Texto plano;
- JSON;
- Test Anything Protocol (TAP).
Y cualquiera de los formatos se puede usar para un análisis posterior de la salida, para generar un resumen de resultados en el formato deseado.
Una de las desventajas de kubeval es que actualmente no puede verificar conformidad con las Custom Resource Definitions (CRDs). Sin embargo, se puede configurar kubeval .
Kubeval es una excelente herramienta para verificar y evaluar recursos; sin embargo, cabe destacar que pasar la prueba no garantiza que el recurso cumpla con las mejores prácticas.
Por ejemplo, el uso de la etiqueta latest El contenedor no cumple con las mejores prácticas. Sin embargo, kubeval no considera esto un error y no lo reporta. Es decir, la validación de este YAML finalizará sin advertencias.
Pero, ¿qué ocurre si necesitamos evaluar el YAML y detectar infracciones como la etiqueta? latest? Как проверить YAML-файл на соответствие лучшим практикам?
2. Kube-score
analiza los manifiestos YAML y los evalúa según pruebas incorporadas. Estas pruebas se seleccionan en base a recomendaciones de seguridad y mejores prácticas, como por ejemplo:
- Ejecutar contenedores no como root.
- La existencia de comprobaciones de estado de los pods.
- Asignar solicitudes y límites de recursos.
Tras la evaluación, se emiten tres resultados: OK, ADVERTENCIA y CRÍTICO.
Kube-score se puede probar en línea o instalar localmente.
Al momento de escribir el artículo original, la versión más reciente de kube-score era 1.7.0.
Probemos con nuestro manifiesto base-valid.yaml:
$ kube-score score base-valid.yaml
apps/v1/Deployment http-echo
[CRÍTICO] Etiqueta de imagen del contenedor
· http-echo -> Imagen con etiqueta latest
Se recomienda usar una etiqueta fija para evitar actualizaciones accidentales
[CRÍTICO] NetworkPolicy de Pod
· El pod no tiene una política de red coincidente
Crea una NetworkPolicy que apunte a este pod
[CRÍTICO] Comprobaciones del Pod
· El contenedor carece de readinessProbe
Se debe usar un readinessProbe para indicar cuándo el servicio está listo para recibir tráfico.
Sin él, el Pod corre el riesgo de recibir tráfico antes de haber iniciado. También se usa durante
los despliegues y puede prevenir el tiempo de inactividad si una nueva versión de la aplicación falla.
Más información: https://github.com/zegl/kube-score/blob/master/README_PROBES.md
[CRÍTICO] Contexto de seguridad del contenedor
· http-echo -> Contenedor no tiene configurado un contexto de seguridad
Establezca securityContext para ejecutar el contenedor en un contexto más seguro.
[CRÍTICO] Recursos del contenedor
· http-echo -> Límite de CPU no está configurado
Se recomiendan límites de recursos para evitar un DDOS de recursos. Establezca resources.limits.cpu
· http-echo -> Límite de memoria no está configurado
Se recomiendan límites de recursos para evitar un DDOS de recursos. Establezca resources.limits.memory
· http-echo -> Solicitud de CPU no está configurada
Se recomiendan solicitudes de recursos para asegurarse de que la aplicación pueda iniciar y ejecutarse sin
fallar. Establezca resources.requests.cpu
· http-echo -> Solicitud de memoria no está configurada
Se recomiendan solicitudes de recursos para asegurarse de que la aplicación pueda iniciar y ejecutarse sin
fallar. Establezca resources.requests.memory
[CRÍTICO] El despliegue tiene PodDisruptionBudget
· No se encontró un PodDisruptionBudget coincidente
Se recomienda definir un PodDisruptionBudget para evitar tiempos de inactividad inesperados durante las
operaciones de mantenimiento de Kubernetes, como cuando se drena un nodo.
[ADVERTENCIA] El despliegue tiene host PodAntiAffinity
· El despliegue no tiene un podAntiAffinity configurado
Se recomienda establecer un podAntiAffinity que impida que múltiples pods de un despliegue se programen
en el mismo nodo. Esto aumenta la disponibilidad en caso de que el nodo se vuelva no disponible.El YAML pasa las verificaciones de kubeval, mientras que kube-score indica las siguientes deficiencias:
- No se han configurado comprobaciones de disponibilidad.
- Faltan solicitudes y límites para recursos de CPU y memoria.
- No se han definido presupuestos de interrupción del Pod.
- Faltan reglas de anti-affinity. (anti-afinidad) para maximizar la disponibilidad.
- El contenedor se ejecuta bajo root.
Todo esto son observaciones razonables sobre las deficiencias que deben solucionarse para que el despliegue sea más eficiente y confiable.
Comando kube-score muestra información en un formato legible con inclusión de todas las violaciones de tipo ADVERTENCIA y CRÍTICO, lo cual es muy útil durante el desarrollo.
Quienes deseen usar esta herramienta en el marco de un pipeline de CI pueden habilitar una salida más compacta usando el flag --output-format ci (en este caso también se muestran las pruebas con resultados 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) El límite de CPU no está establecido
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) El límite de memoria no está establecido
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) La solicitud de CPU no está establecida
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) La solicitud de memoria no está establecida
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) Imagen con la etiqueta más reciente
[OK] http-echo apps/v1/Deployment
[CRITICAL] http-echo apps/v1/Deployment: El pod no tiene una política de red coincidente
[CRITICAL] http-echo apps/v1/Deployment: El contenedor carece de readinessProbe
[CRITICAL] http-echo apps/v1/Deployment: (http-echo) El contenedor no tiene un contexto de seguridad configurado
[CRITICAL] http-echo apps/v1/Deployment: No se encontró un PodDisruptionBudget coincidente
[WARNING] http-echo apps/v1/Deployment: El despliegue no tiene un podAntiAffinity host configurado
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/Service
[OK] http-echo v1/ServiceDe manera similar a kubeval, kube-score retorna un código de salida no cero si hay una prueba que falló. CRÍTICO. También se puede habilitar un manejo similar para ADVERTENCIA.
Además, existe la posibilidad de verificar recursos en conformidad con diferentes versiones de API (como en kubeval). Sin embargo, esta información está 'hardcodeada' en el propio kube-score: no se puede seleccionar otra versión de Kubernetes. Esta limitación puede ser un gran problema si planeas actualizar tu clúster o si tienes varios clústeres con diferentes versiones de K8s.
Tenga en cuenta que con la propuesta de implementar esta funcionalidad.
Para más información sobre kube-score, puedes consultar .
Las pruebas de kube-score son una gran herramienta para la implementación de mejores prácticas, pero ¿qué sucede si necesitas hacer cambios en la prueba o agregar tus propias reglas? Lamentablemente, no es posible hacerlo.
Kube-score no es extensible: no se pueden agregar o ajustar políticas.
Si necesitas escribir pruebas personalizadas para comprobaciones de conformidad con las políticas adoptadas en la empresa, puedes usar una de las siguientes cuatro herramientas: config-lint, copper, conftest o polaris.
3. Config-lint
Config-lint es una herramienta para la validación de archivos de configuración en formatos YAML, JSON, Terraform, CSV y manifiestos de Kubernetes.
Se puede instalar mediante en el sitio del proyecto.
La versión actual al momento de escribir este artículo es 1.5.0.
Config-lint no incluye pruebas integradas para verificar los manifiestos de Kubernetes.
Para realizar cualquier prueba, es necesario crear las reglas correspondientes. Estas se escriben en archivos YAML, conocidos como 'conjuntos de reglas' (rulesets), y tienen la siguiente estructura:
version: 1
description: Reglas para archivos de especificación de Kubernetes
type: Kubernetes
files:
- "*.yaml"
rules:
# lista de reglas(rule.yaml)
Examinemos esto más de cerca:
- Campo
tipoindica qué tipo de configuración utilizará config-lint. Para los manifiestos de K8s, esto es siempreKubernetes. - En el campo
filesademás de los propios archivos, se puede especificar un directorio. - Campo
rulesdestinado a establecer pruebas personalizadas.
Supongamos que desea asegurarse de que las imágenes en el Deployment siempre se descarguen desde un repositorio confiable como my-company.com/myapp:1.0. La regla para config-lint que realiza esta verificación se verá de la siguiente manera:
- id: MY_DEPLOYMENT_IMAGE_TAG
severity: FAILURE
message: El Deployment debe usar una etiqueta de imagen válida
resource: Deployment
assertions:
- every:
key: spec.template.spec.containers
expressions:
- key: image
op: starts-with
value: "my-company.com/"(rule-trusted-repo.yaml)
Para cada regla, deben especificarse los siguientes atributos:
id— identificador único de la regla;severity— puede ser FAILURE, ADVERTENCIA y NON_COMPLIANT;message— el contenido de esta línea se mostrará al violar la regla;resource— el tipo de recurso al que se aplica esta regla;assertions— lista de condiciones que se evaluarán en relación con este recurso.
En la regla anterior, la afirmación llamada verifica que todos los contenedores en el Deployment (key: spec.templates.spec.containers) utilicen imágenes confiables (es decir, que comiencen con my-company.com/).
El conjunto de reglas completo se ve de la siguiente manera:
version: 1
description: Reglas para archivos de especificación de Kubernetes
type: Kubernetes
files:
- "*.yaml"
rules:
- id: DEPLOYMENT_IMAGE_REPOSITORY # !!!
severity: FAILURE
message: El Deployment debe usar un repositorio de imágenes válido
resource: Deployment
assertions:
- every:
key: spec.template.spec.containers
expressions:
- key: image
op: starts-with
value: "my-company.com/"(ruleset.yaml)
Para probar la regla, guardémosla como check_image_repo.yaml. Ejecutemos la verificación en el 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": "El despliegue debe usar un repositorio de imágenes válido",
"Status": "FALLO"
}
]La verificación falló. Ahora vamos a verificar el siguiente manifiesto con un 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)
Ejecutamos 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 permite crear pruebas personalizadas para verificar manifiestos YAML de Kubernetes utilizando YAML DSL.
¿Pero qué hacer si se requiere una lógica y pruebas más complejas? ¿No son las capacidades de YAML demasiado limitadas para eso? ¿Qué tal si se pudieran crear pruebas en un lenguaje de programación completo?
4. Copper
es un marco para la validación de manifiestos mediante pruebas personalizadas (similar a config-lint).
Sin embargo, se diferencia de este último en que no utiliza YAML para describir las pruebas. En su lugar, se pueden crear pruebas en JavaScript. Copper proporciona una biblioteca con varias herramientas básicas, que ayudan a leer información sobre objetos de Kubernetes y reportar errores.
La secuencia de pasos para instalar Copper se puede encontrar en .
2.0.1 es la versión más reciente de esta utilidad al momento de escribir el artículo original.
Al igual que config-lint, Copper no tiene pruebas integradas. Vamos a escribir una. Supongamos que verifica que los despliegues utilicen imágenes de contenedores únicamente de repositorios confiables como my-company.com.
Cree 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',"La imagen " + $.metadata.name + " no es del repositorio my-company.com", 1)
}
});
}
});Ahora, para verificar nuestro manifiesto base-valid.yaml, use 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 La imagen http-echo no es del repositorio my-company.com
La validación fallóEs evidente que con copper se pueden realizar pruebas más complejas, como verificar los nombres de dominio en los manifiestos de Ingress o rechazar pods que funcionan en modo privilegiado.
Copper incluye varias funciones auxiliares:
DockerImagelee el archivo de entrada especificado y crea un objeto con los siguientes atributos:name— nombre de la imagen,tag— etiqueta de la imagen,registry— registro de imágenes,registry_url— protocolo (https://) y registro de imágenes,fqin— ubicación completa de la imagen.
- La función
findByNameayuda a encontrar un recurso por el tipo especificado (tipo) y el nombre (name) del archivo de entrada. - La función
findByLabelsayuda a encontrar un recurso por el tipo especificado (tipo) y las etiquetas (labels).
Puedes familiarizarte con todas las funciones auxiliares disponibles .
Por defecto, carga todo el archivo YAML de entrada en una variable $$ y lo hace accesible para los scripts (un método familiar para aquellos con experiencia en jQuery).
La ventaja principal de Copper es evidente: no necesitas aprender un lenguaje especializado y puedes utilizar diversas capacidades de JavaScript para crear tus propias pruebas, como la interpolación de cadenas, funciones, etc.
También cabe destacar que la versión actual de Copper funciona con la versión ES5 del motor JavaScript, no con ES6.
Los detalles están disponibles en .
Sin embargo, si no te gusta mucho JavaScript y prefieres un lenguaje diseñado específicamente para crear consultas y describir políticas, deberías considerar conftest.
5. Conftest
Conftest es un marco para verificar datos de configuración. Es adecuado también para pruebas/validación de manifiestos de Kubernetes. Las pruebas se describen utilizando un lenguaje de consulta especializado .
Puedes instalar conftest usando , que se encuentran en el sitio del proyecto.
Al momento de escribir el artículo original, la última versión disponible era 0.18.2.
Al igual que config-lint y copper, conftest viene sin pruebas integradas. Vamos a probarlo y a escribir nuestra propia política. Al igual que en los ejemplos anteriores, vamos a verificar si las imágenes de los contenedores provienen de una fuente confiable.
Crea un directorio conftest-checks, y dentro, 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("la imagen '%v' no proviene del repositorio my-company.com", [image])
}Ahora probemos base-valid.yaml a través de conftest:
$ conftest test --policy ./conftest-checks base-valid.yaml
FAIL - base-valid.yaml - la imagen 'hashicorp/http-echo' no proviene del repositorio my-company.com
1 pruebas, 1 aprobada, 0 advertencias, 1 falloLa prueba falló como se esperaba, ya que las imágenes provienen de una fuente no confiable.
En el archivo Rego definimos el bloque deny. Su veracidad se considera una violación. Si hay varios bloques, deny conftest los verifica de manera independiente entre sí, y la veracidad de cualquiera de los bloques se interpreta como una violación.
Además de la salida por defecto, conftest admite JSON, TAP y formato de tabla, lo cual es una característica extremadamente útil si se necesita integrar informes en un pipeline CI existente. El formato deseado se puede establecer mediante el flag --output.
Para ayudar en la depuración de políticas, conftest tiene un flag --trace. Este muestra un seguimiento de cómo conftest analiza los archivos de políticas especificados.
Las políticas de conftest se pueden publicar y compartir en registros OCI (Open Container Initiative) como artefactos.
Comandos push y pull permiten publicar un artefacto o extraer un artefacto existente de un registro remoto. Intentemos publicar la política que creamos en un registro local de Docker utilizando conftest push.
Ejecuta un registro local de Docker:
$ docker run -it --rm -p 5000:5000 registryEn otra terminal, dirígete al directorio que creaste previamente conftest-checks y ejecuta el siguiente comando:
$ conftest push 127.0.0.1:5000/amitsaha/opa-bundle-example:latestSi el comando se ejecutó correctamente, verás un mensaje del siguiente tipo:
2020/06/10 14:25:43 pushed bundle with digest: sha256:e9765f201364c1a8a182ca637bc88201db3417bacc091e7ef8211f6c2fd2609cAhora crea un directorio temporal y ejecuta en él el comando conftest pull. Esto descargará el paquete creado por el comando anterior en él:
$ cd $(mktemp -d)
$ conftest pull 127.0.0.1:5000/amitsaha/opa-bundle-example:latestEn el directorio temporal aparecerá un subdirectorio policy, conteniendo nuestro archivo de políticas:
$ tree
.
└── policy
└── check_image_registry.regoSe pueden realizar pruebas 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 failureDesafortunadamente, DockerHub aún no es compatible. Así que consideren que tienen suerte si utilizan (ACR) o su propio registro.
El formato de los artefactos es el mismo que el de (OPA), lo que permite utilizar conftest para ejecutar pruebas de paquetes OPA existentes.
Más sobre el compartir políticas y otras características de conftest se puede consultar en .
6. Polaris
La última herramienta de la que se hablará en este artículo es . (Su anuncio del año pasado ya lo — nota del traductor.)
Polaris se puede instalar en un clúster o utilizarse en modo línea de comandos. Como ya habrás adivinado, permite realizar un análisis estático de los manifiestos de Kubernetes.
En modo línea de comandos, hay pruebas integradas que cubren áreas como seguridad y mejores prácticas (similar a kube-score). Además, se pueden crear pruebas personalizadas (como en config-lint, copper y conftest).
En otras palabras, Polaris combina las ventajas de ambas categorías de herramientas: con pruebas integradas y personalizadas.
Para instalar Polaris en modo línea de comandos, utiliza .
Al momento de escribir este artículo, está disponible la versión 1.0.3.
Después de completar la instalación, puedes ejecutar polaris sobre el manifiesto base-valid.yaml con el siguiente comando:
$ polaris audit --audit-path base-valid.yamlEste comando generará una línea 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": [
/* lista larga */
]
}La salida completa está disponible .
Al igual que kube-score, Polaris identifica problemas en aquellas áreas donde el manifiesto no cumple con las mejores prácticas:
- Faltan comprobaciones de salud de los pods.
- No se especificaron etiquetas para las imágenes de los contenedores.
- El contenedor se ejecuta bajo root.
- No se especificaron requests y limits para la memoria y el CPU.
A cada prueba se le asigna un nivel de criticidad según sus resultados: advertencia o peligro. Para conocer más sobre las pruebas integradas disponibles, consulta .
Si no necesitas detalles, puedes agregar la bandera --format score. En este caso, Polaris mostrará un número en el rango de 1 a 100 — puntuación (es decir, la calificación):
$ polaris audit --audit-path test-data/base-valid.yaml --format score
68Cuanto más cerca esté la calificación de 100, mayor será el grado de conformidad. Si verificas el código de salida del comando polaris audit, verás que es igual a 0.
Forzar polaris audit la salida con un código distinto de cero se puede hacer con dos banderas:
- El flag
--set-exit-code-below-scoreacepta como argumento un valor umbral en el rango de 1-100. En este caso, el comando finalizará con un código de salida 4 si la calificación es inferior al umbral. Esto es muy conveniente cuando tienes un valor umbral (digamos, 75) y necesitas recibir una alerta si la calificación cae por debajo. - El flag
--set-exit-code-on-dangeresto resultará en que el equipo finalice con un código 3 si alguna de las pruebas de peligro falla.
Ahora intentemos crear una prueba personalizada que verifique si la imagen proviene de un repositorio de confianza. Las pruebas personalizadas se definen en formato YAML, y la prueba en sí se describe mediante JSON Schema.
El siguiente fragmento de código YAML describe una nueva prueba llamada checkImageRepo:
checkImageRepo:
successMessage: El registro de imágenes es válido
failureMessage: El registro de imágenes no es válido
category: Imágenes
target: Contenedor
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 mostrará si la prueba se completa con éxito;failureMessage— este mensaje se mostrará en caso de falla;category— indica una de las categorías:Imágenes,Chequeos de Salud,Seguridad,RedesyRecursos;target— determina a qué tipo de objeto (spec) se aplica la prueba. Posibles valores:Contenedor,PodoControlador;- La prueba se define en el objeto
schemausando el esquema JSON. En esta prueba, la palabra clavepatternse utiliza para comparar la fuente de la imagen con la requerida.
Para ejecutar la prueba anterior es necesario crear la siguiente configuración de Polaris:
checks:
checkImageRepo: danger
customChecks:
checkImageRepo:
successMessage: El registro de imágenes es válido
failureMessage: El registro de imágenes no es válido
category: Imágenes
target: Contenedor
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
checksdefinen las pruebas y su nivel de criticidad. Dado que es deseable recibir una advertencia cuando la imagen se obtiene de una fuente no confiable, establecemos aquí el nivelpeligro. - La prueba misma
checkImageRepoluego se define en el objetocustomChecks.
Guarde el archivo como custom_check.yaml. Ahora se puede ejecutar 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.yamlComando polaris audit ejecutó solo la prueba personalizada definida anteriormente y no tuvo éxito.
Si se corrige la imagen a my-company.com/http-echo:1.0, Polaris completará con éxito. El manifiesto con los cambios ya está en , así que puedes verificar el comando anterior en el manifiesto. image-valid-mycompany.yaml.
Ahora surge la pregunta: ¿cómo ejecutar pruebas integradas junto con las personalizadas? ¡Fácil! Simplemente agregue los identificadores de las pruebas integradas al archivo de configuración. Como resultado, tendrá el siguiente aspecto:
verificaciones:
cpuRequestsMissing: advertencia
cpuLimitsMissing: advertencia
# Otras verificaciones integradas..
# ..
# verificaciones personalizadas
checkImageRepo: peligro # !!!
verificacionesPersonalizadas:
checkImageRepo: # !!!
successMessage: El registro de imágenes es válido
failureMessage: El registro de imágenes no es válido
category: Imágenes
target: Contenedor
esquema:
'$schema': http://json-schema.org/draft-07/schema
type: object
properties:
image:
type: string
pattern: ^my-company.com/.+$(config_with_custom_check.yaml)
Ejemplo de archivo de configuración completo disponible .
Verificar el manifiesto base-valid.yaml, utilizando pruebas integradas y personalizadas, se puede realizar con el comando:
$ polaris audit --config config_with_custom_check.yaml --audit-path base-valid.yamlPolaris complementa las pruebas integradas con pruebas personalizadas, combinando lo mejor de ambos mundos.
Por otro lado, la incapacidad de utilizar lenguajes más potentes, como Rego o JavaScript, puede convertirse en un factor limitante que impida la creación de pruebas más sofisticadas.
Más información sobre Polaris está disponible en .
Currículum
Aunque existen muchas herramientas para verificar 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 se toman los manifiestos de Kubernetes que pasan por el pipeline, kubeval podría ser el primer paso en dicho pipeline. Se encargaría de verificar si las definiciones de objetos cumplen con el esquema de la API de Kubernetes.
Una vez completada una verificación de este tipo, se podría avanzar hacia pruebas más sofisticadas, como la conformidad con las mejores prácticas estándar y políticas específicas. Aquí es donde serían útiles kube-score y Polaris.
Para aquellos con requisitos complejos y la necesidad de personalizar las pruebas, serían útiles copper, config-lint y conftest.
Conftest y config-lint utilizan YAML para definir pruebas personalizadas, mientras que copper proporciona acceso a un lenguaje de programación completo, lo que lo convierte en una opción bastante atractiva.
Por otro lado, ¿deberíamos usar una de estas herramientas y, por lo tanto, crear todas las pruebas manualmente, o preferir Polaris y agregarle solo lo necesario? No hay una respuesta definitiva a esta pregunta.
La tabla a continuación contiene una breve descripción de cada herramienta:
Herramienta
Propósito
Desventajas
Pruebas personalizadas
kubeval
Verifica los manifiestos YAML para la conformidad con una versión específica del esquema de la API
No puede trabajar con CRD
No
kube-score
Analiza los manifiestos YAML para verificar su conformidad con las mejores prácticas
No se puede seleccionar su versión de la API de Kubernetes para verificar recursos
No
copper
Un marco general para crear pruebas JavaScript personalizadas para manifiestos YAML
No hay pruebas integradas. Documentación escasa
Sí
config-lint
Un marco general para crear pruebas en un lenguaje orientado a objetos, integrado en YAML. Soporta varios formatos de configuración (por ejemplo, Terraform)
No hay pruebas predefinidas. Las aserciones y funciones integradas pueden ser insuficientes
Sí
conftest
Marco para crear pruebas personalizadas en Rego (un lenguaje de consultas especializado). Permite compartir políticas a través de paquetes OCI
No hay pruebas integradas. Es necesario aprender Rego. Docker Hub no está soportado para la publicación de políticas
Sí
Polaris
Analiza manifiestos YAML para asegurar el cumplimiento de las mejores prácticas estándar. Permite crear pruebas personalizadas usando JSON Schema
Las capacidades de las pruebas basadas en JSON Schema pueden ser insuficientes
Sí
Dado que estas herramientas no dependen del acceso al clúster de Kubernetes, son fáciles de instalar. Permiten filtrar archivos fuente y brindan una retroalimentación rápida a los autores de solicitudes de extracción en proyectos.
P.D. del traductor
También puedes leer en nuestro blog:
- «»;
- «»;
- «».
Fuente: habr.com
