DevSecOps 101: Introdução a testes de segurança com Snyk

Implementando testes automatizados de segurança em pipelines CI/CD com Snyk

Nicolas Costa
7 min readJan 27, 2024

Resumo

Aqui, tenho como objetivo introduzir os conceitos de DevSecOps e correlatos, como: Shift Left testing e seus benefícios, ferramentas e tipos de testes de segurança.

Também, implementar SCA e SAST em um repositório no GitHub utilizando GitHub Actions e Snyk.

Introdução

Podemos entender DevSecOps como o próximo passo do DevOps. Enquanto a cultura DevOps busca aproximar/unir as equipes de desenvolvimento e operações, o DevSecOps busca integrar ferramentas e princípios relacionados a segurança em todo o fluxo, desde os estágios iniciais, como threat modeling (modelagem de ameaças) e risk assessment (avaliação de riscos) na etapa de plan, SAST, DAST e IAST (explicados abaixo) nas etapas de code/build/test, e WAF e RASP (explicados resumidamente abaixo) na etapa operate.

Shift left testing significa que estamos movendo os testes pra o início do Ciclo de desenvolvimento do software (SDLC). Isso é mais eficiente e barato do que empregar segurança nos estágios finais do ciclo de desenvolvimento ou apenas quando seu sistema estiver em produção. A nível de CI/CD, podemos entender isso como testes de segurança sendo aplicados no início da sua pipeline. A nível de ambiente de desenvolvimento, podemos implementar verificações de segurança na máquina do desenvolvedor (o Snyk oferece plugin para várias IDEs).

Existem diversas ferramentas disponíveis no mercado, nomes famosos como: Veracode, Fortify e SonarQube, geralmente possuem planos restritivos pra quem quer testar. Nesse artigo, vou demonstrar a implementação com o Snyk. Ele oferece um plano free com um pacote de recursos bastante decente para uso pessoal (mais detalhes na página de planos deles).

Temos vários tipos de testes, o mais básico, SCA (Software composition analysis) examina as dependências do seu projeto e gera alertas de acordo com o nível de gravidade da(s) vulnerabilidade(s) encontrada(s) nelas. O Snyk disponibiliza esse produto denominando-o de Snyk Open Source.

Outro teste importante, o SAST (Static application security test), é responsável por fazer white box test, ou seja, o teste é realizado diretamente no código da aplicação. Costuma ter uma taxa de falso positivos considerável, comparado com outros testes. O Snyk o disponibiliza denominando-o de Snyk Code.

O terceiro, DAST é realizado como um black box test, ou seja, sem conhecimento do conteúdo do código da aplicação. É como um pentest automatizado. Se, por um lado, o DAST consegue ter menos falsos positivos do que o SAST e consegue operar independente de linguagem, esse tipo de teste costuma ser mais demorado para rodar.

E o último, IAST, que acaba sendo uma combinação de SAST + DAST e pode ser classificado como gray box test. Ele combina sensores que monitoram o estado da aplicação pelo lado “interno” enquanto os testes externos são realizados. Encontrando alguma anomalia, alertas serão gerados em tempo real.

DAST e IAST não são oferecidos pelo Snyk.

Existem outras ferramentas que costumam ser associadas às citadas acima, são elas: RASP (Real time application protection) e WAF (Web application firewall), ambas se aplicam a sistemas em produção.

Pondo a mão na massa

Primeiramente, necessário ter uma conta free do Snyk. Head to thir site e clique em registre-se.

Haverá algumas opções de registro via Single Sign On, sendo as duas principais: Google e GitHub, sugiro o segundo.

Você será recebido por um wizard que o guiará para definir onde está o código que você quer scanear usando as ferramentas. Selecione GitHub.

Selecione next step.

Em seguida, ele perguntará se o Snyk deverá ter acesso a repositórios públicos apenas, ou públicos e privados.

E, por último, ele perguntará algumas questões sobre automação. Para fins desse tutorial, pode usar as opções padrão como na imagem abaixo.

Depois de passar pela tela de autorização do seu ID provider (GitHub), você se deparará com a home e lista de repositórios:

Você poderá, nessa tela, adicionar repositórios para integrar como o Snyk, examinar as vulnerabilidades reportadas, iniciar scans etc. Não é obrigatório adicionar um repositório aqui para conseguir rodar os testes na pipeline.

