En nuestra publicación anterior sobre CI/CD Pipelines, nosotros vimos Cómo hackear un CI/CD escenario que presumiblemente estaba protegido.
Recordemos nuestro punto del post anterior: empezamos con algunos pipeline que era vulnerable a Envenenado indirecto Pipeline Ejecución (I-PPE) y, para solucionarlo, decidimos dividir el pipeline En dos:
- el 1st pipeline (Build CI), seguro para D-PPE e I-PPE, verificaría el código PR, realizaría la compilación y generaría un artefacto
- El xnumxnd pipeline (Prueba CI), también seguro para D-PPE e I-PPE verificaría el código base (para evitar la modificación del script de shell) y ejecutaría los scripts originales contra el artefacto.
- Para sincronizar el CI de prueba pipeline para ejecutar DESPUÉS de la compilación CI pipeline, nosotros usamos flujo de trabajo_ejecutar desencadenar.
A esto lo denominamos Escenario n.° 3.
Si bien, como mencionamos en ese post, existen otras soluciones, decidimos implementar esta “solución” por razones pedagógicas, para poder profundizar Más información en las vulnerabilidades de CI/CD pipelines.
Después, vimos cómo hackear este escenario envenenando el artefacto. Esto es lo que llamamos Envenenamiento por artefactos, es decir, la capacidad de modificar (piratear) el pipeline lógica modificando un pipeline artefacto.
¿Cuál es el problema con este enfoque? Vimos que el problema surge cuando cualquier usuario “crea” una nueva pipeline.
Si un usuario abre un PR que contiene un nuevo pipeline, GitHub ejecutará eso pipeline (dadas algunas condiciones, como vimos en el post).
El usuario puede entonces crear un nuevo pipeline con el mismo nombre que Build CI!! Sí, es sorprendente, pero GitHub te permite crear dos pipelines con el mismo nombre!!
Cuando el usuario abre un PR con estos cambios, el nuevo" pipeline será ejecutado (cargando un artefacto envenenado) y el Implementar CI pipeline se ejecutará después de eso, lo que dará como resultado que el script de shell "modificado" sobrescriba el script de shell "original" ubicado en el pipeline espacio de trabajo. Entonces, esta “solución” no evita la vulnerabilidad I-PPE (como podemos ver a continuación)
¿Cuáles son los problemas? Al menos, hay un par de cuestiones:
- en primer lugar, ¿Cómo estar seguro de que el proceso de construcción no ha sido alterado? En este escenario, el usuario malintencionado ha podido modificar el proceso de compilación previsto utilizando su pipeline para crear un artefacto envenenado.
- En segundo lugar, ¿Cómo podemos evaluar la procedencia de un artefacto?
Estas preguntas nos lanzan a los brazos de la Certificaciones de software ¡¡dominio!!
Certificaciones de software
An certificación es un pedazo de en que representa prueba de un evento. En el mundo real, generalmente los llamamos certificaciones.
Por ejemplo, cuando un laboratorio analiza su sangre, los datos sobre la prueba se registran y certifican. Los resultados de los análisis de sangre son verificable y trazable.
Más cerca de nuestro dominio de TI, se podría adivinar cuál sería una traducción de este proceso a, por ejemplo, un proceso de compilación.
La información sobre el entorno y las herramientas del servidor de compilación, los materiales (el código fuente) y los productos/artefactos (el código binario) serían parte de dicha certificación.
Obviamente, la certificación debe ser generada por un certificador autorizado (autenticado y no repudiable) para brindar credibilidad.
Probablemente algunos de ustedes estarán pensando... ¿y cuál es el diferencia entre firmas y certificaciones?
Firmas de código y certificaciones
En un nivel alto, un firma se crea utilizando un par de claves y un artefacto. El par de claves consta de una clave pública y una clave privada.
El usuario firma un artefacto con la clave privada, y otros pueden verificar la firma con la clave pública. La clave privada debe mantenerse en secreto, pero la clave pública se distribuye ampliamente.
Se pueden utilizar firmas para demostrar que el titular de la clave privada utilizó la clave privada para firmar el artefacto.
Signatures no lo pruebes
- Los usuarios intención para firmar el artefacto (podrían haber sido engañados), o
- La intención del usuario de realizar cualquier afirmación específica sobre el artefacto
Con Atestaciones, en lugar de firmar un artefacto directamente, los usuarios crean algún tipo de documento que captura su intención detrás de firmar el artefacto y cualquier reclamaciones específicas que se realiza como parte de esta firma.
Marco de certificación integral
El marco más común es el Marco de atestación integral
- define una standard formato para certificaciones que vinculan a los sujetos, los artefactos que se describen, a metadatos autenticados sobre el artefacto.
- proporciona un conjunto de predicados predefinidos para comunicar metadatos autenticados a lo largo y ancho de las cadenas de suministro de software
Entremos en detalles sobre el formato de certificación.
An Atestación es un documento firmado digitalmente que contiene Declaraciones
La diferencia de ALLMAND LAW FIRM, PLLC Comunicado es la capa intermedia de la atestación, vinculándola a un particular Asunto e identificar inequívocamente los tipos de Predicado:
- Asunto: referencia criptográficamente segura al artefacto (generalmente a través de un hash), y
- Predicados: un conjunto de específicos reclamaciones sobre ese artefacto se conoce como Declaración. ¡Estas afirmaciones se pueden utilizar para expresar (y luego probar) cualquier cosa que se te ocurra! Pueden representar aprobación manual, procedencia de artefactos, resultados de pruebas automatizadas, un seguimiento de auditoría o más.
Cuando esta Declaración está firmada criptográficamente, se la denomina declaración Atestación
De esta manera, por ejemplo, Alice crea una Declaración sobre un artefacto y la firma usando su clave privada, creando una Atestación.
- Bob puede entonces verificar la firma en esa Certificación, permitiéndole confiar en las afirmaciones interior.
Bob puede entonces usar esas afirmaciones para decidir si se permite o no el uso de este artefacto.
¿Podrían los atestados ayudar a resolver el envenenamiento por artefactos?
Después de esta introducción a las Atestaciones, volvamos a nuestro problema. ¿Cómo pueden ayudarnos las certificaciones a resolver nuestro problema, es decir, a evitar el envenenamiento de artefactos?
El usuario malintencionado pudo crear un artefacto sin pasar por el mecanismo "oficial", es decir, utilizando su pipeline para generar el artefacto.
Sería fantástico si pudiéramos demostrar que los artefactos que se descargan se han creado con la versión oficial. pipelines. Este es sólo un ejemplo de lo que podríamos llamar “puntos de manipulación”, pero podrían haber muchos otros.
Como puede ver en la imagen de arriba, los puntos de manipulación son múltiples. De esta manera, el consumidor pipeline (Prueba CI en nuestro ejemplo) debe evaluar la integridad del proceso de construcción así como la integridad del artefacto en sí.
En nuestro ejemplo, el artefacto envenenado se creó introduciendo un nuevo artefacto (envenenado). pipeline que altera el proceso de construcción. Pero el usuario malintencionado podría haber podido:
- modificar el código después de haberlo extraído del SCM para generar un binario malicioso
- sustituir el binario correcto producido por la compilación con cualquier otro binario malicioso
- comprometer el Registro de artefactos y cargar un artefacto envenenado creado de cualquier otra manera
- etc.
Como puede ver, puede haber múltiples puntos de "manipulación".
¿Qué es importante aquí? Obviamente para proteger todos esos puntos de “manipulación”. Pero al final lo más importante es que el “consumidor” del artefacto pueda evaluar su integridad y decidir si sigue adelante o no con él.
Podemos evaluar la integridad de un artefacto en dos maneras.
Uno es evaluando la procedencia del artefacto.
Al generar un Atestación de procedencia, proporcionamos metadatos útiles (debidamente autenticados y no repudiados) sobre el artefacto. En los siguientes ejemplos, usaremos SAL Xygeni (Software Attestations Layer for Trust), el componente para generar, registrar y verificar certificaciones de software.
- name: Building ...
run: |
# mvn will compile and create target/MyApp.war
mvn clean package
- name: Generating provenance
run: |
#!/usr/bin/env bash
shopt -s expand_aliases
alias salt=$PWD/salt_pro/xygeni_salt/salt
echo " "
echo "-----------"
echo "Generating Provenance with CLI ..."
salt at slsa \
--basedir ${GITHUB_WORKSPACE}/target \
--key="${PRIVATE_KEY}" \
--public-key=${GITHUB_WORKSPACE}/Test1_public.pem \
--key-password=${KEY_PASSWD} \
--output-unsigned=${GITHUB_WORKSPACE}/cli_provenance_${PIPELINE}_unsigned.json \
--pipeline ${PIPELINE} --pretty-print \
--file ./MyApp.war
En el código anterior, puede ver que hay un paso que construye el archivo war y un segundo paso que genera el Atestación de procedencia. Para hacerlo, el pipeline utiliza la clave privada y también incluye la clave pública en la certificación.
Detrás de escena, Xygeni sal El comando almacena la atestación en un libro mayor (también conocido como registro de atestación, registro en nuestro caso pero puedes usar cualquier otro). Hecho esto, el consumidor pipeline puede incluir Xygeni Motor de verificación verificar la procedencia del artefacto y evaluar su integridad.
- name: 'Verifying the attestation'
run: |
#!/usr/bin/bash
echo " "
echo "-------"
# Calculate sha256sum for the artifact
SHA_SUM=$(sha256sum ./MyApp.war | cut -f1 -d ' ')
# Recover the attestation Id from the sha256sum
ATT_ID=$(echo $(salt -q registry search --digest sha256:$SHA_SUM --format json) | jq -r .[-1].gitoidSha256)
echo " "
echo "-------"
# Download the provenance attestation
echo "Downloading the provenance attestation ..."
salt -q reg get --id=$ATT_ID --format=json > ${GITHUB_WORKSPACE}/provenance_kk.signed.json
echo " "
echo "-------"
echo "Verifying provenance ..."
salt verify \
--basedir ${GITHUB_WORKSPACE} \
--attestation=${GITHUB_WORKSPACE}/provenance_kk.signed.json \
--public-key=${GITHUB_WORKSPACE}/Test1_public.pem \
--file ./MyApp.war
El proceso de verificación evalúa:
- La diferencia de ALLMAND LAW FIRM, PLLC el artefacto sha256sum es válido (es decir, hay una certificación sobre ese “tema”), y
- La diferencia de ALLMAND LAW FIRM, PLLC la atestación está debidamente autenticada (ha sido generado utilizando la clave privada adecuada)
Este proceso de verificación puede evaluar entonces que tanto el artefacto como la atestación son válidos.
Pero, como recordarás, en nuestro caso, el artefacto fue generado por un programa "malicioso". pipeline (es decir, no el original por una modificación pipeline). Entonces hay que seguir adelante y comprobar otro aspecto: que el artefacto ha sido generado por el “original” pipeline, ningún otro.
Para hacerlo, simplemente incluya una línea simple para verificar esa condición, por ejemplo:
echo " "
echo "-------"
# Download the provenance attestation
echo "Downloading the provenance attestation ..."
salt -q reg get --id=$ATT_ID --format=json > ${GITHUB_WORKSPACE}/provenance_kk.signed.json
WFR=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json |base64 -d | jq -r .predicate.buildDefinition.internalParameters.environment.GITHUB_WORKFLOW_REF)
echo $WFR | grep cicd_top10_3_salt\/.github\/workflows\/build.yml
Esta verificación adicional fallará si el artefacto no hubiera sido generado por nuestra “caja fuerte” pipeline.
Si el artefacto fue generado por nuestro original pipeline (cicd_top10_3_salt/.github/workflows/build.yml), el comando grep tendrá éxito; de lo contrario, fallará, rompiendo el pipeline y abortar cualquier paso posterior.
El constructor" pipeline Este es sólo un punto de manipulación que debemos comprobar pero, como se mencionó anteriormente, hay otros puntos de manipulación que debemos comprobar.
Por ejemplo, ¿Qué pasa si el código fuente ha sido manipulado después de la verificación del repositorio y antes del comando de compilación? En este caso, el código a construir no es el mismo que el almacenado en el SCM.
Comprobar este punto de manipulación es tan fácil como comprobar los hashes del material en cada paso.
SHA_ATT_MATERIAL=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json | base64 -d | jq -r .predicate.attestations[0].predicate.materials[].digest[])
SHA_STEP_MATERIAL=$(jq -r .payload ${GITHUB_WORKSPACE}/provenance_kk.signed.json | base64 -d | jq -r .predicate.attestations[3].predicate.materials[0].digest[])
Conclusiones
En resumen, un Certificación de software es una afirmación hecha sobre una pieza de software, es decir, una declaración autenticada (metadatos) sobre un artefacto de software o una colección de artefactos de software.
Las certificaciones de software son una generalización de la firma de código/artefacto sin procesar. La atestación es un documento firmado (en un formato determinado, normalmente basado en JSON) que asocia metadatos con un artefacto. Representan evidencia que vincula las entradas (materiales) y las salidas (artefactos producidos) en cada paso de construcción.
Las certificaciones proporcionan un registro verificable de los pasos realizados para crear los artefactos de software finales, incluidos los materiales de entrada para cada paso y los comandos de compilación ejecutados.
En conclusión, las certificaciones de software son un excelente mecanismo para verificar muchos aspectos diferentes de integridad de nuestro proceso de construcción.
¿Terminó la serie? ¡No te preocupes! Siéntete libre de volver a 'Envenenado Pipeline Ejecución (PPE)' o cualquier otra publicación que vuelva a despertar tu interés!
Mantente atento, profundizaremos en Más información sobre atestaciones de software y build security en futuras publicaciones del blog.





