Skip to main content

Codefresh + Snyk = entregue com rapidez e segurança

Escrito por
Headshot of Antoine Arlaud

Antoine Arlaud

11 de dezembro de 2018

0 minutos de leitura

O desenvolvimento moderno de software é escrever código. Não é construir, nem entregar, mas desenvolver: escrevemos código, fazemos merge, a compilação acontece e a entrega também. É importante testar dos dois lados da fronteira do repositório, entre o código e a parte automatizada. A ideia é testar antes do merge para que as alterações passem pelo pipeline sem problemas.

Os pipelines não existem para nós, desenvolvedores, testarmos nossas alterações pela primeira vez. Eles servem para impedir a entrega quando nosso código não atende aos critérios da nova versão. É como uma lista de verificação final enquanto o foguete ainda está na plataforma de lançamento. No mundo ideal, corrigir problemas durante o pipeline já seria um pouco tarde demais. Preferimos fazer isso durante o desenvolvimento e/ou o merge. Mas, como nem sempre vivemos em um mundo ideal, devemos tentar manter as alterações na fase de desenvolvimento, como regra geral.

Para isso, teste mais cedo e obtenha feedback o mais à esquerda possível, por exemplo, na sua máquina ou no repositório de código. É claro que você ainda precisará criar o pipeline e integrar os testes necessários. É aí que entra o Codefresh. Com ele, você cria pipelines automatizados para entregar seus aplicativos em contêineres e implantações no Kubernetes.

Esses testes PRECISAM incluir segurança. Isso é indispensável. Se você não está convencido, pare de ler esta publicação e converse com sua equipe de segurança, um colega, seus pares, um grupo de meetup ou até mesmo com a gente. Vamos explicar por que isso deve ser importante para você... e é aí que entra o Snyk.

Vamos levar de 5 a 10 minutos para criar esse pipeline no Codefresh e integrar os testes de segurança com Snyk. Os testes serão rápidos e simples para podermos voltar a programar e, por fim, entregar funcionalidades. Codefresh e Snyk têm planos gratuitos, então você pode acompanhar sem pagar nada. Também participei de um webinar com o pessoal do Codefresh. Se preferir assistir ao vídeo, confira aqui.

Vamos criar um aplicativo Node de exemplo e empacotá-lo em um contêiner Docker, que enviaremos ao Docker Hub. Em seguida, outro pipeline será iniciado e implantará o resultado como um aplicativo Kubernetes. O Codefresh detectará as alterações integradas ao nosso repositório, criará as imagens Docker e executará os testes do Snyk para determinar se é seguro seguir com a entrega do resultado.

Antes, vamos fazer uma breve introdução a aplicativos e contêineres. A ilustração abaixo mostra a estrutura de um aplicativo típico executado em uma infraestrutura de contêineres.

O pipeline buscará o código-fonte do meu aplicativo no repositório do GitHub, criará um contêiner Docker e testará as dependências do aplicativo e do sistema operacional em busca de problemas de segurança antes de enviar a imagem ao Docker Hub. Se não houver vulnerabilidades, o pipeline não será interrompido.

Nosso pipeline de aplicativos mostra as etapas, do commit e build do app à análise de dependências, ao build da imagem Docker, à análise da imagem e ao envio para o Docker Hub

Agora, vamos criar esse pipeline de verdade!

1. Crie contas no Codefresh e no Snyk.io.

2. Adicione um repositório no Codefresh.

Painel de repositórios do Codefresh com os filtros All, Private e Public e uma seção para adicionar um novo repositório.

Nesta demonstração, vamos usar o repositório https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan.

Tela de seleção do repositório mostrando a Etapa 1 de 4, o repositório snyk-playground/code e a branch master selecionada para a primeira compilação

3. Em seguida, selecione Start from template como método de build.

Tela de configuração do Codefresh mostrando três opções de método de build do repositório: Codefresh.yml, Dockerfile e template, com Dockerfile selecionado.

Aqui, vamos usar um aplicativo NodeJS. Selecione essa opção e clique em avançar.

IDE Java exibindo um rastreamento de pilha do depurador e o código-fonte do método getSubQuery, com o painel de inspeção de variáveis aberto.

