Skip to main content

Como criar um pipeline de CI/CD seguro com GitHub Actions para sua aplicação Java

Escrito por

27 de junho de 2022

0 minutos de leitura

O GitHub Actions tornou mais fácil do que nunca criar um pipeline seguro de integração contínua e entrega contínua (CI/CD) para seus projetos no GitHub. Ao integrar seu pipeline de CI/CD ao repositório do GitHub, o GitHub Actions permite automatizar o pipeline de build, testes e implantação. Você pode criar workflows que fazem o build e testam cada pull request enviado ao repositório ou implantam em produção os pull requests mesclados. Ao integrar o Snyk ao CI/CD do GitHub, você também pode automatizar as verificações de segurança como parte do ciclo de build, antes da produção.

Como configurar um pipeline de CI com GitHub Actions para Java

Os workflows do GitHub Actions são arquivos YAML na pasta .github/workflows. Se você ainda não tem um workflow ou quer adicionar outro, selecione Ações e Novo workflow.

Página do GitHub Actions mostrando a seção Workflows, um botão New workflow e a opção All workflows selecionada.

Para este projeto Java Spring Boot, criei um pipeline de CI usando Maven da seguinte maneira:

name: Java CI with Maven

on:
 push:
   branches: [ master ]
 pull_request:
   branches: [ master ]
 workflow_dispatch:

jobs:
 build:

   runs-on: ubuntu-latest

   steps:
   - uses: actions/checkout@v2
   - name: Set up JDK 17
     uses: actions/setup-java@v1
     with:
       java-version: 17
   - name: Build with Maven
     run: mvn -B package --file pom.xml

Esta ação será executada a cada push ou pull request na branch master. Ela usa o Ubuntu, faz checkout do repositório e, com a GitHub Action setup-java — usando Java 17 e Maven —, compila o arquivo JAR do Java. Se você já conhece a sintaxe, este workflow é relativamente simples. Para conferir todas as possibilidades, consulte a documentação do GitHub Actions.

Integrando o Snyk ao CI/CD do GitHub

Com o Snyk, você pode integrar testes de segurança ao seu novo projeto Java. Há duas formas principais de fazer isso. Antes, vamos garantir que dois pontos estejam configurados. Primeiro, entre na sua conta do Snyk ou crie uma gratuitamente, caso ainda não tenha uma. Depois, configure sua chave de API como um segredo chamado SNYK_TOKEN no repositório do GitHub.

Opção 1: integrar a CLI do Snyk a uma etapa de build do GitHub Actions

Você pode usar a CLI do Snyk para executar verificações de segurança automaticamente durante o build atual. Siga as etapas abaixo — incluindo as etapas adicionais após Build with Maven — para começar.

 - name: Set up Node 14
   uses: actions/setup-node@v3
   with:
     node-version: 14
 - name: install Snyk CLI
   run: npm install -g snyk
 - name: run Snyk Open Source Test
   run: snyk test
 - name: run Snyk Code Test
   run: snyk code test

Configure o NodeJS versão 14 e baixe a CLI do Snyk com o npm. Em seguida, analise suas dependências com o Snyk Open Source e use o Snyk Code para verificar se há vulnerabilidades no seu código personalizado.

Depois, declare SNYK_TOKEN como a variável de ambiente que contém sua chave de API. Você pode usar o segredo SNYK_TOKEN configurado anteriormente ou reutilizar o exemplo completo de código da GitHub Action.

env:
 SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

A vantagem dessa abordagem é que você só precisa compilar e fazer o build da aplicação uma vez, o que pode economizar bastante tempo em aplicações grandes. A desvantagem é que as etapas são executadas em sequência e podem ser ineficientes se uma das etapas posteriores falhar.

Opção 2: usar as GitHub Actions predefinidas do Snyk para criar seu pipeline de CI/CD

O Snyk criou um conjunto de GitHub Actions para verificar se há vulnerabilidades nos seus projetos. A ação necessária depende da linguagem de programação ou da ferramenta de build que você usa. Por exemplo, no projeto Java, usaremos a GitHub Action baseada em Maven mostrada abaixo.

As ações predefinidas garantem os pré-requisitos corretos para fazer o build da sua aplicação e incluem a versão mais recente da CLI para verificar seu código. Embora talvez seja necessário fazer o build da aplicação várias vezes, essas ações podem ser executadas de forma independente e em paralelo — uma grande vantagem dessa abordagem.

Vamos começar verificando nossas dependências. Já temos uma conta do Snyk e nossa chave de API está armazenada em um segredo chamado SNYK_TOKEN. Então, em vez de criar uma etapa adicional no job de build, crie um novo job chamado opensource-security.

opensource-security:
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@master
     - name: Run Snyk to check for vulnerabilities
       uses: snyk/actions/maven@master
       env:
         SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

