Skip to main content

In this article

Protege el desarrollo de tus aplicaciones de Kubernetes con Snyk y Tilt

Escrito por

11 de enero de 2021

0 minutos de lectura

Desarrollar aplicaciones de Kubernetes puede ser difícil. A menudo trabajamos con arquitecturas de microservicios que tienen muchas piezas en movimiento, además de desarrollar la configuración del clúster para conectarlas y crear flujos de trabajo de iteración y pruebas rápidas. Todo esto puede volverse complicado y difícil de gestionar para los equipos de ingeniería.

Aquí es donde entran en juego herramientas como Tilt.

¿Qué es Tilt?

Tilt es una excelente herramienta para desarrolladores que trabajan con aplicaciones de Kubernetes. Ofrece un flujo de trabajo de implementación local altamente configurable que se actualiza en tiempo real mientras trabajas. En lugar de administrar un conjunto centralizado de entornos en los que trabaja todo el equipo, Tilt ofrece a cada desarrollador su propio entorno local, con implementaciones muy rápidas y la posibilidad de personalizar su flujo de trabajo.

Tilt se configura mediante un archivo Tilftfile basado en Starlark y ofrece una interfaz gráfica y un entorno de CLI personalizables, junto con una API completa. Esto te da mucha flexibilidad para definir tus flujos de trabajo y la información que quieres ver mientras desarrollas tu aplicación. Tilt también admite extensiones personalizadas, lo que te ofrece aún más opciones para configurar y ejecutar tu entorno de desarrollo.

Mi colega Shai Mendel contribuyó una extensión para Tilt que permite ejecutar Snyk desde tu Tiltfile. Hace poco dediqué algo de tiempo a actualizar la extensión y explorar las distintas formas en que Snyk puede integrarse en tus flujos de trabajo de Tilt. Veamos cómo funciona.

Cómo empezar

Lo primero que queremos hacer es implementar un clúster de Kubernetes localmente, junto con un registro. Tilt ofrece una herramienta que facilita mucho esta tarea. Ctlptl admite varias formas de ejecutar Kubernetes localmente, como miniKube, Kind y Docker Desktop. Yo usaré Kind, que primero debes instalar.

matt@Mattbook kind % brew install tilt-dev/tap/ctlptl
matt@Mattbook kind % ctlptl create cluster kind --registry=ctlptl-registry

Este comando implementará un clúster de Kubernetes con Kind y también implementará un registro en tu Docker local, además de configurar todo lo necesario para que Kubernetes lo use. Cuando el comando termine, podremos ver en Docker que se implementaron ambos:

matt@Mattbook 2-optimized-dockerfile % docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                       NAMES
2f38ce48a6c9   kindest/node:v1.19.1   "/usr/local/bin/entr…"   2 minutes ago   Up 2 minutes   127.0.0.1:61091->6443/tcp   kind-control-plane
e61df5496e19   registry:2             "/entrypoint.sh /etc…"   3 minutes ago   Up 3 minutes   0.0.0.0:60923->5000/tcp     ctlptl-registry

A continuación, clonaré una aplicación de ejemplo para usarla en las pruebas. Usaré el ejemplo de Node.js que ofrece Tilt. Esta aplicación incluye varios Tiltfiles de ejemplo con buenas prácticas para usar Tilt, además de una publicación de blog que los explica

Para esta publicación, usaremos el ejemplo de Dockerfile optimizado. Veamos el Tiltfile proporcionado:

matt@Mattbook 2-optimized-dockerfile % cat Tiltfile 
# -*- mode: Python -*

k8s_yaml('kubernetes.yaml')
k8s_resource('example-nodejs', port_forwards=8000,
    resource_deps=['deploy']
)

# Records the current time, then kicks off a server update.
# Normally, you would let Tilt do deploys automatically, but this
# shows you how to set up a custom workflow that measures it.
local_resource(
    'deploy',
    'python now.py > start-time.txt',
)

docker_build('example-nodejs-image', '.')

