Skip to main content

Codefresh + Snyk = publica rápido y de forma segura

Escrito por
Headshot of Antoine Arlaud

Antoine Arlaud

11 de diciembre de 2018

0 minutos de lectura

El desarrollo de software moderno consiste en escribir código. No en compilar ni publicar, sino en desarrollar: escribimos código, hacemos merge, se compila y se publica. Es importante probar a ambos lados de la frontera del repositorio, entre el código y la parte automatizada. El objetivo es probar antes de hacer merge para que los cambios recorran el pipeline sin problemas.

Los pipelines no están pensados para que los desarrolladores probemos nuestros cambios por primera vez; sirven para impedir que nuestro código avance si no cumple los criterios para publicar la nueva versión. Es como una lista de verificación final mientras el cohete sigue en la plataforma de lanzamiento. En un mundo ideal, incluso sería un poco tarde si tuviéramos que corregir algo durante el pipeline. Preferimos hacerlo durante el desarrollo o el merge. Sin embargo, como el mundo no siempre es ideal, en general deberíamos procurar mantener los cambios en la fase de desarrollo.

Para lograrlo, prueba antes y ofrece comentarios lo más temprano posible, por ejemplo, en tu máquina o en el repositorio de código. Por supuesto, primero tendrás que crear este pipeline e integrar las pruebas necesarias. Aquí es donde entra Codefresh. Te permite crear pipelines automatizados para publicar tus aplicaciones en contenedores y en implementaciones de Kubernetes.

Estas pruebas DEBEN incluir seguridad. Es indispensable. Si no te convence, deja de leer esta publicación y habla con tu equipo de seguridad, algún colega, tus compañeros, tu grupo de Meetup o incluso con nosotros. Todos te explicaremos por qué debería importarte... aquí es donde entra Snyk.

Vamos a dedicar entre 5 y 10 minutos a crear este pipeline en Codefresh e integrar las pruebas de seguridad con Snyk. Las pruebas serán rápidas y sencillas para que podamos volver a programar y, en última instancia, publicar funcionalidades. Tanto Codefresh como Snyk tienen planes gratuitos, así que puedes seguir los pasos sin costo. También di una sesión de webinar con el equipo de Codefresh; si prefieres ver el video, puedes encontrarlo aquí.

Vamos a crear una aplicación de ejemplo en Node y publicarla en un contenedor de Docker que subiremos a Docker Hub. Desde allí, se iniciará otro pipeline que implementará el resultado como una aplicación de Kubernetes. Codefresh detectará los cambios integrados en nuestro repositorio, creará las imágenes de Docker y ejecutará las pruebas de Snyk para determinar si es seguro publicar el resultado.

Primero, repasemos brevemente las aplicaciones y los contenedores. A continuación se ilustra la estructura de una aplicación típica que se ejecuta en una infraestructura de contenedores.

El pipeline obtendrá el código fuente de mi aplicación desde mi repositorio de GitHub, lo compilará en un contenedor de Docker y luego analizará las dependencias de la aplicación y del sistema operativo en busca de problemas de seguridad antes de subirlo a Docker Hub. Si no hay vulnerabilidades, no se detendrá.

Nuestro pipeline de aplicaciones muestra las etapas desde el commit y la compilación de la aplicación hasta el análisis de dependencias, la compilación de Docker, el análisis de la imagen y su envío a Docker Hub

¡Ahora vamos a crear este pipeline de verdad!

1. Crea cuentas nuevas en Codefresh y Snyk.io.

2. Agrega un repositorio en Codefresh.

Panel de control de Repositorios de Codefresh que muestra los filtros Todos, Privados y Públicos, y un panel para agregar un nuevo repositorio.

Para esta demostración, usaremos el repositorio https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan.

Pantalla de selección de repositorio que muestra el paso 1 de 4, el repositorio snyk-playground/code y la rama master seleccionada para la primera compilación

3. Luego, selecciona Start from template como método de compilación.

Pantalla de configuración de Codefresh que muestra tres opciones para el método de compilación del repositorio: Codefresh.yml, Dockerfile y plantilla, con Dockerfile seleccionado.

Aquí usaremos una aplicación de NodeJS. Selecciónala y haz clic en Next.

IDE de Java que muestra una traza de pila del depurador y el código fuente del método getSubQuery, con abierto un panel de inspección de variables.

Por ahora usaremos la plantilla estándar. Puedes adaptarla a tus necesidades.

Vista previa de la configuración que muestra un Dockerfile editable con la configuración de Node.js, la instalación de dependencias, la copia de la aplicación y el botón Crear

