Skip to main content

In this article

Proteja o desenvolvimento de aplicações Kubernetes com Snyk e Tilt

Escrito por

11 de janeiro de 2021

0 minutos de leitura

Desenvolver aplicações Kubernetes pode ser difícil. Muitas vezes, lidamos com arquiteturas de microsserviços cheias de componentes interdependentes, além de desenvolver a configuração do cluster para conectar tudo. Com isso, os fluxos de trabalho para iterar e testar rapidamente podem ficar complexos e difíceis de gerenciar pelas equipes de engenharia.

É aí que ferramentas como o Tilt entram em cena.

O que é o Tilt?

O Tilt é uma ferramenta incrível para quem desenvolve aplicações Kubernetes. Ele oferece um fluxo de trabalho de implantação local altamente configurável, que é atualizado em tempo real enquanto você trabalha. Em vez de gerenciar um conjunto centralizado de ambientes compartilhados por todos os desenvolvedores, o Tilt dá a cada pessoa seu próprio ambiente local, com implantações ultrarrápidas e a possibilidade de personalizar o fluxo de trabalho.

O Tilt é configurado com um Tiltfile baseado em Starlark e oferece interfaces gráfica e de linha de comando personalizáveis, além de uma API completa. Isso dá muita flexibilidade para definir seus fluxos de trabalho e as informações que você quer ver durante o desenvolvimento da aplicação. O Tilt também oferece suporte a extensões personalizadas, ampliando ainda mais as opções para configurar e executar seu ambiente de desenvolvimento.

Meu colega Shai Mendel contribuiu com uma extensão para o Tilt que permite executar o Snyk no seu Tiltfile. Recentemente, atualizei essa extensão e explorei as várias formas de integrar o Snyk aos fluxos de trabalho do Tilt. Vamos ver como funciona.

Primeiros passos

Para começar, vamos implantar um cluster Kubernetes localmente, junto com um registro. O Tilt oferece uma ferramenta que facilita muito esse processo. O Ctlptl oferece várias maneiras de executar o Kubernetes localmente, incluindo miniKube, Kind e Docker Desktop. Vou usar o Kind, que você precisa instalar primeiro.

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

Este comando implantará um cluster Kubernetes usando o Kind e também um registro no Docker local, além de configurar tudo o que o Kubernetes precisa para usá-lo. Quando o comando terminar, veremos no Docker que os dois foram implantados:

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

Em seguida, vou clonar uma aplicação de exemplo para testar. Estou usando o exemplo de Node.js oferecido pelo Tilt. Essa aplicação vem com vários Tiltfiles de exemplo que mostram as práticas recomendadas para usar o Tilt, além de uma publicação no blog que explica cada um deles.

Para este artigo, vamos usar o exemplo de Dockerfile otimizado. Veja o Tiltfile fornecido:

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', '.')

Analisando o que esse Tiltfile faz, ele usa a função docker_build para criar a imagem example-node-js-image a partir do Dockerfile desta pasta. Também cria um recurso k8s_yaml usando o arquivo kubernetes.yaml e associa a ele um k8s_resource, com encaminhamento de porta para a porta 8000. Há também um local_resource definido, que grava a hora atual em um arquivo e cria uma dependência com o k8s_resource. Isso garante que ele seja executado antes da atualização do recurso e permite medir o tempo de implantação. Saiba mais sobre todas as funções compatíveis com a API do Tilt na documentação.

Também temos um Dockerfile, que instala as dependências necessárias para a aplicação usando o 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" ]

Nossa aplicação é bem simples: um aplicativo Node.js que exibe uma página da web na porta 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)

Agora que o cluster está implantado, podemos iniciar o Tilt. Na pasta que contém nosso Tiltfile, basta executar:

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

Com o Tilt em execução no terminal, pressione a barra de espaço para abrir a interface do Tilt no navegador.

Registro de implantação em um navegador com tema escuro, mostrando a injeção de YAML no Kubernetes, o acompanhamento da implantação e os painéis de status dos serviços

O Tilt executará o Tiltfile e iniciará todos os recursos definidos. No nosso caso, isso significa criar a imagem, implantá-la no Kubernetes e configurar o encaminhamento de porta para acessar a aplicação.

Com o kubectl, podemos confirmar que o pod que executa a aplicação está em execução:

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

Agora, se acessarmos http://localhost:8000, veremos a própria aplicação:

Página do navegador mostrando três gatos de desenho sobre um raio, acima do texto “Olá, gatos!” e de informações sobre o tempo de implantação.

Com o Tilt em execução, qualquer alteração nos diretórios e arquivos monitorados fará com que o Tiltfile seja executado novamente. A aplicação será criada e reimplantada automaticamente.

