Compartir comentarios
Las respuestas se generan en base a la documentación.

Introducción a las políticas de compilación

Las políticas de compilación te permiten validar las entradas de tus compilaciones de Docker antes de que se ejecuten. Este tutorial te guiará en la creación de tu primera política, enseñándote los conceptos básicos de Rego que necesitas a lo largo del proceso.

Qué aprenderás

Al finalizar este tutorial, comprenderás:

  • Cómo crear y organizar archivos de políticas
  • La sintaxis y patrones básicos de Rego
  • Cómo escribir políticas que validen URLs, sumas de comprobación y imágenes
  • Cómo se evalúan las políticas durante las compilaciones

Requisitos previos

  • Buildx versión 0.31 o posterior
  • Familiaridad básica con Dockerfiles y compilación de imágenes

Cómo funcionan las políticas

Cuando compilas una imagen, Buildx resuelve todas las entradas a las que hace referencia tu Dockerfile: imágenes base de las instrucciones FROM, archivos de las instrucciones ADD o COPY o contextos de compilación, y repositorios Git. Antes de ejecutar la compilación, Buildx evalúa tus políticas frente a estas entradas. Si alguna entrada viola una política, la compilación falla antes de que se ejecute cualquier instrucción.

Las políticas se escriben en Rego, un lenguaje declarativo diseñado para expresar reglas y restricciones. No necesitas saber Rego para comenzar; este tutorial te enseña lo necesario.

Crea tu primera política

Crea un nuevo directorio para este tutorial y añade un Dockerfile:

$ mkdir tutorial-politicas
$ cd tutorial-politicas

Crea un Dockerfile que descargue un archivo con ADD:

FROM scratch
ADD https://example.com/index.html /index.html

Ahora crea un archivo de política. Las políticas usan la extensión .rego y se ubican junto a tu Dockerfile. Crea Dockerfile.rego:

Dockerfile.rego
package docker

default allow := false

allow if input.local
allow if {
  input.http.host == "example.com"
}

decision := {"allow": allow}

Guarda este archivo como Dockerfile.rego en el mismo directorio que tu Dockerfile.

Analicemos lo que hace esta política:

  • package docker - Todas las políticas de compilación deben comenzar con esta declaración de paquete
  • default allow := false - Este ejemplo utiliza una regla de denegación por defecto: si las entradas no coinciden con una regla allow, la verificación de la política falla
  • allow if input.local - La primera regla permite cualquier archivo local (tu contexto de compilación)
  • allow if { input.http.host == "example.com" } - La segunda regla permite descargas HTTP desde example.com
  • decision := {"allow": allow} - El objeto de decisión final le indica a Buildx si debe permitir o denegar la entrada

Esta política dice: "Solo permitir archivos locales y descargas HTTP desde example.com". Rego evalúa todas las reglas de la política para determinar el valor de retorno de la variable decision para cada entrada de compilación. Las evaluaciones ocurren en paralelo y bajo demanda; el orden de las reglas de la política no tiene importancia.

Acerca de input.local

Verás allow if input.local en casi todas las políticas. Esta regla permite el acceso a archivos locales, lo que incluye tu contexto de compilación (normalmente, el directorio .) y, lo que es más importante, el propio Dockerfile. Sin esta regla, Buildx no podría leer tu Dockerfile para iniciar la compilación.

Incluso las compilaciones que no hacen referencia a ningún archivo del contexto de compilación a menudo necesitan input.local porque el Dockerfile es un archivo local. La política se evalúa antes de que comience la compilación, y denegar el acceso local significa denegar el acceso al Dockerfile.

En casos poco comunes, es posible que desees políticas de archivos locales más estrictas; por ejemplo, en compilaciones de CI donde el contexto de compilación utiliza una URL de Git directamente. En estos casos, podrías querer denegar las fuentes locales para evitar que archivos sin seguimiento o cambios no registrados formen parte de tu compilación.

Carga automática de políticas

Buildx carga automáticamente las políticas que coinciden con el nombre de tu Dockerfile. Cuando compilas con Dockerfile, Buildx busca Dockerfile.rego en el mismo directorio. Para un archivo llamado app.Dockerfile, busca app.Dockerfile.rego.

Esta carga automática significa que no necesitas ninguna bandera de línea de comandos en la mayoría de los casos: simplemente crea el archivo de política y compila.

El archivo de política debe estar en el mismo directorio que el Dockerfile. Si Buildx no puede encontrar una política coincidente, la compilación continúa sin la evaluación de la política (a menos que utilices --policy strict=true).

Para obtener más control sobre la carga de políticas, consulta la Guía de uso.

Ejecuta una compilación con tu política

Compila la imagen con la evaluación de políticas habilitada:

$ docker build .

La compilación se realiza con éxito porque la URL de tu Dockerfile coincide con la política. Ahora intenta cambiar la URL en tu Dockerfile por otra cosa:

FROM scratch
ADD https://api.github.com/users/octocat /user.json

