O blog da AWS

Automatizando análise de segurança em Terraform com AWS CodePipeline

Gilmar Rodrigues, Arquiteto de solução, AWS setor público do Brasil

Os times de TI tem buscado cada vez mais se tornarem mais produtivos, criando ambientes em nuvem de forma rápida, consistente e com mais assertividade. Uma forma muito utilizada para isso é o uso de Infraestrutura como código (IaC).

Assim como no desenvolvimento de aplicações, devemos manter controle sobre o código.
Uma das ferramentas mais utilizadas hoje em dia é o Git, e a AWS fornece o AWS CodeCommit, que é um serviço gerenciado de controle de versão baseado em Git, que será usado neste blogpost como repositório do código fonte.

Além disso, existe a preocupação do ponto de vista de segurança em entender se o código vai gerar um ambiente seguro. Para ajudar nessa questão, vamos criar um processo que analisa a segurança do código e provisiona um ambiente caso uma equipe de segurança aprove a execução. Para demonstrar a análise, usaremos um código que provisiona um ambiente de containers com Amazon ECS e AWS Fargate.

Para a execução do código, criaremos um pipeline com o AWS CodePipeline, que será acionado quando houver um commit no repositório.

De forma resumida, seguiremos algumas etapas:

  1. Criação do plano de execução do Terraform
  2. Analise de segurança do código utilizando o Checkov (ferramenta open source)
  3. Validação e aprovação do código pelo time de segurança
  4. Execução do plano Terraform

A escolha do Checkov se dá pela sua capacidade de escanear código de infraestrutura (Terraform, CloudFormation, Kubernetes, Helm, entre outros) e encontrar erros de configuração antes do deploy.

Este blogpost faz referência a um código fonte disponibilizado no repositório público da AWS. Informações de como obtê-lo e configurá-lo, estão no final do artigo.

Introdução

A AWS tem serviços de DevOps que possibilitam estruturar e automatizar entregas de infraestrutura como código, aplicações entre outras coisas. De forma macro, seguem abaixo os serviços, suas responsabilidades e como cada um deles resolve sua parte do processo.

  • AWS CodeCommit
    • É um serviço gerenciado, seguro e altamente dimensionável que hospeda repositórios git. É usado para armazenar e controlar o código fonte de aplicações de forma privada.
    • É possível usar o CodeCommit como fonte de código em um fluxo de CI/CD gerenciado pelo serviço CodePipeline, de forma que alterações no código iniciam a execução do pipeline.
  • AWS CodePipeline
    • É um serviço gerenciado de entrega contínua que automatiza as fases de compilação, teste e implantação do processo de liberação sempre que ocorre uma mudança no código, de acordo com o modelo de liberação que você definiu
    • Além disso é possível utilizar o serviço para solicitar e aguardar uma aprovação manual
  • AWS CodeBuild
  • É um serviço de integração contínua e que fará o trabalho pesado no pipeline, executando atividades como compilação de código, execução de testes e empacotamento de software, assim como um servidor comum. A grande vantagem é que não há necessidade de manter servidores de build, pois o serviço é auto escalável, gerenciado pela AWS e cobrado apenas pelo tempo de execução.
  • Será usado para criar o plano de execução do Terraform, executar a validação do código via Checkov e por fim aplicar o plano Terraform criado

Abaixo emos o desenho da arquitetura dos serviços utilizados:

Figura 1 – Fluxo de execução do pipeline

O fluxo se inicia com o commit do código(1), que dispara um evento(2) e ativa a execução do pipeline. Na sequencia, o código é analisado pelo Checkov (3) e ocorre a notificação por email via o serviço Amazon SNS(4). Após a aprovação manual(5), o código Terraform é executado(6), criando o ambiente de demonstração.

AWS CodeCommit

Procure pelo serviço CodeCommit na console da AWS e clique em criar repositório.

 

 

Figura 2 – Criação do repositório no AWS CodeCommit

Feito isso, temos um repositório git para versionar nosso código. O acesso ao repositório é feito de forma segura através de uma chave de acesso de um usuário no IAM (veja Gerenciar chaves de acesso)

AWS CodeBuild