De acordo com a documentação, o comando padrão é test. Sem nenhuma configuração adicional, ele verifica se há vulnerabilidades conhecidas nas dependências da sua aplicação. Para definir um argumento específico da CLI, como --all-projects, e incluir projetos aninhados, use a palavra-chave with e defina a propriedade como args.

Tabela de propriedades, valores padrão e descrições da Snyk Maven Action para args, command e saída JSON.

Enquanto o Snyk verifica nossas dependências, vamos procurar vulnerabilidades no código Java usando nossa GitHub Action. Para isso, repita o processo anterior, criando um terceiro job específico e definindo a propriedade command como code test.

 code-security:
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@master
     - name: Run Snyk to check for vulnerabilities
       uses: snyk/actions/maven@master
       env:
         SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
       with:
         command: code test

Observe que os três jobs serão executados em paralelo, o que, em muitos casos, é mais eficiente.

Como adicionar entrega contínua segura ao CI/CD do GitHub

Agora, vamos falar sobre a etapa de implantação — ou entrega — do CI/CD do GitHub. Depois que o build e os testes forem concluídos, é hora de publicar o pacote no GitHub. Para isso, usaremos o plugin Maven Release no nosso projeto Java.

Como queremos liberar o pacote somente quando o job de build e os dois jobs de segurança forem concluídos com sucesso, vamos adicionar uma propriedade needs com uma lista dos jobs necessários para a liberação. Assim, garantimos que o pacote não seja implantado antes de estar totalmente compilado e seguro.

release:
   needs: [opensource-security, code-security, build]
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@v2
     - name: Set up JDK 17
       uses: actions/setup-java@v1
       with:
         java-version: 17
     - name: Set Git user
       run: |
         git config user.email "ghactions@brianvermeer.nl"
         git config user.name "GitHub Actions"
     - name: Publish JAR
       run: mvn -B release:prepare release:perform -DskipTests
       env:
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Os comandos do Maven release:prepare e release:perform verificam se a versão da release está correta e publicam o pacote no repositório do GitHub. Como vamos deixar essa tarefa a cargo do Maven, faça as seguintes configurações no arquivo pom.xml.

  <scm>
       <developerConnection>scm:git:https://github.com/bmvermeer/ghaction-example.git</developerConnection>
       <tag>HEAD</tag>
   </scm>
   <distributionManagement>
       <repository>
           <id>github</id>
           <name>GitHub</name>
           <url>https://maven.pkg.github.com/bmvermeer/ghaction-example</url>
       </repository>
   </distributionManagement>

Embora nossa aplicação recém-lançada não tenha vulnerabilidades no momento, isso não significa que ela continuará segura para sempre. Novas vulnerabilidades podem surgir em vários pontos. Por isso, é essencial monitorar continuamente o código e as dependências após a implantação da aplicação.

Além de fazer verificações durante o desenvolvimento, também podemos usar o Snyk para monitorar as dependências após a implantação. Quando a release estiver concluída, use novamente a ação predefinida do Snyk, mas desta vez defina a propriedade command como monitor.

 opensource-monitor:
   needs: [release]
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@master
     - name: Run Snyk to check for vulnerabilities
       uses: snyk/actions/maven@master
       env:
         SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
       with:
         command: monitor

Isso enviará ao Snyk a árvore de dependências, que permanece estática após a release, para monitoramento. Agora, podemos ver nosso projeto na interface do Snyk e receber notificações automáticas se uma nova vulnerabilidade for encontrada em alguma dependência usada — ajudando a manter nosso projeto Java publicado livre de vulnerabilidades.

Painel do projeto Snyk exibindo “nl.brianvermeer.snyk:ghaction-example”, contagens de problemas iguais a zero e um link para ver o relatório

Integrando segurança ao GitHub Actions

Com o GitHub Actions, é simples criar um pipeline de CI/CD para seu projeto no GitHub. E com as ações do Snyk, você pode integrar facilmente verificações de segurança em vários níveis para todas as suas aplicações.

O GitHub representa visualmente o pipeline que criamos hoje na imagem a seguir. Alguns jobs são executados em paralelo, enquanto outros dependem da conclusão bem-sucedida de outros jobs. Confira o projeto de exemplo completo neste repositório do GitHub.

Fluxo de trabalho do GitHub Actions mostrando tarefas bem-sucedidas de build, segurança, lançamento e monitoramento de código aberto, acionadas por um push

Hoje, usamos o Snyk Code e o Snyk Open Source para verificar o código-fonte Java e as dependências do pipeline. Você também pode ampliar a cobertura verificando arquivos Docker com o Snyk Container e arquivos do Kubernetes com o Snyk IaC.

Com as GitHub Actions do Snyk, você pode adicionar verificações automaticamente ao workflow do GitHub Actions e combinar as ações conforme as necessidades do seu projeto, mantendo seu código seguro agora e no futuro.

Comece a jogar Capture the Flag

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