Si analizamos lo que hace este Tiltfile, usa la función docker_build para crear example-node-js-image a partir del Dockerfile de esta carpeta. También crea un recurso k8s_yaml mediante el archivo kubernetes.yaml y lo asocia con un recurso k8s_resource, con un reenvío de puerto al puerto 8000. También define un recurso local_resource, que escribe la hora actual en un archivo y crea una dependencia entre este y k8s_resource. Esto significa que siempre se ejecutará antes de actualizar el recurso y permite medir el tiempo de implementación. Puedes leer más sobre todas las funciones que admite la API de Tiltfile en la documentación.

También tenemos un Dockerfile que instala las dependencias que necesita nuestra aplicación con yarn:

matt@Mattbook 2-optimized-dockerfile % cat Dockerfile 
FROM node:10

WORKDIR /app

ADD package.json .
ADD yarn.lock .
RUN yarn install

ADD . .

ENTRYPOINT [ "node", "/app/index.js" ]

Y nuestra aplicación es una aplicación de Node.js muy sencilla que solo muestra una página web en el puerto 8000:

matt@Mattbook 2-optimized-dockerfile % cat index.js 
/*
 Gratefully adapted from https://github.com/HemingwayLee/sample-mustache-express
*/const fs = require('fs');

const express = require('express');
const app = express();
const mustacheExpress = require('mustache-express');

let timeSince = 'N/A';

app.engine('mustache', mustacheExpress());

app.set('view engine', 'mustache');
app.set('views', __dirname + '/views');
app.use(express.static('public'));

app.get('/', (req, res) => {
    res.render('index.mustache', {
        time: timeSince,
    });
});

app.listen(8000, () => {
    timeSince = getSecsSinceDeploy();
    console.log('Server running at http://localhost:8000/');
});