Para criar um projeto, busque pelo AWS CodeBuild na console da AWS e clique em criar projeto de compilação. Durante qualquer parte da configuração, caso queria mais informações ou tenha dúvidas, consulte a documentação.

Conforme a figura 3 abaixo, preencha o nome do projeto, opcionalmente coloque uma descrição e mantenha as configurações padrão.

 

Figura 3 – Criação do projeto no AWS CodeBuild

Na figura 4, escolha seu repositório do AWS CodeCommit e sua ramificação, tag do git ou até mesmo ID de confirmação.

 

Figura 4 – Criação de origem no AWS CodeBuild

Abaixo será feita a configuração do ambiente, para isso, escolha uma imagem gerenciada pela AWS (também é possível usar uma imagem docker customizada) com S.O. Linux Ubuntu e mantenha as outras opções conforme indicado na figura 5.

Um aspecto importante é a criação de uma service role para que o AWS CodeBuild tenha os acessos necessários para executar todos os comandos e serviços dependentes. Esse é um padrão que os serviços seguem para garantir a segurança, pois exigem que o acesso seja liberado de forma explicita. Pela praticidade, escolha deixar o serviço fazer isso por você, porém é possível criar manualmente conforme explicado na documentação.

 

 

 

Figura 5 – Configuração do ambiente no AWS CodeBuild

O buildspec é um arquivo em formato YAML que define quais comandos serão executados nas diversas fases do build, como pre_build, build e post_build entre outras. Conforme a figura 6, deixe o nome do arquivo em branco para que o serviço procure pelo arquivo padrão, que é o buildspec.yml na raiz do projeto.

 

Figura 6 – Definição do buildspec no AWS CodeBuild

Mantenha a configuração padrão para o restante das opções.

Para debugar e corrigir problemas do build, escolha enviar os logs para o CloudWatch, pois isso facilita muito encontrar os erros, uma vez que o serviço centraliza e mantem os logs para consulta futura. Escolha um nome do grupo, que é a forma como o serviço agrupa logs similares, como se fosse um diretório no sistema operacional. E escolha o nome do fluxo, que é onde os logs de cada execução ficarão armazenados.

 

 

Figura 7 – Habilitação dos logs de execução no AWS CodeBuild

No código fonte deste projeto, você encontra o arquivo “buildspec.yml”, que contém os comandos necessários para executar o terraform. Será necessário mais um build para executar o Checkov. Repita o processo acima, mas preencha o nome do Buildspec com “buildspec_checkov.yml”.

 

 

Figura 8 – Definição do buildspec no AWS CodeBuild

AWS CodePipeline

A última etapa é a criação do pipeline, que vai controlar toda a execução.

Antes de prosseguir com as etapas do pipeline, é preciso um recurso para notificar o time de segurança.O Amazon SNS faz esse papel e neste caso enviará um email com o resultado do Checkov para o time revisar e aprovar a atividade.
Procure pelo serviço e crie um novo tópico. Existem diversas opções para diferentes casos. Para esta demonstração seguiremos com o tipo Padrão e manteremos as opções default.

 

Figura 9 – Criação de tópico no Amazon SNS

Entre no tópico criado e anote seu ARN na seção de “Detalhes”. Vamos utilizá-lo no próximo passo.
Na mesma tela, crie uma assinatura escolhendo como Protocolo o tipo “E-mail” e preencha com o email (pode ser uma lista de distribuição) que receberá as notificações. Não se esqueça de aceitar o pedido de autorização que o serviço solicitará por email, caso contrário o serviço não fará o envio.

Também precisaremos de um bucket S3 para armazenar o plano de execução do terraform. Queremos garantir que a execução do terraform seja referente ao plano aprovado e não a qualquer outra mudança que tenha subido para o repositório antes da aprovação. Procure por S3 na console e crie um novo bucket.

Seguindo com a criação do pipeline, procure pelo AWS CodePipeline na console da AWS e clique em criar pipeline.

 

 

Figura 10 – Criação do pipeline (etapa 1) no AWS CodePipeline

Assim como no CodeBuild, o CodePipeline precisa de permissão para utilizar os recursos AWS. Vamos utilizar a opção de criação automática da service role para facilitar o processo.
O próximo passo é escolher a origem dos dados AWS CodeCommit, o repositório e o branch criados. Mantenha o restante das opções no padrão (Figura 11).

 

 

