Validación de repositorios Git
Los repositorios de Git a menudo aparecen en las compilaciones de Docker como
entradas de código fuente. La instrucción ADD puede clonar repositorios y los
contextos de compilación pueden hacer referencia a URLs de Git. Validar estas
entradas garantiza que estás realizando compilaciones a partir de fuentes de
confianza con versiones verificadas.
Esta guía te enseña a escribir políticas que valen las entradas de Git, desde la fijación básica de versiones hasta la verificación de commits y etiquetas firmados.
Requisitos previos
Debes comprender los conceptos básicos de las políticas a partir de la Introducción: la creación de archivos de políticas, la sintaxis básica de Rego y cómo se evalúan las políticas durante las compilaciones.
¿Qué son las entradas de Git?
Las entradas de Git provienen de instrucciones ADD que hacen referencia a
repositorios de Git:
# Clonar una etiqueta específica
ADD https://github.com/moby/buildkit.git#v0.26.1 /buildkit
# Clonar una rama
ADD https://github.com/user/repo.git#main /src
# Clonar un commit
ADD https://github.com/user/repo.git#abcde123 /srcEl contexto de compilación también puede ser un repositorio Git cuando compilas con:
$ docker build https://github.com/user/repo.git#main
Cada referencia de Git desencadena la evaluación de una política. Tu política puede inspeccionar las URLs de los repositorios, validar las versiones, comprobar los metadatos de los commits y verificar las firmas.
Coincidir con repositorios específicos
La política de Git más sencilla restringe qué repositorios se pueden utilizar:
package docker
default allow := false
allow if input.local
allow if {
input.git.host == "github.com"
input.git.remote == "https://github.com/moby/buildkit.git"
}
decision := {"allow": allow}Esta política:
- Deniega todas las entradas por defecto
- Permite el contexto de compilación local
- Permite únicamente el repositorio de BuildKit de GitHub
El campo host contiene el nombre de host del servidor de Git, y remote
contiene la URL completa del repositorio. Pruébalo:
FROM scratch
ADD https://github.com/moby/buildkit.git#v0.26.1 /$ docker build .
La compilación se realiza con éxito. Intenta con un repositorio diferente y fallará.
Puedes hacer coincidir múltiples repositorios con reglas adicionales:
allow if {
input.git.host == "github.com"
input.git.remote == "https://github.com/moby/buildkit.git"
}
allow if {
input.git.host == "github.com"
input.git.remote == "https://github.com/docker/cli.git"
}
decision := {"allow": allow}Pin a versiones específicas
Las etiquetas y las ramas pueden cambiar con el tiempo. Fíjalas a versiones específicas para asegurar compilaciones reproducibles:
package docker
default allow := false
allow if input.local
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
input.git.tagName == "v0.26.1"
}
decision := {"allow": allow}El campo tagName contiene el nombre de la etiqueta cuando la referencia de Git
apunta a una etiqueta. Utiliza branch para las ramas:
allow if {
input.git.remote == "https://github.com/user/repo.git"
input.git.branch == "main"
}O utiliza ref para cualquier tipo de referencia (rama, etiqueta o SHA de commit):
allow if {
input.git.ref == "v0.26.1"
}Utilizar listas de permitidos para versiones
Para repositorios en los que confías pero de los cuales deseas controlar las versiones, mantén una lista de permitidos:
package docker
default allow := false
allowed_versions = [
{"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
]
is_buildkit if {
input.git.remote == "https://github.com/moby/buildkit.git"
}
allow if {
not is_buildkit
}
allow if {
is_buildkit
some version in allowed_versions
input.git.tagName == version.tag
input.git.isAnnotatedTag == version.annotated
startswith(input.git.commitChecksum, version.sha)
}
decision := {"allow": allow}Esta política:
- Define una lista de permitidos de versiones aprobadas con metadatos
- Utiliza una regla asistente (
is_buildkit) para mejorar la legibilidad - Permite todas las entradas que no sean de BuildKit
- Para BuildKit, comprueba el nombre de la etiqueta, si es una etiqueta anotada y el SHA del commit frente a la lista de permitidos
La regla asistente hace que las políticas complejas sean más fáciles de mantener. Puedes ampliar la lista de permitidos a medida que se aprueben nuevas versiones:
allowed_versions = [
{"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
{"tag": "v0.27.0", "annotated": true, "sha": "def456"},
{"tag": "v0.27.1", "annotated": true, "sha": "789abc"},
]Validar con patrones regex
Utiliza la coincidencia de patrones para el versionado semántico (semantic versioning):
package docker
default allow := false
allow if input.local
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}
decision := {"allow": allow}Esto permite cualquier etiqueta de BuildKit que coincida con el patrón vX.Y.Z
donde X, Y y Z son números. La expresión regular (regex) garantiza que estés
utilizando versiones de lanzamiento y no etiquetas de pre-lanzamiento como
v0.26.0-rc1.
Coincidir con versiones principales (major versions):
# Solo permitir lanzamientos v0.x
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
regex.match(`^v0\.[0-9]+\.[0-9]+$`, input.git.tagName)
}Inspeccionar metadatos de commits
El objeto commit proporciona información detallada sobre los commits:
package docker
default allow := false
allow if input.local
# Comprobar el autor del commit
allow if {
input.git.remote == "https://github.com/user/repo.git"
input.git.commit.author.email == "[email protected]"
}
decision := {"allow": allow}El objeto commit incluye:
author.name: Nombre del autorauthor.email: Correo electrónico del autorauthor.when: Cuándo se creó el commitcommitter.name: Nombre del committercommitter.email: Correo electrónico del committercommitter.when: Cuándo se registró (committed) el commitmessage: Mensaje de commit
Validar mensajes de commit:
allow if {
input.git.commit
contains(input.git.commit.message, "Signed-off-by:")
}Fijar a un SHA de commit específico:
allow if {
input.git.commitChecksum == "abc123def456..."
}Requerir commits firmados
Los commits firmados con GPG demuestran la autenticidad. Comprueba las firmas de los commits:
package docker
default allow := false
allow if input.local
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
input.git.commit.pgpSignature != null
}
decision := {"allow": allow}El campo pgpSignature es null para los commits no firmados. Para los commits
firmados, contiene los detalles de la firma.
Las firmas SSH funcionan de manera similar:
allow if {
input.git.commit.sshSignature != null
}Requerir etiquetas firmadas
Las etiquetas anotadas pueden estar firmadas, lo que proporciona una garantía criptográfica de la versión:
package docker
default allow := false
allow if input.local
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
input.git.tag.pgpSignature != null
}
decision := {"allow": allow}El objeto tag solo está disponible para las etiquetas anotadas. Incluye:
tagger.name: Quién creó la etiquetatagger.email: Correo electrónico del etiquetadortagger.when: Cuándo se creó la etiquetamessage: Mensaje de la etiquetapgpSignature: Firma GPG (si está firmada)sshSignature: Firma SSH (si está firmada)
Las etiquetas ligeras (lightweight tags) no tienen un objeto tag, por lo que
esta política exige de forma efectiva etiquetas anotadas y firmadas.
Verificar firmas con claves públicas
Utiliza la función verify_git_signature() para verificar criptográficamente
las firmas de Git frente a claves públicas de confianza:
package docker
default allow := false
allow if input.local
allow if {
input.git.remote == "https://github.com/moby/buildkit.git"
input.git.tagName != ""
verify_git_signature(input.git.tag, "keys.asc")
}
decision := {"allow": allow}Esto verifica que las etiquetas de Git estén firmadas por claves contenidas en el
archivo de claves públicas keys.asc. Para configurar esto:
- Exporta las claves públicas de los mantenedores:
$ curl https://github.com/user.gpg > keys.asc - Coloca
keys.ascjunto a tu archivo de política.
La función verifica las firmas PGP en commits o etiquetas. Consulta las Funciones integradas para más detalles.
Aplicar reglas condicionales
Utiliza diferentes reglas para diferentes contextos. Permite referencias no firmadas durante el desarrollo pero exige firmas para producción:
package docker
default allow := false
allow if input.local
is_buildkit if {
input.git.remote == "https://github.com/moby/buildkit.git"
}
is_version_tag if {
is_buildkit
regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}
# Las etiquetas de versión deben estar firmadas
allow if {
is_version_tag
input.git.tagName != ""
verify_git_signature(input.git.tag, "keys.asc")
}
# Referencias sin versión permitidas en desarrollo
allow if {
is_buildkit
not is_version_tag
input.env.target != "release"
}
decision := {"allow": allow}Esta política:
- Define reglas asistentes para mejorar la legibilidad
- Requiere etiquetas de versión firmadas por los mantenedores
- Permite referencias no firmadas (ramas, commits) a menos que se esté compilando el target de lanzamiento (release)
- Utiliza
input.env.targetpara detectar el target de compilación
Compila un target de desarrollo sin firmas:
$ docker buildx build --target=dev .
Compila el target de lanzamiento, y se exigirá la firma:
$ docker buildx build --target=release .
Siguientes pasos
Ahora comprendes cómo validar repositorios Git en las políticas de compilación. Para continuar aprendiendo:
- Explora Ejemplos de políticas para conocer patrones de políticas completos
- Lee las Funciones integradas para conocer las funciones de verificación de firmas de Git
- Consulta la Referencia de inputs para conocer todos los campos de Git disponibles