Muy bien, ya agregamos nuestro nuevo repositorio. Ahora sigamos con la definición del pipeline.

Interfaz de desarrollo en Java que compara dos archivos Hello.java y muestra las diferencias en el método main y el historial de Git debajo

4. Ahora, compila el repositorio haciendo clic en Create pipeline.

Primero, definamos algunas variables de entorno necesarias. Nos aseguraremos de cifrar los secretos. Agrega una variable nueva llamada ‘SNYK_TOKEN’.

Pantalla de configuración del pipeline que muestra las variables de entorno PORT=8080 y una variable SNYK_TOKEN cifrada.

Puedes encontrar el valor en https://app.snyk.io/account.

Página de configuración de la cuenta que muestra un campo de token de API enmascarado y el botón Mostrar resaltado

Ya que estás ahí, agrega otra variable llamada SNYK_ORG y asígnale como valor la parte final de tu URL https://app.snyk.io/org/. En mi caso, es aarlaud-snyk-demo

URL del navegador que muestra app.snyk.io/org/aarlaud-snyk-demo/

Eso es todo para Snyk.

Ahora necesitaremos algunas variables de entorno adicionales para descargar la imagen del registro de Codefresh y también para subir la imagen final a Docker Hub.

Para que Codefresh pueda acceder a nuestro registro de imágenes privado, agrega las siguientes variables (consulta más detalles aquí: https://codefresh.io/docs/docs/docker-registries/codefresh-registry/#generate-cfcr-login-token):

  • CF_USER_NAME - mi nombre de usuario de Codefresh (por ejemplo, aarlaud en mi caso)

  • CFCR_ACCOUNT - en mi caso, es igual a mi nombre de usuario: aarlaud

  • CFCR_LOGIN_TOKEN: genera un token en https://g.codefresh.io/user/settings y ¡cífralo!

Para la integración con Docker Hub, guardaremos el nombre de la imagen a la que queremos subir nuestra imagen final de Docker en Hub:

IMAGE_NAME - por ejemplo, en mi caso: aarlaudsnyk/trainingapp

El conjunto de variables debería verse así:

Panel de configuración de variables de entorno que muestra las variables configuradas de puerto, Snyk, Cloud Foundry y nombre de imagen, con algunos valores cifrados

Por último, tendremos que configurar Docker en la sección Integrations de Codefresh:

Pantalla de configuración de integraciones que muestra opciones de Git, Docker Registry y Kubernetes con botones Configurar; Integraciones está resaltado en la barra lateral.

Necesitarás una cuenta de Docker Hub (https://hub.docker.com/), así que crea una si aún no tienes y configura la integración con el registro de Docker:

Vista de Snyk de un informe de vulnerabilidades que muestra problemas de dependencias, paquetes y soluciones disponibles en una interfaz tabular

Muy bien, ¡ya podemos continuar! Si revisas los activadores, verás que cada commit activará una compilación. Ten en cuenta que, como creamos este pipeline a partir de la rama master, solo los commits en master activarán la compilación. Por ahora es suficiente, y es fácil cambiarlo o duplicarlo para otras ramas y otros entornos.

Interfaz de activadores que muestra un activador de Git para el repositorio snyk-playground/codefresh-pipeline-snyk-app-do...

Si revisamos el flujo de trabajo, reconoceremos la plantilla de Docker que vimos antes. En algún momento quizá convenga trasladarla a un Dockerfile.

Formulario de compilación del flujo de trabajo que muestra un Dockerfile de plantilla de Codefresh para Node.js, con el nombre de la imagen y comandos de Docker.

Ahora, intentemos compilarlo para comprobar que funciona como esperamos antes de seguir.

Cuadro de diálogo para seleccionar la rama principal y el pipeline antes de compilar codefresh-pipeline-snyk-app-docker-scan, con el botón Build resaltado

Verás que la compilación comienza:

Panel de CVSS de Snyk que muestra una puntuación alta de 8.2 y detalles de vulnerabilidades de NVD y Red Hat, incluidos impactos altos en la integridad y la disponibilidad.

Y ahora mi aplicación ya se compiló.

Editor de código que muestra una configuración de diseño JSON con un elemento UIImage seleccionado y sus propiedades de posición.

Ahora Codefresh coloca automáticamente esta imagen en tu propio registro privado de Docker en tu cuenta de Codefresh. Si reviso la sección Images, veo mi imagen de Docker recién compilada:

Panel de imágenes que muestra un filtro por etiqueta y el registro de una imagen del repositorio con columnas de rama, confirmación, fecha, etiqueta y SHA

Además, antes de subir esta imagen a Docker Hub, quiero asegurarme de que no tenga vulnerabilidades de seguridad.

5. Volvamos al pipeline y agreguemos el comando snyk test para analizar las dependencias en busca de vulnerabilidades de seguridad.

Primero instalaremos Snyk y luego lo ejecutaremos con comandos muy simples, configurados para detenerse si encontramos problemas de gravedad alta. Por ahora, no quiero detener el proceso por problemas de gravedad baja o media, hasta que entienda mejor mi flujo de trabajo.

> npm install -g snyk
> snyk test --severity-threshold=high
Sección de pruebas unitarias que muestra comandos de terminal para instalar Snyk globalmente y ejecutar pruebas con un umbral de gravedad alto.

Haz clic en Save y luego vuelve a compilar para ejecutarlo. Verás un paso de extracción en el pipeline para Running Unit Tests. Probablemente fallará por algunos problemas. Los corregiremos más adelante. Ahora analicemos la imagen de Docker para detectar problemas en el sistema operativo de mi aplicación.

Cuando Codefresh compila la aplicación, sube la imagen a nuestro registro privado. Luego la descarga para ejecutar las pruebas unitarias. Repetiremos ese proceso para ejecutar una segunda prueba de Snyk dirigida a la imagen de Docker.

Para hacerlo, usaremos una composición de Codefresh. Consulta la documentación para obtener más detalles, pero cambiaremos a YAML para tener más opciones.

Interruptor con opciones BASIC y YAML, con YAML seleccionada

Ahora, en modo YAML, agreguemos estas 3 líneas justo después de “version: ‘1.0’”stages:

-scan
-promote

Este cambio es puramente visual: creará en la interfaz una sección similar a un contenedor. Ajustemos un poco la sección RunningUnitTests existente para que use la sección SnykAppScan. Además de cambiar los títulos, agregamos una sección de etapa para ubicarla en el contenedor correcto de la interfaz y pasamos las variables de entorno de forma más directa, simplificando algunas cosas.

SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

Ahora agreguemos una sección SnykScanImage, esta vez para analizar nuestra imagen de Docker. Aquí la etapa también es scan, así que estará en el mismo contenedor que la etapa de análisis de las dependencias de la aplicación. La documentación de composiciones mencionada permite ejecutar varios servicios para realizar las pruebas.

En nuestro caso, BuildingDockerImage será la imagen de salida de la etapa de compilación. Queremos probar esa imagen desde afuera, así que combinaremos nuestra prueba con un servicio de análisis que ejecuta otra imagen que compilé previamente: aarlaudsnyk/snyk-container-scan-docker. Esta imagen reúne las piezas necesarias para que Snyk analice una imagen de Docker. Puedes ver el código fuente aquí:

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

La sección de interés del archivo YAML anterior es:

image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"

Usamos esa imagen para ejecutar el comando de Python, que hace principalmente dos cosas:

  • Descarga la imagen para probarla localmente

  • Ejecuta ‘snyk test --docker ’

Esta imagen está diseñada para descargar la imagen del registro de Codefresh si se definen las siguientes variables de entorno

  • CFCR_ACCOUNT

  • CF_USER_NAME

  • CFCR_LOGIN_TOKEN

Esto nos permite probar la imagen recién compilada. De lo contrario, intentará descargar una imagen de Docker Hub.

Por último, agreguemos al final la publicación en el registro de Docker Hub para subir la imagen si superamos las pruebas:

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

Nada complicado: Codefresh facilita mucho la publicación en Docker Hub, siempre que se haya configurado la integración (consulta la sección anterior). Observa que la etapa es promote para distinguirla de las pruebas de análisis.

En conjunto, debería verse más o menos así

version: '1.0'
stages:
- scan
- promote
steps:
BuildingDockerImage:
title: Building Docker Image
type: build
image_name: ${{IMAGE_NAME}}
working_directory: ./
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
dockerfile:
content: |-
FROM node:8.0-alpine AS builder
WORKDIR /app
COPY package.json /app
# Creating tar of productions dependencies
RUN npm install --production && cp -rp ./node_modules /tmp/node_modules
# Installing all dependencies
RUN npm install
# Copying application code
COPY . /app
SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

6. Intentemos compilar ahora para obtener una referencia inicial. Podemos ver que nuestra organización está bastante limpia:

IDE de Angular que muestra un archivo de prueba app.component.spec.ts, el explorador del proyecto y el panel de bienvenida de Terminal+ para un proyecto de Angular 2 con TypeScript.

Al cabo de un momento, obtenemos esto

Pipeline de compilación de Codefresh que muestra un análisis de dependencias de aplicaciones de Snyk fallido y la salida de la terminal que informa una ruta vulnerable.

Uy, parece que hay algunos problemas en nuestra aplicación: el pipeline se detuvo de forma segura antes de publicar algo con problemas de seguridad. Vamos a corregirlos siguiendo los pasos de solución indicados en el resultado. Actualizar el paquete qs a la versión 6.0.4 en package.json lo resolverá.

Volvamos a ejecutarlo.

Panel del pipeline de CI que muestra las etapas predeterminada, de análisis y de promoción, con las pruebas de dependencias de Snyk completadas y sin rutas vulnerables.

¡Ya corregimos la vulnerabilidad de qs! Pero ahora tenemos un problema con las dependencias del sistema operativo en nuestra imagen de Docker.

Editor XML que muestra una factura con detalles de facturación y envío, partidas de productos, totales, comentarios y un panel flotante de esquema.

La recomendación de solución indica que actualizar la imagen sería una buena opción (consulta la sección de Docker en snyk.io/docs). Así que actualicemos a node:10-alpine y volvamos a intentarlo.

Captura de pantalla que muestra código fuente de PlantUML junto a un diseño de memoria generado y diagramas de casos de uso.

Guardar => Compilar => ¡Hacer flexiones mientras se compila!

Pipeline de Codefresh completado que muestra la clonación del repositorio, la creación de una imagen de Docker, el análisis de dependencias con Snyk y el envío a un registro de Docker

¡Excelente! Ahora tenemos una referencia inicial nueva y un pipeline totalmente funcional que publica nuestra aplicación y contenedor en Docker Hub.

Ahora podemos volver a programar. Asegurémonos de ejecutar snyk test con nuestros cambios antes de hacer merge o de probarlos con la integración de Snyk para solicitudes de extracción de GitHub. A partir de ahí, los cambios se publicarán automáticamente. ¡Y una ventaja adicional: la última incorporación!

Usa snyk monitor para supervisar tus dependencias a lo largo del tiempo. A nadie le gusta estar pendiente de sus proyectos; al ejecutar snyk monitor, Snyk nos avisará automáticamente si se divulga una nueva vulnerabilidad en alguna dependencia del proyecto o de la imagen de Docker. Solo tenemos que agregar snyk monitor después de la sección snyk test.

Editor de configuración YAML que muestra YAML en línea seleccionado, un botón Importar desde un archivo y el comando “snyk monitor” resaltado.

Luego verás en el resultado la URL de la instantánea para supervisar:

Salida de terminal que muestra la URL de una instantánea de monitoreo de una aplicación y notificaciones sobre problemas de dependencias recién divulgados.

La parte de Docker se hará automáticamente si snyk test se ejecuta correctamente (es decir, si no hay problemas conocidos). También se proporcionan enlaces a las instantáneas de supervisión.

Salida de terminal que muestra a Snyk monitoreando una aplicación de capacitación y notificando a los usuarios sobre problemas de dependencias divulgados recientemente

También puedes ver los proyectos supervisados en la interfaz de Snyk, dentro de tu organización de Snyk:

Panel de Snyk Projects que muestra dos repositorios con el número de vulnerabilidades y menús desplegables «Probar a diario»

Consulta el pipeline de Codefresh haciendo clic en la insignia del repositorio (https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan).

¡Eso es todo, amigos! ¡Mantente seguro!

Empieza con Capture the Flag

Aprende a resolver desafíos de Capture the Flag viendo nuestro taller virtual introductorio a pedido.

Publicado en:

Leer más

feature insights context
Blog

Los ataques autónomos ya están aquí. La defensa debe estar a su altura.

Los atacantes autónomos están reduciendo el tiempo disponible para defenderse. Descubre cómo el descubrimiento, la corrección, la validación y la prevención continuos pueden ayudar a los equipos de seguridad a seguirles el ritmo.

Blog

Evo ADS Govern Agent Behavior ya está disponible: controla el uso de MCP

Evo ADS Govern Agent Behavior ya está disponible, comenzando con MCP Governance. Descubre, aprueba, monitorea, registra y bloquea el uso de servidores MCP en los principales agentes de programación con IA.

illustration hero ai
Blog

¿Qué es Agentic AppSec?

Descubre cómo Agentic AppSec usa agentes de IA con contexto, límites definidos y verificación independiente para ejecutar el ciclo de seguridad de aplicaciones.