Figura 11 – Configuração de origem (etapa2) no AWS CodePipeline

O passo seguinte refere-se à escolha do Build. Selecione o projeto de compilação do terraform e adicione as seguintes variáveis de ambiente para parametrizar o build, conforme identificado na figura 12:
ENVIRONMENT com o valor “dev1”
SEC_TOPIC_ARN com código arn do tópico do SNS.
S3_BUCKET com o nome do bucket
Isso fará com que durante o processo de build, o arquivo dev1.tfvars seja utilizado para parametrizar o ambiente.

 

Figura 12 – Configuração de compilação (etapa 3) no AWS CodePipeline

Pule a etapa 4 do wizard, faça a revisão e clique em criar pipeline.

Agora vamos adicionar a etapa de aprovação. Para isso encontre o pipeline criado, clique em editar e em Adicionar etapa, dê um nome a ela, clique em Editar etapa e adicione uma ação.
De um nome a ela e escolha Aprovação Manual no Provedor de ação. Escolha o ARN do tópico do SNS criado no passo anterior e clique em Concluído, conforme a figura abaixo.

 

Figura 13 – Adição de aprovação manual no pipeline

A etapa de aprovação tem como objetivo fazer com que a execução do pipeline fique aguardando até que o time de segurança aprove ou rejeite a ação.

E como ultima etapa queremos que caso aprovado, o ambiente seja criado.

Adicione uma nova etapa e nela uma ação do tipo AWS CodeBuild. Escolha SourceArtifact na lista de Artefatos de entrada, escolha seu projeto de build e adicione as mesmas variáveis de ambiente do build anterior e uma nova chamada SEC_TOPIC_ARN com o valor do ARN do tópico criado anteriormente. Mantenha a configuração padrão para o restante. Clique em Concluído e salve o pipeline.

 

Figura 14 – Adição do build do terraform no pipeline

Nesse ponto o pipeline está criado e a partir de agora, qualquer commit na branch definida, irá disparar o pipeline.

Aqui podemos observar o pipeline com o passo de Build em andamento.

 

Figura 15 – Pipeline em execução no AWS CodePipeline

No link “Detalhes”, é possível visualizar os logs de execução.

 

Figura 16 – Log de execução do pipeline

Também é possível observar o pipeline aguardando a revisão pelo time de segurança.

Figura 17 – Log de execução do pipeline

Código fonte e dependências

O código fonte que cria o ambiente pode ser encontrado neste repositório público com exemplos da AWS. Baixe o código e faça as alterações necessárias conforme indicado a seguir, para que reflita as informações da sua conta.

Altere o arquivo main.tf na raiz do projeto, uma vez que o terraform não aceita variáveis na configuração do backend. Utilize o mesmo bucket criado no inicio do projeto.

terraform {
  backend "s3" {
    bucket = "<terraform-bucket-name>"
    key    = "terraform.tfstate"
    region = "us-east-1" #altere para a região desejada
  }
}

O deploy do ambiente utiliza a imagem oficial do container Apache(httpd) que precisa estar em uma repositório público no Amazon ECR. No link a seguir você encontra o passo a passo de como criar sua própria imagem e também em como fazer o envio usando Docker e o AWS CLI.  Uso do Amazon ECR com o AWS CLI

Conclusão

É importante reiterar que criar pipelines de automação é extremamente importante em termos de agilidade, produtividade e consistência para as operações executadas pelos times de TI. Aqui vimos como usar os serviços da AWS, como o AWS CodeCommit, AWS CodeBuild e AWS CodePipeline para construir um pipeline de CI/CD que faz o provisionamento de infraestrutura a partir de código, além de melhorar a postura de segurança. Mas não devemos parar por aí, pois o aspecto de segurança tem ganhado uma importância cada vez maior dentro das empresas e só conseguiremos atingir os níveis ideais através de automações e serviços especializados.


Sobre o autor

Gilmar Rodrigues é Arquiteto de Soluções da AWS no time de setor público com foco em empresas de Utilities. Trabalhou anteriormente com arquitetura e integração de aplicações em empresas do setor de telecomunicações e varejo.