Por enquanto, vamos usar o template padrão. Fique à vontade para ajustá-lo às suas necessidades.

Prévia da configuração mostrando um Dockerfile editável com a configuração do Node.js, a instalação de dependências, a cópia do aplicativo e o botão Criar

Certo, adicionamos o novo repositório. Agora vamos definir o pipeline.

Interface de desenvolvimento Java comparando dois arquivos Hello.java, mostrando as diferenças no método main e o histórico do Git abaixo

4. Agora, crie o repositório clicando em Create pipeline.

Primeiro, vamos definir algumas variáveis de ambiente necessárias. Não se esqueça de criptografar os segredos. Adicione uma variável chamada ‘SNYK_TOKEN’.

Tela de configuração do pipeline mostrando as variáveis de ambiente PORT=8080 e uma variável SNYK_TOKEN criptografada.

Você encontra o valor em https://app.snyk.io/account.

Página de configurações da conta mostrando um campo de token de API oculto e o botão Mostrar em destaque

Aproveite e adicione outra variável chamada SNYK_ORG. Use como valor a parte final do seu URL: https://app.snyk.io/org/. No meu caso, é aarlaud-snyk-demo.

URL do navegador mostrando app.snyk.io/org/aarlaud-snyk-demo/

Isso é tudo no Snyk.

Agora, precisaremos de mais algumas variáveis de ambiente para buscar a imagem no registro do Codefresh e também enviar a imagem final ao Docker Hub.

Para que o Codefresh acesse nosso registro privado de imagens, adicione as variáveis a seguir (veja mais detalhes aqui: https://codefresh.io/docs/docs/docker-registries/codefresh-registry/#generate-cfcr-login-token):

  • CF_USER_NAME - meu nome de usuário do Codefresh (por exemplo, aarlaud no meu caso)

  • CFCR_ACCOUNT - no meu caso, é igual ao meu nome de usuário: aarlaud

  • CFCR_LOGIN_TOKEN - gere um token em https://g.codefresh.io/user/settings e criptografe-o!

Para integrar com o Docker Hub, vamos armazenar o nome da imagem que queremos enviar ao Hub:

IMAGE_NAME - por exemplo, no meu caso: aarlaudsnyk/trainingapp

O conjunto de variáveis deve ficar parecido com este:

Painel de configurações de variáveis de ambiente exibindo variáveis configuradas de porta, Snyk, Cloud Foundry e nome da imagem, com alguns valores criptografados

Por fim, precisamos configurar o Docker na seção Integrations do Codefresh:

Tela de configurações de integrações mostrando opções de Git, Docker Registry e Kubernetes com botões Configurar; Integrações está destacado na barra lateral.

Você precisa ter uma conta no Docker Hub (https://hub.docker.com/). Crie uma, caso ainda não tenha, e configure a integração com o registro Docker:

Relatório de vulnerabilidades do Snyk View, com problemas de dependências, pacotes e correções disponíveis em uma interface tabular

Certo, agora podemos continuar! Se você conferir os gatilhos, verá que cada commit inicia um build. Como criamos este pipeline a partir do branch master, somente os commits no master vão iniciar o build. Por enquanto, isso é suficiente e é fácil alterar ou duplicar a configuração para outros branches e ambientes.

Interface de acionadores mostrando um acionador Git para o repositório snyk-playground/codefresh-pipeline-snyk-app-do...

Ao analisar o fluxo de trabalho, reconhecemos o template Docker que vimos antes. Talvez, em algum momento, seja melhor transferi-lo para um Dockerfile.

Formulário de criação de workflow mostrando um Dockerfile de modelo do Codefresh para Node.js, com o nome da imagem e comandos Docker.

Agora, vamos tentar fazer o build para verificar se tudo funciona como esperado antes de prosseguir.

Caixa de diálogo para selecionar a branch principal e o pipeline antes de compilar codefresh-pipeline-snyk-app-docker-scan, com o botão Build em destaque

Você verá o build começar:

Painel CVSS da Snyk mostrando uma pontuação alta de 8,2 e detalhes de vulnerabilidades da NVD e da Red Hat, incluindo alto impacto na integridade e na disponibilidade.

E agora o build do meu aplicativo foi concluído.

Editor de código exibindo uma configuração de layout JSON, com um elemento UIImage selecionado e suas propriedades de posicionamento.

O Codefresh agora coloca automaticamente essa imagem no seu próprio registro privado do Docker, na sua conta do Codefresh. Na seção Images, vejo a imagem Docker que acabei de criar:

Painel de imagens mostrando um filtro por tags e um registro de imagem do repositório com colunas de branch, commit, data, tag e SHA

Além disso, antes de simplesmente enviar essa imagem ao Docker Hub, quero garantir que ela não tenha vulnerabilidades de segurança.

5. Voltando ao pipeline, vamos adicionar um comando snyk test para verificar as dependências em busca de vulnerabilidades de segurança.

Primeiro, vamos instalar o Snyk e executá-lo com comandos simples, configurados para interromper o pipeline se houver problemas de alta gravidade. Por enquanto, não quero interrompê-lo por problemas de gravidade baixa ou média, até entender melhor meu fluxo de trabalho.

> npm install -g snyk
> snyk test --severity-threshold=high
Seção de testes unitários mostrando comandos de terminal para instalar o Snyk globalmente e executar testes com um limite de alta gravidade.

Clique em Save e faça o build novamente para executá-lo. Você verá uma etapa extra no pipeline, chamada Running Unit Tests. Provavelmente, ela vai falhar devido a alguns problemas. Vamos corrigi-los depois. Agora, vamos analisar a própria imagem Docker em busca de problemas no componente de sistema operacional do aplicativo.

Quando o Codefresh cria o aplicativo, ele envia a imagem ao nosso registro privado. Depois, busca a imagem para executar os testes unitários. Vamos repetir esse processo para executar um segundo teste do Snyk, desta vez direcionado à imagem Docker.

Para isso, vamos usar uma composição do Codefresh. Consulte a documentação para mais detalhes. Vamos mudar para YAML para ter mais recursos.

Seletor com as opções BASIC e YAML, com YAML selecionado

Agora, no modo YAML, vamos adicionar estas três linhas logo depois de “version: ‘1.0’”: stages:

-scan
-promote

Essa alteração é puramente visual: ela cria uma seção parecida com uma categoria na interface. Vamos ajustar a seção RunningUnitTests que já temos para usar a seção SnykAppScan. Além de mudar os títulos, adicionamos uma seção de estágio para colocar essa etapa na categoria correta da interface e passamos as variáveis de ambiente de forma mais direta, simplificando algumas coisas.

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

Agora, vamos adicionar uma seção SnykScanImage para analisar nossa imagem Docker. O estágio também é scan, então essa etapa fica na mesma categoria da análise das dependências do aplicativo. A documentação sobre composições explica como executar vários serviços para realizar testes.

No nosso caso, BuildingDockerImage será a imagem gerada pelo estágio de build. Queremos testar essa imagem externamente, então vamos compor nosso teste com um serviço de análise que executa outra imagem que criei anteriormente: aarlaudsnyk/snyk-container-scan-docker. Essa imagem reúne os componentes necessários para que o Snyk teste uma imagem Docker. Você encontra o código-fonte aqui:

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

O trecho relevante do arquivo YAML acima é:

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

Usamos essa imagem para executar um comando Python que faz principalmente duas coisas:

  • Baixa a imagem para testá-la localmente

  • Executa ‘snyk test --docker ’

Essa imagem foi criada para buscar a imagem no registro do Codefresh quando as variáveis de ambiente a seguir estiverem definidas:

  • CFCR_ACCOUNT

  • CF_USER_NAME

  • CFCR_LOGIN_TOKEN

Assim, podemos testar a imagem recém-criada. Caso contrário, ela tentará buscar uma imagem no Docker Hub.

Por fim, vamos adicionar ao final o envio ao registro do Docker Hub, para que a imagem seja enviada se os testes forem aprovados:

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

Nada de complicado por aqui: o Codefresh facilita o envio para o Docker Hub, desde que a integração esteja configurada (veja um pouco antes). Observe que o estágio se chama promote, para diferenciá-lo dos testes de análise.

No conjunto, deve ficar mais ou menos assim:

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. Vamos fazer um build para estabelecer uma referência inicial. Nossa organização parece estar bem limpa:

IDE do Angular exibindo um arquivo de teste app.component.spec.ts, o explorador do projeto e o painel de boas-vindas do Terminal+ para um projeto Angular 2 em TypeScript.

Depois de um momento, temos este resultado:

Pipeline de build do Codefresh mostrando uma análise de dependências do aplicativo com o Snyk que falhou e a saída do terminal informando um caminho vulnerável.

Ops, parece que há alguns problemas no nosso aplicativo — o pipeline foi interrompido com segurança antes de entregar algo com problemas de segurança. Vamos corrigir isso seguindo as etapas de remediação indicadas no resultado. Atualizar o pacote qs para a versão 6.0.4 no package.json resolve o problema.

Vamos executar novamente.

Painel do pipeline de CI mostrando as etapas padrão, de análise e de promoção, com os testes de dependências do Snyk concluídos e nenhum caminho vulnerável encontrado.

Corrigimos a vulnerabilidade do qs, eba! Mas agora há um problema com as dependências do sistema operacional na nossa imagem Docker.

Editor XML exibindo uma fatura com dados de cobrança e entrega, itens, totais, comentários e um painel flutuante de estrutura.

A recomendação de remediação indica que atualizar a imagem pode resolver o problema (consulte a seção sobre Docker em snyk.io/docs). Então, vamos atualizar para node:10-alpine e tentar novamente.

Captura de tela mostrando o código-fonte do PlantUML ao lado do layout de memória gerado e de diagramas de casos de uso.

Salvar => Fazer build => Fazer flexões enquanto o build acontece!

Pipeline do Codefresh concluído, mostrando a clonagem do repositório, a criação da imagem Docker, as análises de dependências do Snyk e o envio para um registro Docker

Ótimo! Agora temos uma nova referência inicial e um pipeline totalmente funcional que entrega nosso aplicativo e contêiner ao Docker Hub.

Agora podemos voltar a programar. Lembre-se de executar snyk test nas suas alterações antes do merge e/ou testá-las usando a integração do Snyk com pull requests do GitHub. Depois disso, as alterações serão entregues automaticamente. E tem mais: um recurso recém-adicionado!

Use snyk monitor para acompanhar suas dependências ao longo do tempo. Ninguém gosta de ficar cuidando de projetos o tempo todo. Ao executar snyk monitor, o Snyk avisa você automaticamente se uma nova vulnerabilidade for divulgada em qualquer dependência do projeto ou da imagem Docker. Basta adicionar snyk monitor depois da seção snyk test.

Editor de configuração YAML mostrando o YAML selecionado em linha, um botão Importar do arquivo e o comando “snyk monitor” destacado.

O URL do snapshot de monitoramento aparecerá no resultado:

Saída do terminal mostrando a URL de um snapshot de monitoramento do app e notificações sobre problemas recém-divulgados em dependências.

A etapa do Docker será executada automaticamente se o snyk test for aprovado (ou seja, se não houver problemas conhecidos). Os links para os snapshots de monitoramento também serão exibidos.

Saída do terminal mostrando o Snyk monitorando um aplicativo de treinamento e notificando os usuários sobre problemas recém-divulgados em dependências

Você também pode ver os projetos monitorados na interface do Snyk, na sua organização do Snyk:

Painel do Snyk Projects mostrando dois repositórios com a quantidade de vulnerabilidades e menus suspensos “Testar diariamente”

Acesse o pipeline do Codefresh clicando no selo do repositório (https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan).

É isso, pessoal! Mantenha-se seguro!

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.

Publicado em:

Leia mais

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.

Blog

Evo ADS Govern Agent Behavior já está disponível: controle o uso de MCP

Evo ADS Govern Agent Behavior já está disponível, começando por MCP Governance. Descubra, aprove, monitore, registre e bloqueie o uso de servidores MCP nos principais agentes de programação com IA.

illustration hero ai
Blog

O que é Agentic AppSec?

Saiba como Agentic AppSec usa agentes de IA fundamentados, com limites definidos e verificados de forma independente para executar o ciclo de segurança de aplicações.