Como Usar Infrastructure as Code Security: Checkov, tfsec e KICS para Terraform em Produção Já leu

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

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.

Referências


Artigos relacionados