Compila de nuevo:

$ docker build .

Esta vez la compilación falla debido a una violación de la política. El nombre de host api.github.com no coincide con la regla de tu política, por lo que Buildx lo rechaza antes de ejecutar cualquier paso de compilación.

Depuración de fallas de políticas

Si tu compilación falla debido a una violación de la política, utiliza --progress=plain para ver exactamente qué salió mal:

$ docker buildx build --progress=plain .

Esto muestra todas las verificaciones de políticas, los datos de entrada para cada fuente y las decisiones de permitir/denegar. Para obtener una guía de depuración completa, consulta Depuración.

Añadir mensajes de error útiles

Cuando una política deniega una entrada, los usuarios ven un mensaje de error genérico. Puedes proporcionar mensajes personalizados que expliquen por qué se denegó la compilación:

Dockerfile.rego
package docker

default allow := false

allow if input.local
allow if {
  input.http.host == "example.com"
  input.http.schema == "https"
}

deny_msg contains msg if {
  not allow
  input.http
  msg := "solo se permiten descargas HTTPS desde example.com"
}

decision := {"allow": allow, "deny_msg": deny_msg}

Now, cuando se deniegue una compilación, los usuarios verán tu mensaje personalizado explicando qué salió mal:

$ docker buildx build .
Policy: solo se permiten descargas HTTPS desde example.com
ERROR: failed to build: ... source not allowed by policy

La regla deny_msg utiliza contains para añadir mensajes a un conjunto. Puedes añadir múltiples mensajes de denegación para diferentes condiciones de falla para ayudar a los usuarios a comprender exactamente qué debe cambiar.

Entender las reglas de Rego

Las políticas de Rego se construyen a partir de reglas. Una regla define cuándo se permite algo. El patrón básico es:

allow if {
    condition_one
    condition_two
    condition_three
}

Todas las condiciones deben ser verdaderas para que la regla coincida. Piensa en ello como una operación AND: la URL debe coincidir AND la suma de comprobación debe coincidir AND cualquier otra condición que especifiques.

Puedes tener múltiples reglas allow en una sola política. Si alguna regla coincide, la entrada se permite:

# Permitir descargas desde example.com
allow if {
    input.http.host == "example.com"
}

# También permitir descargas desde api.github.com
allow if {
    input.http.host == "api.github.com"
}

Esto funciona como un OR: la entrada puede coincidir con la primera regla OR con la segunda regla.

Acceder a los campos de entrada

El objeto input te da acceso a la información sobre las entradas de compilación. La estructura depende del tipo de entrada:

  • input.http - Archivos descargados con ADD https://...
  • input.image - Imágenes de contenedor de FROM o COPY --from
  • input.git - Repositorios de Git de ADD git://... o del contexto de compilación
  • input.local - Contexto de archivos locales

Consulta la Referencia de inputs para conocer todos los campos de entrada disponibles.

Para las descargas HTTP, puedes acceder a:

ClaveDescripciónEjemplo
input.http.urlLa URL completahttps://example.com/index.html
input.http.schemaEl protocolo (HTTP/HTTPS)https
input.http.hostEl nombre de hostexample.com
input.http.pathLa ruta de la URL, incluyendo params/index.html

Actualiza tu política para requerir HTTPS:

package docker

default allow := false

allow if {
    input.http.host == "example.com"
    input.http.schema == "https"
}

decision := {"allow": allow}

Ahora la política requiere tanto que el nombre de host sea example.com como que el protocolo sea HTTPS. Las URLs HTTP (sin TLS) fallarían la verificación de la política.

Coincidencia de patrones y cadenas

Rego proporciona funciones integradas para la coincidencia de patrones. Utiliza startswith() para hacer coincidir prefijos de URL:

allow if {
    startswith(input.http.url, "https://example.com/")
}

Esto permite cualquier URL que comience con https://example.com/.

Utiliza regex.match() para patrones complejos:

allow if {
    regex.match(`^https://example\.com/.+\.json$`, input.http.url)
}

Esto coincide con URLs que:

  • Comienzan con https://example.com/
  • Terminan con .json
  • Tienen al menos un carácter entre el dominio y la extensión

Ubicación del archivo de política

Los archivos de políticas se ubican junto al Dockerfile que validan, utilizando el patrón de nomenclatura <nombre-dockerfile>.rego:

project/
├── Dockerfile           # Dockerfile principal
├── Dockerfile.rego      # Política para Dockerfile
├── lint.Dockerfile      # Dockerfile de análisis estático (linting)
└── lint.Dockerfile.rego # Política para lint.Dockerfile

Cuando compilas, Buildx carga automáticamente el archivo de política correspondiente:

$ docker buildx build -f Dockerfile .        # Carga Dockerfile.rego
$ docker buildx build -f lint.Dockerfile .   # Carga lint.Dockerfile.rego

Siguientes pasos

Ahora comprendes cómo escribir políticas de compilación básicas para recursos HTTP. Para continuar aprendiendo: