Sitemap
Photo by Jainath Ponnala on Unsplash

DevSecOps do Zero com TFlint, Checkov, Terraform, GitHub Actions & AWS

Desenvolvimento seguro com DevSecOps para sua pipeline de infraestrutura, com Terraform (S3, VPC, etc.) e provisionamento direto na AWS.

--

Quando se fala em DevSecOps, temos que entender a parte mais fundamental da abordagem, que é a segurança. Se você estiver apenas fazendo testes de segurança, scan de vulnerabilidades pontuais, isso ainda não é um DevSecOps efetivo para o ciclo de SDLC. A verdadeira prática envolve automação, cultura, e integração da segurança desde o planejamento até a produção.

DevSecOps Flow

Existem dois tipos de abordagens quando falamos de DevSecOps, no qual podemos usar dentro do ciclo de desenvolvimento. Gosto de mencionar uma passagem do artigo do

, onde ele aborda de maneira simples e direta o conceito de pipelines. 👇👇👇

O pipeline usado para entregar software segue o mesmo conceito usado normalmente nas indústrias, que é uma esteira metálica que faz o produto “se mover” por dentro da fábrica, e os robôs, que estão parados, montam o produto à medida que ele passa.

  • 🧩Pipeline de Aplicação — desenvolvido com foco em tecnologias como Java, Python, Golang, para deploy de um app.
    Foco: Código da aplicação (ex: Node.js, Java, Python, etc.)
  • 🏗️Pipeline de Infraestrutura — desenvolvido com foco em produtos de uma infraestrutura usando o modelo de IaC.
    Foco: Infraestrutura como código (ex: Terraform, CloudFormation, Ansible)

Nesse post de hoje vamos focar apenas no modelo de pipeline de infraestrutura, onde é representado com foco no modelo de IaC (Infrastructure as Code). Eu criei essa arquitetura bem simples abaixo, exemplificando os passos que podemos ter em todo o ciclo, desde o commit até o deploy do produto final, fazendo a adição de algumas ferramentas capazes de analisar, testar e provisionar todo o produto.

O objetivo final é inserir a abordagem de “shift left”, trazendo as medidas de segurança para a esquerda no desenvolvimento, assim criando um produto para ser provisionado diretamente na AWS de forma mais segura. Pensei de criar simples recursos como, EC2, S3, VPC para evidenciar todas as ações.

DevSecOps Pipeline

IaC (Infrastructure as Code)

A abordagem de IaC (Infraestrutura como Código) é o que vamos usar aqui hoje para provisionar os produtos na AWS com Terraform. Basicamente, Infraestrutura como Código (IaC) é uma abordagem que consiste em você gerenciar e provisionar os recursos e/ou serviços da sua infraestrutura via código, ao invés de processos manuais. No IaC, você cria arquivos de configuração (.yml/.tf) que incluem as especificações da sua infraestrutura.

provider "aws" {
region = "us-east-1"
}

resource "aws_s3_bucket" "meu_bucket" {
bucket = "meu-bucket-seguro-exemplo"
acl = "private"

versioning {
enabled = true
}

server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}

tags = {
Name = "MeuBucket"
Environment = "producao"
}
}

Terraform

Também usaremos aqui o Terraform, acredito que é uma das ferramentas mais fortes hoje no mercado de DevOps/Cloud Automation, justamente por elevar o nível de você codar e manter toda uma infraestrutura de TI organizada, versionada e com gerenciamento total de estado dos serviços. Para quem está estudando Terraform, eu super indico você ler as boas práticas da ferramenta que foram escritas pelo Anton Babenko, responsável por criar diversos módulos hoje usados por toda a comunidade e uma pessoa maravilhosa, super dedicada em melhorar e criar boas práticas do Terraform com AWS. Aproveita e segue os projetos dele no GitHub porque são muito usados e lá você fica sempre de olho no que ele está trabalhando em torno de Terraform. Veja abaixo alguns dos principais comandos do Terraform.

Hashicorp Terraform

terraform init baixa os plugins necessários para executar o código.
terraform plan mostra o que o Terraform irá realizar na infra.
terrraform apply executa tudo que foi definido no arquivo de configuração.
terraform destroy irá destruir tudo que foi aplicado no provider.

Stack

Para nosso hands-on de hoje, você precisa seguir com a seguinte stack:

  • Ter o Ansible instalado na sua maquineta/instância/VirtualBOX.
  • Ter o Terraform instalado na sua maquineta/instância/VirtualBOX.
  • Ter o Git instalado na sua maquineta/instância/VirtualBOX.
  • Ter uma conta free tier na AWS.
  • Não precisa ter conhecimento prévio de IaC (vamos aprender…)

Definindo nosso arquivo “.tf”

Por boas práticas do Terraform, sempre é bom criar vários arquivos (.tf) para que fique mais organizado o diretório de trabalho e os serviços que você está provisionando e sempre que possível, use módulos no Terraform (locais ou de produtos como AWS, Azure, GCP), para que você evite código duplicado, configuração complexa de arquivos (.tf) e limites de reusabilidade, os módulos existem justamente para sanar esse tipo de problema. No arquivo main.tf, vamos declarar nosso recurso que é a instância AWS EC2.

terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.0.0-beta2"
}
}
}

provider "aws" {
# Configuration options
region = "sa-east-1"
shared_credentials_files = ["/home/foobar/.aws/credentials"]
profile = "default"
}

data "aws_ami" "ubuntu" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
monitoring = true

tags = {
Name = "HelloWorld"
}
}

O que já temos definido?

Acredito que estamos bem encaminhados por aqui, vamos fazer um checklist dos itens que já temos e o que está faltando.

  • Criamos nossa estrutura do Terraform conforme mostrado anteriormente.
  • Definimos nosso arquivo (.tf) que será utilizado.
  • Definimos que vamos usar a Cloud da AWS e o serviço de EC2.
  • A ferramenta de CI/CD que vamos usar é o GitHub Actions.

CI/CD Workflow

A ideia do CI (Continuous Integration) dentro de DevOps, é justamente monitorar todas as mudanças que ocorrem no desenvolvimento da aplicação/infraestrutura, ou seja, toda vez que modificamos o código e enviamos as alterações para o repositório no GitHub, o servidor de CI fica ouvindo as alterações para que ele tome determinada ação. Esse seria um exemplo de workflow no contexto de CI em DevOps. A ideia do GitHub Actions acontece em seguida à esse processo, é o método de automatizar essa entrega, para que o processo seja mais consistente, rápido e efetivo, vamos aprender mais sobre Actions no próximo tópico, fica ligado!

O que é GitHub Actions

Antes de começar com a parte mais legal, que é a prática, vamos de conceitos iniciais para entender de fato, que raios é esse tal de Actions no GitHub. O GitHub Actions é uma ferramenta do próprio GitHub, com o propósito de simplificar o processo de build e deployment automatizado de aplicações, é uma forma de se criar, testar e implantar o código diretamente do GitHub, sem usar ferramentas de terceiros, como CircleCI, Jenkins, Drone CI e outras. Existem alguns outros conceitos que são importantes dentro de Actions, como os workflows, actions, jobs, events, vou explicar cada componente para que fique claro o entendimento, mas sempre consulte a documentação oficial, para maiores informações sobre o GitHub Actions.

Definindo nosso arquivo de pipeline, vamos começar com o init do Terraform, onde podemos adicionar alguns passos iniciais de execução da infraestrutura, como o init e o fmt, ambos são comandos nativos do Terraform e devem ser usados dentro do workflow da pipeline. Como prática recomendada, após a inicialização do Terraform, precisamos garantir que nosso código Terraform respeite os padrões que configuramos. Portanto, neste exemplo, estamos verificando se o código está formatado corretamente e se a configuração é válida com este bloco:

jobs:
terraform:
name: "Terraform Init"
runs-on: ubuntu-latest
#permissions:
#contents: read
#security-events: write
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3
# terraform_version: 0.13.0:

- name: Terraform Format
id: fmt
run: terraform fmt

- name: Terraform Init
id: init
run: terraform init

Abaixo o exemplo de uso do comando terraform validate comando nativo também e com uma ideia bem legal de uso. Claro, você pode adicionar outras ferramentas aqui que ajudem no seu fluxo de trabalho do Terraform antes ou mesmo depois da inicialização. Isso inclui ferramentas de verificação de vulnerabilidades de segurança como Tfscan, Checkov, Terrascan, Kicks, etc.

terraform-validate:
name: "Terraform Validate"
runs-on: ubuntu-latest
needs: terraform # Optional: make it run after Terraform Init

steps:
- name: Checkout source code
uses: actions/checkout@v4

