O Que é Infrastructure as Code Security?
Infrastructure as Code (IaC) é a prática de gerenciar e provisionar infraestrutura de computação através de código em vez de processos manuais. Essa abordagem traz versionamento, automação e rastreabilidade, mas introduz um novo vetor de risco: vulnerabilidades definidas no próprio código. Se você escrever uma política de segurança IAM permissiva, um bucket S3 públicamente acessível ou credenciais em plain text no seu código de infraestrutura, essas falhas se propagarão para todos os ambientes que utilizarem esse código.
Security scanning de IaC é o processo de análise estática desse código antes da execução, identificando problemas de configuração, compliance e práticas inadequadas. Ferramentas como Checkov, tfsec e KICS funcionam como guardiões: elas analisam seus arquivos Terraform antes do deploy e apontam riscos antes que se tornem incidentes de segurança em produção. Este artigo abordará como dominar essas três ferramentas e entender quando e como utilizá-las.
Entendendo as Três Ferramentas: Características e Diferenças
Checkov: Abrangência Multiplataforma
Checkov é desenvolvido pela Bridgecrew (adquirida pela Palo Alto Networks) e destaca-se pela suporte a múltiplas plataformas IaC: Terraform, CloudFormation, Kubernetes, Docker, Helm, Dockerfile e até mesmo arquivos de configuração genéricos. Sua força está na quantidade de verificações (mais de 700 políticas), cobertura ampla de frameworks de compliance (CIS, PCI-DSS, HIPAA, SOC2) e integração profunda com pipelines CI/CD.
O Checkov funciona como um scanner que analisa o código declarativo antes da execução e mapeia recursos com políticas de segurança. Uma verificação típica verifica se um grupo de segurança permite acesso SSH de 0.0.0.0/0 ou se um bucket S3 tem versionamento habilitado. A ferramenta produz relatórios detalhados que indicam linha exata do problema, severity e remediation.
tfsec: Especialização em Terraform
tfsec, desenvolvido pela Aqua Security, é uma ferramenta focada especificamente em análise de segurança de código Terraform. Por ser especializada, ela oferece um conjunto robusto de verificações altamente otimizadas para as particularidades do Terraform. O tfsec é particularmente bom em detectar problemas com recursos AWS, Azure e GCP, com mensagens de erro claras e sugestões de correção.
A principal vantagem do tfsec é a velocidade e precisão nas análises Terraform. Ele entende profundamente a sintaxe HCL (HashiCorp Configuration Language) e consegue detectar problemas contextuais, não apenas estruturais. Por exemplo, tfsec identifica quando você usa var.enable_encryption condicionalmente em um recurso, alertando se essa variável poderia ser falsa em produção.
KICS: Flexibilidade e Detecção de Padrões
KICS (Keeping Infrastructure as Code Secure) é um projeto open-source mantido pela Checkmarx que oferece análise profunda através de queries Rego (linguagem do Open Policy Agent). KICS suporta Terraform, CloudFormation, Kubernetes, Dockerfile, Docker Compose, Helm, AWS SAM e JSON/YAML genéricos. Sua grande diferença é a capacidade de criar regras customizadas através de queries Rego sem necessidade de recompilar a ferramenta.
KICS é ideal quando você precisa de regras específicas do seu contexto organizacional. Enquanto Checkov e tfsec vêm com regras pré-compiladas e você as usa "como estão", KICS permite que você escreva suas próprias queries usando Open Policy Agent, tornando-o extremamente flexível para organizações com políticas de segurança não-padrão.
Instalação e Configuração Prática
Instalando Checkov
# Instalação via pip (Python)
pip install checkov
# Ou via Homebrew no macOS
brew install checkov
# Verificar instalação
checkov --version
Após a instalação, você pode executar uma verificação básica em um diretório com código Terraform:
checkov -d ./terraform --framework terraform
Esse comando varre todos os arquivos .tf no diretório e executa todas as políticas Terraform disponíveis. O Checkov produzirá um relatório mostrando passed checks, failed checks e skipped checks.
Para configuração customizada, crie um arquivo .checkov.yaml na raiz do seu projeto:
framework:
- terraform
check:
skip-check:
- CKV_AWS_1 # Disable a specific check
external-checks-dir:
- ./custom-checks
output: json
Instalando tfsec
# Via Homebrew (macOS/Linux)
brew install tfsec
# Via Go
go install github.com/aquasecurity/tfsec/cmd/tfsec@latest
# Verificar instalação
tfsec --version
Para usar tfsec em um projeto:
# Scan de um diretório
tfsec ./terraform
# Scan com formato JSON para processamento
tfsec ./terraform -f json > tfsec-report.json
# Ignorar problemas específicos
tfsec ./terraform --skip aws_s3_bucket_public_access_block_not_enabled
Crie um arquivo .tfsec/config.json para customizar comportamento:
{
"minimum_severity": "WARNING",
"format": "sarif",
"enable_all_checks": true,
"exclude_modules": ["terraform-aws-modules"]
}
Instalando KICS
# Via Homebrew
brew install kics
# Via Docker (recomendado para CI/CD)
docker pull checkmarx/kics:latest
# Verificar instalação
kics --version
Para executar KICS:
# Scan básico
kics scan -p ./terraform -t Terraform
# Com output JSON
kics scan -p ./terraform -t Terraform -o json --output-name kics-report
# Via Docker
docker run -v $(pwd):/path/to/project checkmarx/kics scan -p /path/to/project -t Terraform
Crie um arquivo kics.config.json para customização:
{
"log_level": "INFO",
"payload_lines": true,
"minimal_ui": false,
"no-color": false,
"format": "json",
"disable-secrets": false,
"output-path": "./kics-results"
}
Exemplos Práticos: Detectando Vulnerabilidades Comuns
Exemplo 1: Bucket S3 Público Sem Encriptação
Considere este código Terraform problemático:
resource "aws_s3_bucket" "data_bucket" {
bucket = "my-unencrypted-data-bucket"
}
resource "aws_s3_bucket_public_access_block" "data_bucket_pab" {
bucket = aws_s3_bucket.data_bucket.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data_bucket_sse" {
bucket = aws_s3_bucket.data_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
Ao executar cada ferramenta, aqui está o que elas detectam:
Checkov:
$ checkov -f main.tf --framework terraform
Check: CKV_AWS_56: "Ensure S3 bucket has public access block"
File: main.tf:1-6
Severity: HIGH
Status: FAILED
Check: CKV_AWS_20: "S3 Bucket has an ACL which allows public access"
File: main.tf:1-6
Severity: HIGH
Status: FAILED
tfsec:
$ tfsec main.tf
aws_s3_bucket.data_bucket
Line 1: S3 bucket does not have logging configured
Rule: AWS016
aws_s3_bucket_public_access_block.data_bucket_pab
Lines 8-12: Public access is not blocked
Rule: AWS077
KICS:
$ kics scan -p . -t Terraform
[Results]
Description: S3 Bucket allows public access
File: main.tf
Line: 8
CWE: CWE-732
Severity: HIGH
O código corrigido seria:
resource "aws_s3_bucket" "data_bucket" {
bucket = "my-encrypted-data-bucket"
force_destroy = false
tags = {
Name = "Secure Data Bucket"
}
}
resource "aws_s3_bucket_versioning" "data_bucket_versioning" {
bucket = aws_s3_bucket.data_bucket.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_public_access_block" "data_bucket_pab" {
bucket = aws_s3_bucket.data_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data_bucket_sse" {
bucket = aws_s3_bucket.data_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.s3_key.arn
}
}
}
resource "aws_s3_bucket_logging" "data_bucket_logging" {
bucket = aws_s3_bucket.data_bucket.id
target_bucket = aws_s3_bucket.log_bucket.id
target_prefix = "logs/"
}
resource "aws_kms_key" "s3_key" {
description = "KMS key for S3 encryption"
deletion_window_in_days = 7
enable_key_rotation = true
}
Exemplo 2: Security Group Com Acesso SSH Aberto
Código vulnerável:
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # CRÍTICO: SSH aberto para a internet
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Todas as três ferramentas detectam isso:
Checkov detecta:
CKV_AWS_24: "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22"
Status: FAILED
tfsec detecta:
Rule: AWS006
Description: AWS Security Group allows unrestricted ingress on port 22
KICS detecta:
Description: Security group allows SSH access from anywhere
Severity: HIGH
Correção apropriada:
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = aws_vpc.main.id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion_sg.id] # Apenas de bastion
description = "SSH from bastion host only"
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTP from internet"
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS from internet"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "web-sg"
}
}
Exemplo 3: RDS Com Encryption Desabilitada e Backup Inadequado
Código vulnerável:
resource "aws_db_instance" "main" {
identifier = "main-database"
engine = "postgres"
engine_version = "13.7"
instance_class = "db.t3.micro"
allocated_storage = 20
storage_type = "gp2"
db_name = "maindb"
username = "admin"
password = "hardcodedpassword123!" # CRÍTICO
storage_encrypted = false # CRÍTICO
backup_retention_days = 0 # CRÍTICO
skip_final_snapshot = true # CRÍTICO
publicly_accessible = true # CRÍTICO
}
Detecções esperadas:
Checkov:
CKV_AWS_29: "Ensure DB instance backup retention is enabled"
CKV_AWS_35: "Ensure all data stored in RDS is encrypted"
CKV_AWS_79: "Ensure RDS instances are not publicly accessible"
CKV_AWS_52: "Ensure RDS snapshot are encrypted"
tfsec:
Rule: AWS016: RDS database encryption not enabled
Rule: AWS018: RDS backup retention not configured
Rule: AWS078: RDS instance publicly accessible
KICS:
Description: Credentials exposed in plain text
Description: Database encryption not enabled
Description: Database publicly accessible
Código corrigido:
# Usar AWS Secrets Manager para credenciais
resource "aws_secretsmanager_secret" "db_password" {
name = "rds-main-password"
recovery_window_in_days = 7
}
resource "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
secret_string = jsonencode({
username = "admin"
password = random_password.db_password.result
})
}
resource "random_password" "db_password" {
length = 32
special = true
}
resource "aws_db_instance" "main" {
identifier = "main-database"
engine = "postgres"
engine_version = "13.7"
instance_class = "db.t3.micro"
allocated_storage = 20
storage_type = "gp2"
db_name = "maindb"
username = "admin"
password = random_password.db_password.result
storage_encrypted = true
kms_key_id = aws_kms_key.rds_key.arn
backup_retention_period = 30
skip_final_snapshot = false
final_snapshot_identifier = "main-database-final-snapshot-${formatdate("YYYY-MM-DD-hhmm", timestamp())}"
publicly_accessible = false
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.rds_sg.id]
enabled_cloudwatch_logs_exports = ["postgresql"]
multi_az = true
deletion_protection = true
tags = {
Name = "main-database"
}
}
resource "aws_kms_key" "rds_key" {
description = "KMS key for RDS encryption"
deletion_window_in_days = 7
enable_key_rotation = true
}
resource "aws_db_subnet_group" "main" {
name = "main-db-subnet-group"
subnet_ids = [aws_subnet.private_1.id, aws_subnet.private_2.id]
}
resource "aws_security_group" "rds_sg" {
name = "rds-sg"
vpc_id = aws_vpc.main.id
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app_sg.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Integração em CI/CD e Melhores Práticas
Pipeline GitLab CI
stages:
- validate
- plan
- security-scan
- apply
validate:
stage: validate
image: hashicorp/terraform:latest
script:
- terraform fmt -check
- terraform validate
security-checkov:
stage: security-scan
image: bridgecrew/checkov:latest
script:
- checkov -d ./terraform --framework terraform --output json
artifacts:
reports:
sast: checkov-report.json
allow_failure: true
security-tfsec:
stage: security-scan
image: aquasec/tfsec:latest
script:
- tfsec ./terraform --format json --out tfsec-report.json
artifacts:
reports:
sast: tfsec-report.json
allow_failure: true
security-kics:
stage: security-scan
image: checkmarx/kics:latest
script:
- kics scan -p ./terraform -t Terraform -f json --output-name kics-report
artifacts:
reports:
sast: kics-report.json
allow_failure: true
plan:
stage: plan
image: hashicorp/terraform:latest
script:
- terraform plan -out=tfplan
artifacts:
paths:
- tfplan
GitHub Actions
name: Terraform Security Scan
on:
pull_request:
paths:
- 'terraform/**'
push:
branches:
- main
jobs:
checkov:
runs-on: ubuntu-latest
name: Checkov Scan
steps:
- uses: actions/checkout@v3
- name: Run Checkov
id: checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform
framework: terraform
output_format: json
output_file_path: reports/checkov.json
tfsec:
runs-on: ubuntu-latest
name: tfsec Scan
steps:
- uses: actions/checkout@v3
- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.0
with:
working_directory: terraform
format: json
output_file: reports/tfsec.json
kics:
runs-on: ubuntu-latest
name: KICS Scan
steps:
- uses: actions/checkout@v3
- name: Run KICS
uses: Checkmarx/kics-github-action@master
with:
path: terraform
type: Terraform
output_path: reports/kics.json
Makefile Para Execução Local
.PHONY: security-scan security-checkov security-tfsec security-kics
security-scan: security-checkov security-tfsec security-kics
@echo "All security scans completed"
security-checkov:
@echo "Running Checkov..."
checkov -d ./terraform --framework terraform --output json > reports/checkov.json
@grep -c "passed check" reports/checkov.json || echo "Review Checkov results"
security-tfsec:
@echo "Running tfsec..."
tfsec ./terraform -f json --out reports/tfsec.json || true
@echo "tfsec completed"
security-kics:
@echo "Running KICS..."
kics scan -p ./terraform -t Terraform -f json -o reports/kics.json || true
@echo "KICS completed"
fmt:
terraform fmt -recursive ./terraform
validate:
terraform validate
plan:
terraform plan -out=tfplan
apply:
terraform apply tfplan
full-check: fmt validate security-scan plan
@echo "Full check completed successfully"
Escolhendo a Ferramenta Certa Para Seu Caso
A decisão entre Checkov, tfsec e KICS não é necessariamente excludente. Muitas organizações usam múltiplas ferramentas:
Use Checkov quando: você trabalha com múltiplos frameworks IaC (Terraform, CloudFormation, Kubernetes) e precisa de uma solução unificada. Sua integração com plataformas comerciais (Prisma Cloud) é excelente se você já está no ecossistema Palo Alto Networks. O suporte a compliance frameworks pré-configurados é robusto.
Use tfsec quando: você trabalha exclusivamente com Terraform e quer a melhor experiência específica para essa linguagem. A ferramenta é leve, rápida e excelente para pipelines CI/CD com feedback imediato. Mensagens de erro claras facilitam correção rápida.
Use KICS quando: você precisa de regras customizadas específicas do seu contexto organizacional ou compliance. A capacidade de escrever queries Rego oferece flexibilidade máxima. Ideal para organizações com políticas de segurança única e não-padrão.
Conclusão
Os três pontos principais que você deve levar para sua prática profissional:
Primeiro: Infrastructure as Code Security é um componente essencial do seu pipeline DevSecOps. Detectar problemas de segurança no código, antes do deployment, é exponencialmente mais barato e menos disruptivo que corrigir em produção. As três ferramentas (Checkov, tfsec e KICS) são maduras, confiáveis e amplamente adotadas na indústria.
Segundo: Não existe "melhor ferramenta" absoluta — existe a ferramenta mais adequada para seu contexto. Avalie seu stack tecnológico (apenas Terraform vs. múltiplos IaC), sua necessidade de customização (regras padrão vs. políticas customizadas) e sua integração existente com plataformas de segurança. Muitas grandes organizações integram todas as três.
Terceiro: A automação de segurança é apenas tão boa quanto o processo que a rodeia. Configure os scanners no seu pipeline CI/CD, defina claramente o que é bloqueador vs. aviso, documente exceções apropriadas e, acima de tudo, cultive awareness do time sobre os problemas que essas ferramentas detectam. Uma ferramenta que ninguém entende é tão inútil quanto não ter ferramenta nenhuma.