Agora, vamos ver como integrar o Snyk a esse fluxo de trabalho. Se ainda não tiver feito isso, instale a Snyk CLI e crie uma conta gratuita no Snyk.

Primeiro, precisamos carregar a extensão do Snyk no 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', '.')

Ao fazer isso, você verá que o Tilt executa o Tiltfile novamente de forma automática. Na pasta da aplicação, aparecerá o diretório tilt_modules, que contém a extensão do Snyk. As extensões são, na verdade, Tiltfiles que são carregados no Tiltfile principal.

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

Com a extensão do Snyk carregada, podemos usá-la para adicionar o Snyk ao nosso fluxo de trabalho do Tilt. A extensão é compatível com os três modos disponíveis na Snyk CLI: podemos analisar contêineres, dependências de pacotes e arquivos de infraestrutura como código — neste caso, YAML do Kubernetes. Ela também foi projetada para ser o mais flexível possível, permitindo criar diferentes fluxos de trabalho no Tilt.

Vamos começar analisando nosso YAML do Kubernetes. No Tiltfile, chamamos a extensão do Snyk e a configuramos para analisar o arquivo kubernetes.yaml:

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

A extensão aceita vários argumentos. Consulte a documentação completa no README. Aqui, definimos kubernetes.yaml como alvo, especificamos uma análise de IaC, damos um nome ao recurso, definimos o modo como info e configuramos o acionamento manual. O sinalizador de modo pode ser info ou gate. No modo info, o processo sempre retorna código zero, mesmo que encontre vulnerabilidades, ou seja, não será considerado uma falha na interface do Tilt. Se definirmos o acionamento como auto, a análise será executada sempre que o Tilt detectar alterações em kubernetes.yaml. No modo manual, precisamos acioná-la pela interface do Tilt.

Depois de salvar o Tiltfile, veremos na interface do Tilt um novo link na barra lateral, chamado snyk-iac-manual.

Painel de terminal escuro mostrando as etapas de implantação do Kubernetes, o acompanhamento da atualização dos pods e os logs do servidor em execução

Esse item tem um botão de atualização, indicando que podemos executá-lo manualmente. Vamos fazer isso.

Terminal exibindo um teste do Snyk IaC que analisa um arquivo YAML do Kubernetes e lista problemas de segurança em infraestrutura como código

Ao executar a análise, vemos a Snyk CLI ser chamada para analisar kubernetes.yaml e os resultados aparecem na interface. Embora tenhamos identificado vários possíveis problemas de segurança nesse arquivo, o teste ainda aparece como concluído com sucesso, pois definimos o modo informativo. Vamos ver o que acontece se definirmos o modo como gate. No Tiltfile, altere a configuração desta verificação:

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

Assim que o Tiltfile é executado novamente, vemos na interface que o botão de atualização da verificação manual está destacado. Isso indica que ela está fora de sincronia com as outras etapas e precisa ser atualizada.

Painel de recursos da interface do Tilt ampliado, exibindo um filtro ALL e entradas recentes, incluindo “(Tiltfile)”, “example-nod...”, “deploy” e “snyk-iac-manu...”

Agora, vamos executar novamente a configuração atualizada:

Interface escura de terminal exibindo logs de implantação do Kubernetes, comandos com falha e uma lista de status dos contêineres.

Como agora definimos o recurso como gate, o Tilt o identifica como uma falha de compilação.

Agora, vamos ver as opções para integrar a análise de contêineres ao fluxo de trabalho do Tilt. É importante saber que o Tilt usa tags imutáveis. Assim, cada compilação recebe uma tag exclusiva, que também é passada ao Kubernetes. Isso acelera o processo de implantação. Saiba mais sobre os detalhes aqui.

Por padrão, ao usar a função docker_build, você verá várias dessas tags imutáveis ao consultar as imagens no 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

Isso também cria um desafio para a análise: atualmente, não há um recurso integrado que permita acessar essas tags em outros pontos do Tiltfile. Para analisar a imagem com o Snyk, precisamos saber qual é a tag.

No entanto, há algumas opções para contornar isso. O Tilt oferece uma função para definir suas próprias etapas de compilação, e podemos usá-la para desenvolver nosso fluxo de trabalho.

Primeiro, vamos configurar uma etapa de análise manual. Para isso, vamos tornar a tag da imagem mutável, fixando seu valor para que todas as compilações usem a mesma tag. Antes da implantação, o Tilt atribuirá à compilação uma nova tag imutável.

No Tiltfile, vamos remover a função docker_build e substituí-la por custom_build:

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

Aqui, vamos chamar o Docker, como faria a função docker_build, mas adicionando a variável de ambiente especial $EXPECTED_REF. Também especificamos tag=’dev’,, que o Tilt usará para definir essa variável. Depois de salvar o Tiltfile, veremos que o Tilt criou uma imagem com uma tag mutável e, em seguida, atribuiu uma nova tag:

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