function getSecsSinceDeploy() {
    let curTimeMs = new Date().getTime();
    let contents = fs.readFileSync('/app/start-time.txt', 'utf8');
    let startTimeMs  = parseInt(contents.trim()) / 10**6;
    return ((curTimeMs - startTimeMs) / 10**3).toFixed(2)

Ahora que implementamos el clúster, podemos iniciar Tilt. Desde la carpeta que contiene nuestro Tiltfile, solo tenemos que ejecutar:

matt@Mattbook 2-optimized-dockerfile % tilt up
Tilt started on http://localhost:10350/
v0.17.13, built 2020-12-02

(space) to open the browser
(s) to stream logs (--stream=true)
(t) to open legacy terminal mode (--legacy=true)
(ctrl-c) to exit

Con Tilt ejecutándose en la terminal, podemos presionar la barra espaciadora para abrir la interfaz de Tilt en el navegador.

Registro de implementación oscuro en el navegador que muestra la inyección de YAML de Kubernetes, el seguimiento del despliegue y los paneles de estado del servicio

Tilt ejecutará el Tiltfile y activará todos los recursos definidos; en nuestro caso, creará la imagen, la implementará en Kubernetes y creará un reenvío de puerto para acceder a la aplicación.

Con kubectl podemos ver que el pod que ejecuta la aplicación está en ejecución:

matt@Mattbook snyk % kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
example-nodejs-7577d84888-d6q5t   1/1     Running   0          3m6s

Si ahora vamos a http://localhost:8000, podremos ver la aplicación:

Página del navegador que muestra tres gatos caricaturizados sobre un rayo, encima del texto “¡Hola, gatos!” y la información sobre los tiempos de implementación.

Una vez que Tilt está en ejecución, cualquier cambio que hagamos en los directorios y archivos supervisados volverá a ejecutar el Tiltfile y creará e implementará automáticamente la aplicación.

Ahora veamos cómo integrar Snyk en este flujo de trabajo. Si aún no lo hiciste, tendrás que instalar la CLI de Snyk y registrarte para obtener una cuenta gratuita de Snyk.

Lo primero que debemos hacer es cargar la extensión de Snyk, lo cual hacemos en el Tiltfile:

# -*- mode: Python -*

load('ext://snyk', 'snyk')

k8s_yaml('kubernetes.yaml')
k8s_resource('example-nodejs', port_forwards=8000,
    resource_deps=['deploy']
)

# Records the current time, then kicks off a server update.
# Normally, you would let Tilt do deploys automatically, but this
# shows you how to set up a custom workflow that measures it.
local_resource(
    'deploy',
    'python now.py > start-time.txt',
)

docker_build('example-nodejs-image', '.')

Al hacerlo, verás que Tilt vuelve a ejecutar el Tiltfile automáticamente. En la carpeta de nuestra aplicación aparecerá un directorio tilt_modules que contiene la extensión de Snyk. Las extensiones son Tiltfiles que se cargan en el Tiltfile principal.

matt@Mattbook 2-optimized-dockerfile % ls tilt_modules 
extensions.json snyk

Ahora que cargamos la extensión de Snyk, podemos usarla para agregar Snyk a nuestro flujo de trabajo de Tilt. La extensión admite los tres modos disponibles en la CLI de Snyk, así que podemos analizar contenedores, dependencias de paquetes y archivos de infraestructura como código, en este caso, archivos YAML de Kubernetes. Además, está diseñada para ofrecer la mayor flexibilidad posible y permitirte crear distintos flujos de trabajo en Tilt.

Primero, veamos cómo analizar nuestro YAML de Kubernetes. En el Tiltfile, llamamos a la extensión de Snyk y la configuramos para analizar el archivo kubernetes.yaml:

snyk('kubernetes.yaml', 'iac', 'snyk-iac-manual', mode='info', trigger=’manual’)

La extensión admite varios argumentos; puedes consultar toda la documentación en el README. Aquí seleccionamos kubernetes.yaml, especificamos que queremos un análisis de IaC, asignamos un nombre a este recurso, definimos el modo como informativo y configuramos el activador como manual. La marca de modo puede ser info o gate. En el modo info, el comando siempre termina con un código de retorno cero, incluso si encuentra vulnerabilidades, por lo que no se considera un error en la interfaz de Tilt. Si configuramos el activador como auto, el análisis se ejecutará cada vez que Tilt detecte cambios en kubernetes.yaml. En el modo manual, tendremos que iniciarlo desde la interfaz de Tilt.

Cuando guardamos el Tiltfile, vemos un nuevo enlace en la barra lateral de la interfaz de Tilt, titulado snyk-iac-manual.

Panel de terminal oscuro que muestra los pasos de implementación de Kubernetes, el seguimiento del despliegue de pods y los registros del servidor en ejecución

Esta opción tiene un botón de actualizar, lo que indica que podemos ejecutarla manualmente. Vamos a hacerlo.

Terminal que muestra una prueba de Snyk IaC analizando un archivo YAML de Kubernetes y enumerando problemas de seguridad de infraestructura como código

Al ejecutarla, vemos que se llama a la CLI de Snyk para analizar kubernetes.yaml y que los resultados del análisis aparecen en la interfaz. Aunque identificamos varios posibles problemas de seguridad en ese archivo, la prueba sigue apareciendo como completada correctamente porque configuramos el modo informativo. Veamos qué ocurre si lo configuramos en modo gate. En el Tiltfile, cambia la configuración de esta comprobación:

snyk('kubernetes.yaml', 'iac', 'snyk-iac-manual', mode='gate', trigger='manual')

Lo primero que vemos en la interfaz después de que se vuelve a ejecutar el Tiltfile es que el botón de actualizar de nuestra comprobación manual está resaltado, lo que significa que no está sincronizada con las demás etapas y hay que actualizarla.

Panel de recursos de la interfaz de Tilt ampliado que muestra un filtro ALL y entradas recientes, como “(Tiltfile)”, “example-nod...”, “deploy” y “snyk-iac-manu...”

Ahora volvamos a ejecutar la configuración actualizada:

Interfaz oscura de terminal que muestra registros de implementación de Kubernetes, comandos fallidos y una lista de estados de contenedores.

Como ahora configuramos el recurso en modo gate, Tilt lo detecta como un error de compilación.

Ahora veamos las opciones para integrar el análisis de contenedores en nuestro flujo de trabajo de Tilt. Algo importante que debes tener en cuenta es que Tilt usa etiquetas inmutables. Por eso, cada compilación recibe una etiqueta única que también se transfiere a Kubernetes. Esto acelera el proceso de implementación. Puedes leer más detalles aquí.

De forma predeterminada, al usar la función docker_build, verás muchas de estas etiquetas inmutables al consultar las imágenes en Docker:

matt@Mattbook 2-optimized-dockerfile % docker images
REPOSITORY                             TAG                     IMAGE ID       CREATED          SIZE
localhost:60923/example-nodejs-image   tilt-d30fcbf90266f17c   d30fcbf90266   2 minutes ago    918MB
localhost:60923/example-nodejs-image   tilt-7285dc3648babacf   7285dc3648ba   6 minutes ago    918MB
localhost:60923/example-nodejs-image   tilt-b897a2c5ce4f7431   b897a2c5ce4f   10 minutes ago   918MB
localhost:60923/example-nodejs-image   tilt-a470f2969ce1ee4c   a470f2969ce1   11 minutes ago   918MB
localhost:60923/example-nodejs-image   tilt-9d3e699a8bfe9d37   9d3e699a8bfe   24 minutes ago   918MB
localhost:60923/example-nodejs-image   tilt-2a3065202354b6c4   2a3065202354   26 minutes ago   918MB
localhost:60923/example-nodejs-image   tilt-33de7ba78c394971   33de7ba78c39   34 minutes ago   918MB

Esto también plantea un desafío a la hora de analizarlas, ya que actualmente no hay una función integrada que permita acceder a estas etiquetas desde otras partes del Tiltfile, y necesitamos conocer la etiqueta de la imagen para analizarla con Snyk.

Sin embargo, tenemos un par de opciones para hacerlo. Tilt ofrece una función para definir tus propios pasos de compilación, que podemos usar para crear nuestro flujo de trabajo.

Primero, veamos cómo configurar un paso de análisis manual. Para ello, haremos que la etiqueta de nuestra imagen sea mutable: fijaremos la etiqueta para que todas nuestras compilaciones tengan la misma. Luego, Tilt volverá a etiquetar la compilación con una etiqueta inmutable antes de implementarla.

En nuestro Tiltfile, eliminemos la función docker_build y reemplazémosla por una custom_build:

custom_build('example-nodejs-image', 'docker build -t $EXPECTED_REF .', ['.'], tag='dev')

Aquí llamaremos a Docker, igual que lo haría la función docker_build, pero agregaremos la variable de entorno especial $EXPECTED_REF y también especificamos tag=’dev’,, que Tilt usará para asignar un valor a esa variable. Cuando guardemos el Tiltfile, veremos que Tilt creó una imagen con una etiqueta mutable y luego le asignó otra etiqueta:

matt@Mattbook 2-optimized-dockerfile % docker images
REPOSITORY                             TAG                     IMAGE ID       CREATED          SIZE
example-nodejs-image                   dev                     ffea1aaff7dd   10 seconds ago   918MB
localhost:60923/example-nodejs-image   tilt-ffea1aaff7ddcc22   ffea1aaff7dd   10 seconds ago   918MB

Aquí definimos como destino la etiqueta conocida, especificamos el modo de contenedor, asignamos un nombre al análisis, definimos el modo como informativo y, como tenemos el Dockerfile en nuestro directorio, también podemos agregarlo al argumento extra_opts para obtener sugerencias sobre la imagen base.

Panel oscuro de recursos que muestra un campo de filtro y cuatro recursos en la lista: (Tiltfile), example-nodejs, deploy y snyk-cnr-manual.

Ahora tenemos el análisis manual de contenedores en la barra lateral y podemos ejecutarlo.

Informe de análisis de vulnerabilidades de una imagen de contenedor que muestra las dependencias evaluadas, el número de vulnerabilidades y los niveles de gravedad.

Ya iniciamos manualmente el análisis de contenedores, pero ¿qué pasa si queremos que se ejecute automáticamente en cada compilación de Tilt? Este caso es un poco más complicado, ya que Tilt no ofrece una gestión muy desarrollada de las dependencias previas o posteriores a la compilación. Podríamos llamar a Snyk directamente desde la función custom_build, pero el objetivo de diseño de la extensión es ofrecer a los usuarios una forma flexible de integrar los análisis de Snyk en sus flujos de trabajo.

Primero, modifiquemos nuestra función custom_build. Quitaremos el argumento tag=’dev’, con lo que $EXPECTED_REF recibirá la etiqueta inmutable que Tilt genera automáticamente. Luego, en cada compilación, tomaremos esa etiqueta y la escribiremos en un archivo en nuestro sistema de archivos. Usamos printf para evitar que se agreguen saltos de línea al final de la etiqueta cuando la escribimos en el archivo. 

custom_build('example-nodejs-image', 'docker build -t $EXPECTED_REF . && printf $EXPECTED_REF > /tmp/ref.txt', ['.'])

También agregaremos una función para obtener la etiqueta del archivo. La función read_file devuelve un blob, así que tenemos que convertirlo en una cadena y quitar los saltos de línea:

def get_tag ():
return str(read_file('/tmp/ref.txt', default=''))

Luego llamaremos a la extensión de Snyk, configuraremos el destino con el resultado de nuestra función get_tag, estableceremos el activador en auto y crearemos una dependencia del archivo en el sistema de archivos para que la extensión se ejecute cada vez que cambie.

snyk(get_tag(), 'container', 'snyk-cnr-auto', test_deps='ref.txt', mode='info', extra_opts='--file=Dockerfile', trigger='auto')

Cuando volvemos a guardar el Tiltfile, vemos que cada vez que se ejecuta nuestra compilación, también se inicia automáticamente el

análisis de Snyk.

Panel de terminal que muestra registros de implementación y un cambio en Tiltfile que activa un nuevo análisis

Por último, veamos cómo analizar las dependencias del código fuente de nuestra aplicación. Como se trata de una aplicación de Node.js que usa yarn como administrador de paquetes, tenemos un archivo yarn.lock en la carpeta que muestra las versiones de los módulos que usamos.

matt@Mattbook 2-optimized-dockerfile % ls
Dockerfile Tiltfile index.js kubernetes.yaml now.py package.json public ref.txt start-time.txt tilt_modules views yarn.lock

Podemos analizarlo automáticamente con Snyk para buscar vulnerabilidades:

snyk('.', 'oss', 'snyk-oss-auto', mode='info', trigger='auto')
Interfaz de terminal oscura que muestra una compilación y actualización exitosas en Tilt, con un análisis de vulnerabilidades que no detecta rutas vulnerables conocidas

En este caso, la aplicación es muy sencilla y ninguna de sus dependencias tiene vulnerabilidades, así que todo está bien.

Tilt es una herramienta fantástica que puede acelerar considerablemente el desarrollo local de aplicaciones basadas en microservicios para Kubernetes. Además, ofrece muchísimas opciones de configuración para que puedas crear el flujo de trabajo que mejor se adapte a ti.

En esta publicación, vimos las distintas formas de integrar los análisis de Snyk en tus flujos de trabajo de Tilt mediante la extensión de Snyk para Tilt, para garantizar la seguridad de tus aplicaciones nativas de la nube y sus configuraciones. Regístrate para obtener una cuenta gratuita de Snyk y pruébala.

Empieza con Capture the Flag

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

Leer más

blog feature snyk container custom base recommendations
Blog

Presentamos Evo Agentic AppSec: seguridad al ritmo del desarrollo con IA

El desarrollo impulsado por IA supera el ritmo de los flujos de trabajo de seguridad tradicionales. Agentic AppSec de Snyk usa agentes de seguridad para encontrar, corregir y verificar vulnerabilidades de forma continua, mientras las personas definen el estándar.

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

Por qué los agentes de programación con IA siguen generando fallas de control de acceso

Los agentes de programación con IA pueden generar lógica de autorización que compila y supera la revisión, pero expone los datos de un inquilino a otro. Descubre por qué es difícil detectar el control de acceso roto y cómo prevenirlo.