Em seguida, em Account Settings, no menu inferior esquerdo, obtenha (click to show) o Auth token, esse token é necessário para o Snyk CLI autenticar na sua conta, quando ele estiver rodando dentro do container que vai subir durante a execução dos testes na pipeline do seu projeto.

O próximo passo é configurar o token nos secrets do seu repositório. Crie uma variável chamada SNYK_TOKEN e cole o token obtido no passo anterior.

Depois disso, agora partiremos para configurar nosso workflow no repositório.

Podemos criar algumas condicionais no nosso workflow para que o scan apenas seja executado em caso de o pull request fechado devido a um merge da sua branch na main.

name: Snyk Security

on:
pull_request_target:
types:
- closed
branches:
- main

permissions:
contents: read

jobs:
if_merged:
if: github.event.pull_request.merged == true
permissions:
contents: read
# necessário para que a última action consiga fazer o upload dos arquivos sarif
security-events: write
runs-on: ubuntu-latest

Primeiro, criaremos o step de checkout, esse é responsável fazer a árvore de trabalho corresponder a o commit que disparou o workflow.

      - name: Checkout
uses: actions/checkout@v3

Em seguida, criaremos o step que configura o Snyk CLI e rodar o SCA. O Snyk já tem uma action para as linguagens suportadas, no repositório que esta sendo utilizado aqui, Golang.

      - name: Set up Snyk CLI to perform SCA
uses: snyk/actions/golang@master
# Continua em caso de erro, para que possa ocorrer o upload do arquivo sarif
continue-on-error: true
env:
# Obtemos o token setado no repositório
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
# O comando padrão é teste, que executa o Snyk Open source (SCA)
# Ele só irá reportar vulnerabilidades com nível alto
# E irá gerar o arquivo sarif com os resultados
args: --severity-threshold=high --sarif-file-output=snyk.sarif

Agora, criaremos o step de SAST:

      - name: Perform Snyk SAST
uses: snyk/actions/golang@master
# Continua em caso de erro, para que possa ocorrer o upload do arquivo sarif
continue-on-error: true
env:
# Obtemos o token setado no repositório
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: code test
# O comando code test é repsonsável por executar o Snyk Code (SAST)
# E irá gerar o arquivo sarif com os resultados
args: --sarif-file-output=snyk-code.sarif

E, finalmente, criaremos os steps de movimentação dos arquivos SARIF e de upload dos arquivos SARIF para que o próprio GitHub permita a visualização dos resultados dos nossos scans na aba Security do repositório.

      - name: Create SARIF directory and move SARIF files
# Criamos o diretório e movemos os arquivos pra dentro dele
run: |
mkdir sarif_files && mv snyk.sarif snyk-code.sarif sarif_files/

# Realiza o upload do conteúdo da pasta
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: sarif_files

Assim fica todo o conteúdo do arquivo de workflow:

name: Snyk Security

on:
pull_request_target:
types:
- closed
branches:
- main

permissions:
contents: read

jobs:
if_merged:
if: github.event.pull_request.merged == true
permissions:
contents: read
security-events: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Snyk CLI to perform SCA
uses: snyk/actions/golang@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high --sarif-file-output=snyk.sarif

- name: Perform Snyk SAST
uses: snyk/actions/golang@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: code test
args: --sarif-file-output=snyk-code.sarif

- name: Create SARIF directory and move SARIF files
run: |
mkdir sarif_files && mv snyk.sarif snyk-code.sarif sarif_files/

- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: sarif_files

Feito tudo isso, ao fechar um PR, por causa de ter sido feito merge na sua branch principal (main/master), a action deve ser disparada. Entrando nos detalhes da execução do workflow e, em seguida, nos detalhes do job if_merged, você deve encontrar o detalhe dos steps.

Abaixo, é possível ver o resultado da execução do SAST:

E do SCA:

Também é possível acompanhar os problemas via painel do Snyk:

Conclusão

Agora, seu repositório deverá conter steps de SCA e SAST minimamente funcionais na sua esteira de CI/CD, conforme combinamos na introdução.

Espero que este artigo ajude alguém.

Referências:

Fisher, Derek. Application Security Program Handbook: A guide for software engineers and team leaders. Manning, 2023.

--

--