- name: Set up Terraform
uses: hashicorp/setup-terraform@v3

- name: Terraform Init
run: terraform init

- name: Terraform Validate
id: validate
run: terraform validate -no-color

TFLint

O TFLint é um framework e cada recurso é fornecido por plugins. Os principais recursos são os seguintes:

  • Encontrar possíveis erros (como tipos de instância inválidos) para os principais provedores de nuvem (AWS/Azure/GCP).
  • Alertar sobre sintaxe obsoleta e declarações não utilizadas.
  • Aplicar as melhores práticas e convenções de nomenclatura.
tflint:
name: "TFLint Scanning"
runs-on: ${{ matrix.os }}

strategy:
matrix:
os: [ubuntu-latest]

steps:
- uses: actions/checkout@v4
name: Checkout source code

- uses: actions/cache@v4
name: Cache plugin dir
with:
path: ~/.tflint.d/plugins
key: ${{ matrix.os }}-tflint-${{ hashFiles('.tflint.hcl') }}

- uses: terraform-linters/setup-tflint@v4
name: Setup TFLint
with:
tflint_version: v0.52.0
- name: Show version
run: tflint --version

- name: Init TFLint
run: tflint --init
env:
# https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/plugins.md#avoiding-rate-limiting
GITHUB_TOKEN: ${{ github.token }}

- name: Run TFLint
run: tflint -f compact
needs: terraform-validate

Checkov

Checkov usa uma interface de linha de comando comum, para gerenciar e analisar resultados de varredura de infraestrutura como código (IaC) em plataformas como Terraform, CloudFormation, Kubernetes, Helm, ARM Templates e Serverless Framework. Muito utilizado dentro de diversos projetos, empresas e comunidades como Policy as Code, com foco na verificação das configurações de infraestrutura de nuvem. para encontrar erros de configuração antes que elas sejam implantadas.

# This workflow contains a single job called "checkov"
checkov:
name: "Checkov Security Scanning"
needs: [tflint]
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status

# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so follow-up steps can access it
- uses: actions/checkout@v3

- name: Checkov GitHub Action
uses: bridgecrewio/checkov-action@v12
with:
# This will add both a CLI output to the console and create a results.sarif file
output_format: cli,sarif
output_file_path: console,results.sarif

- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3

# Results are generated only on a success or failure
# this is required since GitHub by default won't run the next step
# when the previous one has failed. Security checks that do not pass will 'fail'.
# An alternative is to add `continue-on-error: true` to the previous step
# Or 'soft_fail: true' to checkov.
if: success() || failure()
with:
sarif_file: results.sarif

GitHub Action Workflow

A integração do Checkov no GitHub Actions, fornece uma maneira simples e automática de aplicar políticas ao seu código Terraform, durante a revisão da solicitação de pull e como parte de qualquer processo de compilação. Eu não adicionei o job de apply da infraestrutura neste post, seria um próximo passo ali do workflow, onde de fato ele deve escrever as alterações na AWS e criar todo o ambiente de EC2.

Definir um pipeline de CI/CD personalizado com a abordagem de DevSecOps, com o GitHub Actions para gerenciar o ciclo de vida e o provisionamento de infraestrutura do Terraform, é um excelente método para impor as melhores práticas, aplicar alterações de infraestrutura, tudo isso de forma previsível e segura, para eliminar a necessidade de intervenção humana em todas as etapas de codificação.

Pretendo voltar com mais algumas abordagens de uso de um verdadeiro DevSecOps, buscando adicionar outras ferramentas de S-SDLC, Shift Left, SAST e DAST, não perde hein? Vai ser demais e você tem tudo para praticar e sair usando para manter a segurança como principal e entregar um produto de valor, seguro e resiliente.

E isso é tudo pessoal. Se você gostou deste post, mostre seu apoio 👏 nesta história. Obrigado por ler! Quer colaborar também ou tem uma dúvida, sugestão? Manda a sua mensagem que a gente troca ideia e acerta os passos, vamos aprender e estudar Terraform, AWS e pipelines.

--

--

DevSecOps from Zero!🧑‍💻🛡️
DevSecOps from Zero!🧑‍💻🛡️

Written by DevSecOps from Zero!🧑‍💻🛡️

DevSecOps Engineer| Appsec | Lifelong learner | Medium Creator | AWS/Azure certified☁️ | Hashicorp Ambassador | Containers | Tech | Community | Coffee

No responses yet