19 de fevereiro de 2026 • 11 min de leitura
Security as Code Prevenindo Falhas Antes do Deploy
Em ambientes de nuvem, a velocidade dos deploys cresce continuamente. A cada sprint, releases se tornam mais frequentes, automatizadas e distribuídas. No entanto, essa agilidade traz um efeito colateral perigoso: erros de configuração podem ir para produção em minutos, abrindo portas para incidentes de segurança que poderiam ter sido evitados.
Times de desenvolvimento e infraestrutura operam hoje em modelos altamente ágeis: CI/CD, infra como código, microserviços.
Mas a segurança nem sempre acompanha esse ritmo.
Modelos tradicionais dependem de revisões manuais no final do ciclo, quando tudo já está pronto ou até mesmo em produção. E aí surgem dois problemas:
- Custo de correção mais alto
- Risco de incidentes devido a erros que poderiam ter sido barrados antes
Security as Code resolve esse gargalo ao trazer a segurança para o início do ciclo, automatizando verificações e prevenindo erros antes mesmo de chegar ao deploy.
O caso do bucket exposto
Todos os anos, vemos incidentes praticamente idênticos envolvendo buckets S3 públicos ou mal configurados. Alguns exemplos conhecidos:
- mcGraw Hill – milhões de registros de estudantes expostos
- Premier Diagnostics – dados sensíveis acessíveis publicamente
- Raindeer – informações pessoais deixadas em buckets sem proteção
O bucket não estava criptografado, não tinha autenticação adequada e estava acessível publicamente. O pior? Isso poderia ter sido evitado com uma simples verificação automatizada no código Terraform ou através de remediações automáticas através do AWS Config.
Esse tipo de falha não é exclusividade de grandes empresas. Qualquer organização que não tenha práticas de segurança automatizadas corre o mesmo risco. A diferença entre o desastre e a prevenção está em colocar a segurança no início do ciclo de desenvolvimento e é aí que entra o Security as Code.
O que é Security as Code
Security as Code é a prática de definir, versionar e automatizar políticas de segurança no mesmo fluxo de desenvolvimento e entrega de código.
Ao invés de revisar manualmente configurações depois que o ambiente está no ar, as regras são aplicadas e validadas antes do deploy.
Objetivos principais
- Prevenção proativa: evitar que configurações inseguras sejam criadas.
- Consistência: todos os ambientes seguem os mesmos padrões.
- Velocidade: segurança integrada ao pipeline, sem gargalos manuais.
- Compliance contínuo: auditoria facilitada com relatórios e histórico.
Security as Code no ciclo DevSecOps
O DevSecOps coloca a segurança como responsabilidade compartilhada entre desenvolvedores, operações e segurança. O Security as Code é o motor dessa abordagem, ele garante que as regras de segurança não fiquem “guardadas” em documentos, mas vivam no código e pipelines.
Fluxo simplificado:
- Desenvolvedor escreve código de infraestrutura.
- Pipeline executa verificações de segurança automaticamente.
- Se violar as regras → pipeline falha.
- Se passar → deploy autorizado.
Ferramentas populares de Security as Code
| Ferramenta | Foco principal | Pontos fortes |
|---|---|---|
| Checkov | IaC (Terraform, CloudFormation, K8s) | Open source, fácil de integrar, centenas de checks prontos. |
| OPA / Rego | Políticas genéricas | Muito flexível, pode validar qualquer formato de dado, mas requer curva de aprendizado. |
| Terraform Cloud Sentinel | Políticas para Terraform | Integração nativa com Terraform Enterprise/Cloud, mas proprietário. |
| CloudFormation Guard | Templates AWS CloudFormation | Focado em AWS, fácil para quem já usa CloudFormation. |
| Conftest | Políticas em YAML/JSON | Simples, versátil, ideal para pipelines leves. |
Estratégia do hands-on
Vamos criar alguns buckets no s3 via Terraform e implementar políticas que bloqueiem qualquer recurso s3 de estarem publicamente acessíveis e validar se outras features como versionamento esta habilitado. Isso será integrado à pipeline localmente, mas a mesma lógica pode ser aplicada no GitHub Actions, GitLab CI, etc.
Cenário 1: Bloqueio de buckets públicos na conta
Arquivo block_public_access.tf:
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_account_public_access_block" "account_level" {
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}Vamos agora testar criar um bucket com public-read, a tentativa de aplicar public-read deve falhar, mostrando que o bloqueio está ativo.
aws s3api create-bucket --bucket bucket-teste-publico --region us-east-1
aws s3api put-bucket-acl --bucket bucket-teste-publico --acl public-readCenário 2: Política como código com Checkov
Arquivo insecure.tf: (inseguro propositalmente):
resource "aws_s3_bucket" "insecure" {
bucket = "bucket-sem-seguranca-${random_id.suffix.hex}"
}
resource "random_id" "suffix" {
byte_length = 4
}Criando política customizada do Checkov
Arquivo s3_policy.yaml:
metadata:
name: "S3 Buckets devem ter versionamento habilitado"
id: "CUSTOM_AWS_S3_1"
category: "Security"
scope:
provider: aws
definition:
and:
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: versioning
operator: existsExecute o checkov com a política customizada:
checkov -d . --external-checks-dir .Saída esperada:
FAILED for resource: aws_s3_bucket.insecureCorrigindo
Atualize o insecure.tf:
resource "aws_s3_bucket" "secure" {
bucket = "bucket-seguro-${random_id.suffix.hex}"
versioning {
enabled = true
}
}
resource "aws_s3_bucket" "log_bucket" {
bucket = "bucket-de-logs-${random_id.log_suffix.hex}"
}
resource "random_id" "log_suffix" {
byte_length = 4
}Agora é só executar o scan novamente e agora ele deve retornar sucesso:
checkov -d . --external-checks-dir .Auto-remediação com AWS Config
Em ambientes dinâmicos, com múltiplas contas, times diferentes e centenas de recursos sendo criados diariamente, um risco adicional surge: o drift, quando um recurso muda depois do deploy e foge dos padrões aprovados.
É aqui que entra o AWS Config, um dos serviços mais poderosos da AWS para quem deseja segurança contínua e governança automatizada, ele permite:
- Monitorar recursos em tempo real
- Registrar todo o histórico de alterações
- Avaliar se cada recurso está em conformidade com as regras da empresa
- Gerar alertas
- Principalmente, aplicar auto-remediação quando algo estiver fora do padrão
Ou seja:
Se um desvio acontecer, ele será corrigido automaticamente sem intervenção humana.
Isso reduz risco operacional, diminui o tempo de exposição e aumenta a maturidade de segurança da organização.
Como funciona o ciclo de auto-remediação
1.Regra do AWS Config monitora um recurso e avalia se ele está em conformidade. 2. Se a avaliação for NON_COMPLIANT, a regra pode acionar:
- Um SSM Automation Runbook, ou
- Uma Lambda Function
- O runbook/função executa a correção e retorna o recurso ao estado desejado.
- AWS Config reavalia o recurso e confirma a conformidade.
Garantir que grupos de segurança não permitam tráfego 0.0.0.0/0 na porta 22
Mesmo em ambientes maduros, um dos problemas mais recorrentes é a abertura acidental de portas perigosas para a internet especialmente SSH. Isso representa risco de ataques de força bruta e exposição desnecessária do servidor.
Objetivo da auto-remediação
- Detectar automaticamente qualquer Security Group que permita acesso SSH de qualquer origem pública.
- Executar uma ação de correção removendo a regra insegura.
1. Regra do AWS Config
Usamos a regra gerenciada: INCOMING_SSH_DISABLED Ela verifica se existe alguma regra de inbound SSH aberta para 0.0.0.0/0.
2. Ação de remediação
Podemos anexar um SSM Automation Runbook que remove automaticamente a regra insegura.
Exemplo de runbook pronto da AWS: AWS-DisablePublicAccessForSecurityGroup ele:
- localiza regras de entrada perigosas
- remove apenas aquelas que estão fora da conformidade
- mantém outras regras intactas
Fluxo da auto-remediação
- Alguém cria ou altera um Security Group e adiciona a regra:
Inbound
Porta: `22`
Origem: `0.0.0.0/0`- AWS Config detecta a regra e marca como NON_COMPLIANT
- O runbook é acionado automaticamente
- A regra insegura é removida em segundos
- O recurso volta ao estado COMPLIANT
Métricas e ROI: O impacto real do Security as Code
Implementar Security as Code não é apenas uma questão de segurança, é também um investimento com retorno mensurável. Organizações que adotam essas práticas reportam:
Redução de vulnerabilidades
- 70-80% menos vulnerabilidades críticas chegando a produção (fonte: estudos de DevSecOps da Gartner)
- Tempo médio de detecção (MTTD) reduzido de dias para minutos
- Tempo médio de remediação (MTTR) reduzido em até 60%
Economia de tempo e recursos
- Revisões manuais de segurança: de 2-3 dias para execução automatizada em minutos
- Custo de correção: corrigir na fase de desenvolvimento custa 10x menos que em produção
- Horas de engenharia: times economizam 15-20 horas/semana em revisões manuais
Impacto financeiro
Considere o custo médio de um incidente de segurança:
- Pequenas empresas: $120k - $1.2M por incidente
- Médias empresas: $1.2M - $8.5M por incidente
- Grandes empresas: $8.5M+ por incidente
Um único bucket S3 exposto pode resultar em:
- Multas regulatórias (LGPD, GDPR)
- Perda de confiança de clientes
- Custos de resposta a incidentes
- Danos à reputação
ROI típico: Para cada $1 investido em Security as Code, empresas economizam $5-10 em custos de remediação e incidentes evitados.
Integração com CI/CD: GitHub Actions e GitLab CI
Vamos ver como integrar o Checkov em pipelines reais de CI/CD.
GitHub Actions
Crie o arquivo .github/workflows/security-scan.yml:
name: Security Scan
on:
pull_request:
branches: [ main, develop ]
push:
branches: [ main ]
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: cli,sarif
output_file_path: console,results.sarif
soft_fail: false # Falha o pipeline se encontrar problemas
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: results.sarif
- name: Comment PR with results
uses: actions/github-script@v6
if: github.event_name == 'pull_request'
with:
script: |
const fs = require('fs');
const results = fs.readFileSync('results.sarif', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '## Security Scan Results\n\n' + results
});GitLab CI
Crie o arquivo .gitlab-ci.yml:
stages:
- security
- deploy
security_scan:
stage: security
image: bridgecrew/checkov:latest
script:
- checkov -d terraform/ --output cli --output json --output-file-path console,checkov-report.json
artifacts:
reports:
sast: checkov-report.json
paths:
- checkov-report.json
expire_in: 1 week
allow_failure: false # Bloqueia o pipeline se falhar
deploy:
stage: deploy
script:
- terraform apply -auto-approve
only:
- main
needs:
- security_scanOutput real do Checkov
Quando você executa o Checkov, a saída é bem detalhada:
$ checkov -d terraform/
_ _
___| |__ ___ ___| | _______ __
/ __| '_ \ / _ \/ __| |/ / _ \ \ / /
| (__| | | | __/ (__| < (_) \ V /
\___|_| |_|\___|\___|_|\_\___/ \_/
By bridgecrew.io | version: 2.3.187
terraform scan results:
Passed checks: 12, Failed checks: 3, Skipped checks: 0
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-18
Guide: https://docs.bridgecrew.io/docs/s3_13-enable-logging
15 | resource "aws_s3_bucket" "data" {
16 | bucket = "my-data-bucket"
17 | acl = "private"
18 | }
Check: CKV_AWS_19: "Ensure the S3 bucket has server-side encryption enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-18
Check: CKV_AWS_21: "Ensure the S3 bucket has versioning enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-18Comparação: Checkov vs OPA/Rego
Vamos ver a mesma política implementada em ambas as ferramentas.
Checkov (YAML)
metadata:
name: "S3 deve ter encryption e versioning"
id: "CUSTOM_S3_SECURE"
category: "Security"
scope:
provider: aws
definition:
and:
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: versioning.enabled
operator: equals
value: true
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: server_side_encryption_configuration
operator: existsOPA/Rego
package terraform.s3
import input as tfplan
deny[msg] {
resource := tfplan.resource_changes[_]
resource.type == "aws_s3_bucket"
not resource.change.after.versioning[_].enabled
msg := sprintf(
"S3 bucket '%s' deve ter versionamento habilitado",
[resource.address]
)
}
deny[msg] {
resource := tfplan.resource_changes[_]
resource.type == "aws_s3_bucket"
not resource.change.after.server_side_encryption_configuration
msg := sprintf(
"S3 bucket '%s' deve ter encryption habilitado",
[resource.address]
)
}Quando usar cada um:
- Checkov: Mais simples, ideal para começar, centenas de checks prontos
- OPA/Rego: Mais flexível, ideal para políticas complexas e customizadas
Troubleshooting e boas práticas
Falsos positivos comuns
Problema 1: Buckets de logs não precisam de versionamento
# Solução: Criar exceção por tag
metadata:
name: "S3 versioning exceto logs"
id: "CUSTOM_S3_VERSIONING"
scope:
provider: aws
definition:
and:
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: versioning.enabled
operator: equals
value: true
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: tags.Purpose
operator: not_equals
value: "logs"Problema 2: Recursos legados que não podem ser alterados
Use o arquivo .checkov.baseline para suprimir checks específicos:
# .checkov.baseline
{
"checks": {
"CKV_AWS_18": {
"skip": [
{
"id": "aws_s3_bucket.legacy_bucket",
"reason": "Bucket legado, migração planejada para Q2 2025"
}
]
}
}
}Debugging de políticas customizadas
Use o modo verbose para entender por que uma política falhou:
checkov -d . --external-checks-dir policies/ -vTeste políticas isoladamente:
# Testar apenas uma política específica
checkov -d . --check CUSTOM_S3_SECUREEstrutura de repositório recomendada
.
├── .github/
│ └── workflows/
│ └── security-scan.yml
├── terraform/
│ ├── modules/
│ │ ├── s3/
│ │ ├── ec2/
│ │ └── vpc/
│ ├── environments/
│ │ ├── dev/
│ │ ├── staging/
│ │ └── prod/
│ └── main.tf
├── policies/
│ ├── s3/
│ │ ├── encryption.yaml
│ │ ├── versioning.yaml
│ │ └── public-access.yaml
│ ├── iam/
│ │ └── least-privilege.yaml
│ └── ec2/
│ └── security-groups.yaml
├── .checkov.baseline
└── README.mdCasos de uso avançados
1. Validação de IAM Policies
Política Checkov para IAM:
metadata:
name: "IAM roles não devem ter wildcard em actions"
id: "CUSTOM_IAM_NO_WILDCARD"
category: "IAM"
scope:
provider: aws
definition:
cond_type: attribute
resource_types:
- aws_iam_role_policy
- aws_iam_policy
attribute: policy
operator: not_contains
value: '"Action": "*"'2. Encryption at Rest obrigatória
Para RDS:
metadata:
name: "RDS deve ter encryption at rest"
id: "CUSTOM_RDS_ENCRYPTION"
scope:
provider: aws
definition:
cond_type: attribute
resource_types:
- aws_db_instance
attribute: storage_encrypted
operator: equals
value: truePara EBS:
metadata:
name: "EBS volumes devem ser criptografados"
id: "CUSTOM_EBS_ENCRYPTION"
scope:
provider: aws
definition:
cond_type: attribute
resource_types:
- aws_ebs_volume
attribute: encrypted
operator: equals
value: true3. Compliance com frameworks
PCI-DSS Requirement 3.4 (Encryption):
metadata:
name: "PCI-DSS 3.4: Dados sensíveis devem ser criptografados"
id: "PCI_DSS_3_4"
category: "Compliance"
guidelines: "PCI-DSS v3.2.1"
scope:
provider: aws
definition:
or:
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: server_side_encryption_configuration
operator: exists
- cond_type: attribute
resource_types:
- aws_db_instance
attribute: storage_encrypted
operator: equals
value: trueHIPAA Security Rule (Encryption):
metadata:
name: "HIPAA: PHI deve ser criptografado em repouso"
id: "HIPAA_ENCRYPTION"
category: "Compliance"
guidelines: "HIPAA Security Rule § 164.312(a)(2)(iv)"
scope:
provider: aws
definition:
and:
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: tags.DataClassification
operator: equals
value: "PHI"
- cond_type: attribute
resource_types:
- aws_s3_bucket
attribute: server_side_encryption_configuration
operator: existsIntegração com SIEM e Observabilidade
Enviando resultados para Datadog
# send_to_datadog.py
import json
import requests
import os
def send_checkov_to_datadog(report_file):
with open(report_file) as f:
results = json.load(f)
api_key = os.getenv('DD_API_KEY')
for check in results['results']['failed_checks']:
event = {
'title': f"Security Check Failed: {check['check_id']}",
'text': check['check_name'],
'alert_type': 'error',
'tags': [
f"resource:{check['resource']}",
f"check_id:{check['check_id']}",
'source:checkov',
'security:vulnerability'
]
}
requests.post(
'https://api.datadoghq.com/api/v1/events',
headers={'DD-API-KEY': api_key},
json=event
)
if __name__ == '__main__':
send_checkov_to_datadog('checkov-report.json')Dashboard de Compliance
Crie métricas customizadas no Datadog:
# datadog-dashboard.json
{
"title": "Security as Code - Compliance Dashboard",
"widgets": [
{
"definition": {
"type": "timeseries",
"requests": [
{
"q": "sum:checkov.failed_checks{*} by {severity}",
"display_type": "bars"
}
],
"title": "Failed Security Checks por Severidade"
}
},
{
"definition": {
"type": "query_value",
"requests": [
{
"q": "sum:checkov.compliance_score{*}",
"aggregator": "avg"
}
],
"title": "Compliance Score (%)",
"precision": 2
}
}
]
}Alertas proativos
Configure alertas no Datadog para notificar quando:
# datadog-monitor.yaml
name: "Critical Security Checks Failed"
type: metric alert
query: "sum(last_5m):sum:checkov.failed_checks{severity:critical} > 0"
message: |
{{#is_alert}}
Checks de segurança críticos falharam!
Recursos afetados: {{value}}
Ação necessária: Revisar o PR e corrigir antes do merge.
{{/is_alert}}
tags:
- security
- critical
- checkovGovernança de políticas
Quem aprova mudanças nas políticas?
Estabeleça um processo claro:
- Proposta: Qualquer membro do time pode propor uma nova política
- Revisão técnica: Time de segurança valida a política
- Teste: Política é testada em ambiente de dev/staging
- Aprovação: Requer aprovação de Security Lead + Engineering Manager
- Rollout gradual: Implementar primeiro como warning, depois como bloqueio
CODEOWNERS para políticas
# .github/CODEOWNERS
/policies/ @security-team
/policies/iam/* @security-team @iam-admins
/policies/network/* @security-team @network-team
/.checkov.baseline @security-team @engineering-managersVersionamento de políticas
Use tags semânticas:
git tag -a policies-v1.2.0 -m "Adiciona validação de encryption para RDS"
git push origin policies-v1.2.0Próximos passos
Se você chegou até aqui, já tem todo o conhecimento necessário para começar. Agora é hora de agir:
Para começar hoje:
- Instale o Checkov:
pip install checkov - Rode um scan no seu código:
checkov -d terraform/ - Analise os resultados: identifique os 3 problemas mais críticos
- Corrija um por vez: comece pequeno, ganhe confiança
- Automatize: adicione ao seu pipeline de CI/CD
Recursos adicionais:
- Documentação oficial do Checkov
- OPA Policy Library
- AWS Config Rules Repository
- CIS Benchmarks para AWS
- OWASP Cloud Security
Conclusão
Security as Code não é um luxo e nem uma tendência: é um pilar obrigatório para empresas que querem operar em nuvem com segurança e velocidade.
A diferença entre organizações que sofrem incidentes de segurança e aquelas que os previnem está na capacidade de automatizar, validar e remediar problemas antes que cheguem à produção.
Começar pode parecer intimidador, mas lembre-se: você não precisa implementar tudo de uma vez. Comece com os checks mais críticos, ganhe experiência, e expanda gradualmente.
O importante é dar o primeiro passo hoje. Seu futuro eu (e seu time de segurança) vão agradecer.