Aqui, definimos como alvo a tag conhecida, especificamos o modo de contêiner, demos um nome à análise e escolhemos o modo informativo. Como o Dockerfile está no nosso diretório, também podemos incluí-lo no argumento extra_opts para receber sugestões de imagens-base.

Painel de recursos escuro com um campo de filtro e quatro recursos listados: (Tiltfile), example-nodejs, deploy e snyk-cnr-manual.

Agora, temos na barra lateral a análise manual de contêineres, que podemos executar.

Relatório de análise de vulnerabilidades de uma imagem de contêiner, com dependências testadas, número de vulnerabilidades e níveis de gravidade.

Pronto: acionamos a análise de contêineres manualmente. Mas e se quisermos executá-la automaticamente a cada compilação no Tilt? Esse cenário é um pouco mais desafiador, pois o Tilt ainda não oferece suporte muito avançado a dependências anteriores ou posteriores à compilação. Poderíamos chamar o Snyk diretamente dentro da função custom_build, mas o objetivo da extensão é oferecer uma forma flexível para que cada pessoa integre as análises do Snyk aos seus fluxos de trabalho.

Primeiro, vamos modificar nossa função custom_build. Vamos remover o argumento tag=’dev’, para que $EXPECTED_REF receba a tag imutável gerada automaticamente pelo Tilt. A cada compilação, vamos gravar essa tag em um arquivo no sistema de arquivos. Usamos printf para evitar que sejam adicionadas quebras de linha ao final da tag no arquivo. 

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

Também vamos adicionar uma função para obter a tag do arquivo. A função read_file retorna um blob, então precisamos convertê-lo em uma string e remover as quebras de linha:

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

Em seguida, vamos chamar a extensão do Snyk, definir como alvo a saída da função get_tag, configurar o acionamento como auto e criar uma dependência do arquivo no sistema de arquivos. Assim, sempre que ele for alterado, a extensão será executada.

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

Depois de salvar o Tiltfile novamente, veremos que, sempre que a compilação for executada, também vamos acionar automaticamente

a análise do Snyk.

Painel do terminal mostrando logs de implantação e uma alteração no Tiltfile que aciona uma nova verificação

Por fim, vamos analisar as dependências do código-fonte da aplicação. Como se trata de uma aplicação Node.js que usa o yarn como gerenciador de pacotes, temos na pasta um arquivo yarn.lock que mostra as versões dos módulos utilizados.

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 analisá-lo automaticamente com o Snyk para verificar se há vulnerabilidades:

snyk('.', 'oss', 'snyk-oss-auto', mode='info', trigger='auto')
Interface de terminal escura mostrando uma compilação e atualização bem-sucedidas no Tilt, com uma análise de vulnerabilidades sem caminhos vulneráveis conhecidos.

Neste caso, a aplicação é bem simples e nenhuma das dependências tem vulnerabilidades. Tudo certo!

O Tilt é realmente uma ferramenta fantástica, que pode acelerar muito o desenvolvimento local de aplicações Kubernetes baseadas em microsserviços. Além disso, oferece inúmeras opções de configuração para que você crie o fluxo de trabalho ideal para suas necessidades.

Neste artigo, vimos várias maneiras de integrar as análises do Snyk aos fluxos de trabalho do Tilt usando a extensão do Snyk para Tilt, ajudando a manter seguras suas aplicações nativas da nuvem e suas configurações. Crie uma conta gratuita no Snyk e experimente.

Comece a participar de desafios de Capture the Flag

Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.

Leia mais

blog feature ai lilac
Blog

Transforme seu backlog de vulnerabilidades em pull requests com remediação agentiva

O Evo Remediation Agent está em Open Preview e traz a resolução automatizada de dependências para o Evo Agentic AppSec. Agora, as equipes de AppSec podem executar campanhas contínuas de remediação

blog feature snyk container custom base recommendations
Blog

Conheça o Evo Agentic AppSec: segurança que acompanha o ritmo do desenvolvimento com IA

O desenvolvimento impulsionado por IA está ultrapassando os fluxos de trabalho tradicionais de segurança. O Agentic AppSec da Snyk usa agentes de segurança para encontrar, corrigir e verificar vulnerabilidades continuamente, enquanto as pessoas definem os critérios.

feature insights context
Blog

Os ataques autônomos já chegaram. A defesa precisa acompanhar o ritmo.

Os atacantes autônomos estão reduzindo o tempo disponível para a defesa. Saiba como a descoberta, a correção, a validação e a prevenção contínuas ajudam as equipes de segurança a acompanhar esse ritmo.