mozak.tech Engenharia de IA Corporativa 23%

Parte I — Operações e Infraestrutura Potencializadas por IA

1.7 — Verificação Automatizada de Conformidade e Segurança em IaC (Security Compliance)

Objetivo da Aula

Ao concluir esta aula, você será capaz de:

Implementar detector de secrets hardcoded via regex (senhas, API keys, URLs com credenciais)

Implementar scanner de IaC que identifica recursos com configurações inseguras

Completar gerar_relatorio_compliance() com seções SOC2 e ISO27001

Usar Claude para análise contextualizada e plano de remediação priorizado

Entender as categorias de controles SOC2 e ISO27001 relevantes para IaC

Por que isso importa

Secrets hardcoded são a causa #1 de brechas de segurança em repositórios de código. Em 2023, o GitHub reportou que sua ferramenta de detecção de secrets bloqueou mais de 1 milhão de commits com credenciais expostas. Uma única DATABASE_URL com senha em texto no código pode comprometer um banco de dados inteiro.

Para compliance SOC2 e ISO27001, relatórios de segurança são mandatórios em auditorias. Um scanner automatizado que gera esses relatórios reduz semanas de trabalho manual de auditoria para minutos.

Conceitos Fundamentais

Detector de Secrets via Regex

PADROES_SECRETS = [

    (r'(?i)(password|passwd|pwd)\s*=\s*["\']([^"\']{8,})["\']', 'PASSWORD'),

    (r'(?i)(secret|api_key|access_key)\s*=\s*["\']([^"\']{10,})["\']', 'SECRET/API_KEY'),

    (r'sk-ant-api\d+-[a-zA-Z0-9]+', 'ANTHROPIC_API_KEY'),

    (r'AKIA[0-9A-Z]{16}', 'AWS_ACCESS_KEY'),

    (r'postgresql://[^@]+:[^@]+@[^/]+', 'DATABASE_URL_COM_CREDENCIAIS'),

]



def detectar_secrets(codigo: str) -> list[dict]:

    encontrados = []

    for padrao, tipo in PADROES_SECRETS:

        for match in re.finditer(padrao, codigo):

            linha = codigo[:match.start()].count('\n') + 1

            encontrados.append({

                'tipo': tipo,

                'linha': linha,

                'trecho': match.group(0)[:50] + '...',

                'severidade': 'CRITICO',

            })

    return encontrados

re.finditer retorna todos os matches — não apenas o primeiro. codigo[:match.start()].count('\n') + 1 conta linhas até o início do match para reportar a linha exata.

Scanner de IaC

CHECKLIST_SEGURANCA = [

    ('S3 público', r'acl\s*=\s*["\']public', 'CRITICO', 'Remover ACL pública'),

    ('SSH aberto', r'from_port\s*=\s*22.*cidr_blocks.*0\.0\.0\.0/0', 'CRITICO', 'Restringir SSH a IPs corporativos'),

    ('RDS público', r'publicly_accessible\s*=\s*true', 'ALTO', 'Colocar RDS em subnet privada'),

    ('Sem encryption', r'resource.*aws_db_instance(?!.*encrypted)', 'MEDIO', 'Habilitar encryption at rest'),

    ('Sem tags', r'resource.*\{(?!.*tags)', 'BAIXO', 'Adicionar tags obrigatórias'),

]



def escanear_iac(codigo: str) -> list[dict]:

    problemas = []

    for nome, padrao, severidade, remediacao in CHECKLIST_SEGURANCA:

        if re.search(padrao, codigo, re.DOTALL | re.IGNORECASE):

            problemas.append({'nome': nome, 'severidade': severidade, 'remediacao': remediacao})

    return problemas

re.DOTALL faz . matchear \n — essencial para padrões que se espalham por múltiplas linhas no HCL.

TODO: gerar_relatorio_compliance(analise, problemas, secrets)

O TODO pede completar o relatório com as categorias SOC2 e ISO27001:

def gerar_relatorio_compliance(analise: str, problemas: list, secrets: list) -> str:

    criticos = len([p for p in problemas + secrets if p.get('severidade') == 'CRITICO'])

    altos = len([p for p in problemas if p.get('severidade') == 'ALTO'])

    medios = len([p for p in problemas if p.get('severidade') == 'MEDIO'])

    

    # Classificação por categoria de compliance

    itens_acesso = [p for p in problemas if p['nome'] in ('SSH aberto', 'S3 público', 'RDS público')]

    itens_crypto = [p for p in problemas if p['nome'] in ('Sem encryption',)]

    itens_secrets_list = [s for s in secrets if s['tipo'] in ('PASSWORD', 'SECRET/API_KEY')]

    

    status_geral = 'REPROVADO' if criticos > 0 else ('AVISO' if altos > 0 else 'APROVADO')

    

    return f'''# Relatório de Compliance — {datetime.now().strftime('%Y-%m-%d')}



## Sumário Executivo

- **Status**: {status_geral}

- Secrets expostos: {len(secrets)}

- Problemas críticos: {criticos} | Altos: {altos} | Médios: {medios}



---



## SOC2 — Critérios Relevantes



### CC6 — Controle de Acesso Lógico

{"✅ Nenhuma violação de controle de acesso" if not itens_acesso else chr(10).join(f"❌ {p['nome']}: {p['remediacao']}" for p in itens_acesso)}



### CC6.7 — Credenciais em Repositórios

{"✅ Nenhuma credencial exposta" if not itens_secrets_list else chr(10).join(f"❌ {s['tipo']} na linha {s.get('linha', '?')}" for s in itens_secrets_list)}



### CC7 — Operações do Sistema

{"✅ Recursos com configurações seguras" if not problemas else chr(10).join(f"⚠️ {p['nome']}: {p['remediacao']}" for p in problemas[:3])}



---



## ISO27001 — Controles Aplicáveis



### A.9 — Controle de Acesso

{"✅ Sem violações detectadas" if not itens_acesso else chr(10).join(f"❌ {p['nome']}: {p['remediacao']}" for p in itens_acesso)}



### A.10 — Criptografia

{"✅ Recursos com encryption configurada" if not itens_crypto else chr(10).join(f"❌ {p['nome']}: {p['remediacao']}" for p in itens_crypto)}



### A.12 — Segurança de Operações

Recursos monitorados: {len(problemas)} verificações realizadas



---



## Plano de Remediação Priorizado



{analise[:600]}



---



## Próximos Passos

1. Rotacionar IMEDIATAMENTE qualquer credencial exposta

2. Aplicar fixes críticos antes do próximo deploy

3. Adicionar pré-commit hook com detect-secrets

4. Revisar e aprovar este relatório com equipe de segurança

'''

Aprofundamento Técnico

Categorias SOC2 TC Relevantes para DevOps

Categoria

Sigla

O que verifica

Logical Access

CC6

Controle de quem acessa recursos

System Operations

CC7

Monitoramento e detecção de anomalias

Change Management

CC8

Processos de deploy e aprovação

Para IaC, CC6 é o mais crítico: recursos sem controle de acesso (S3 público, SSH aberto, RDS acessível) violam diretamente CC6.

ISO27001 Relevante

Controle

Descrição

A.9.1

Política de controle de acesso

A.10.1

Criptografia em trânsito e em repouso

A.12.6

Gestão de vulnerabilidades técnicas

A.14.2

Segurança no ciclo de desenvolvimento

Integração com Pre-commit Hooks

# .pre-commit-config.yaml

repos:

- repo: https://github.com/Yelp/detect-secrets

  rev: v1.4.0

  hooks:

  - id: detect-secrets

    args: ['--baseline', '.secrets.baseline']



- repo: https://github.com/bridgecrewio/checkov

  rev: v3.0.0

  hooks:

  - id: checkov

    args: ['--quiet', '--framework', 'terraform']

Com esses hooks, qualquer commit com secrets ou IaC inseguro é bloqueado antes de entrar no repositório.

Exemplos Anotados

Exemplo 1: Código com Todos os Problemas

CODIGO_INSEGURO = '''

DATABASE_URL = "postgresql://admin:SuperSecret123@prod-db.internal:5432/myapp"

AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"



resource "aws_s3_bucket" "data" {

  bucket = "company-data-prod"

  acl    = "public-read"          # ← S3 público

}



resource "aws_security_group_rule" "ssh" {

  from_port   = 22

  cidr_blocks = ["0.0.0.0/0"]   # ← SSH aberto para o mundo

}

'''



secrets = detectar_secrets(CODIGO_INSEGURO)

# → [{'tipo': 'DATABASE_URL_COM_CREDENCIAIS', 'linha': 2, ...}, {'tipo': 'AWS_SECRET_KEY', ...}]



problemas = escanear_iac(CODIGO_INSEGURO)

# → [{'nome': 'S3 público', 'severidade': 'CRITICO', ...}, {'nome': 'SSH aberto', ...}]



analise = analisar_com_llm(CODIGO_INSEGURO, problemas, secrets)

relatorio = gerar_relatorio_compliance(analise, problemas, secrets)

print(relatorio)

Exemplo 2: Relatório Completo com Seções SOC2

# Com o TODO implementado, o relatório inclui:

print(relatorio)

# → # Relatório de Compliance — 2024-01-15

# → ## Sumário Executivo

# → - Status: REPROVADO

# → - Secrets expostos: 3

# → - Problemas críticos: 2 | Altos: 1 | Médios: 1

# → ...

# → ## SOC2 — Critérios Relevantes

# → ### CC6 — Controle de Acesso Lógico

# → ❌ S3 público: Remover ACL pública

# → ❌ SSH aberto: Restringir SSH a IPs corporativos

Padrões e Armadilhas

Padrões

Padrão 1: Truncar trecho do secret no relatório

'trecho': match.group(0)[:50] + '...',  # não expor o secret completo no log

O relatório confirma que um secret foi encontrado, mas não o expõe completo — afinal, o relatório pode ser compartilhado.

Padrão 2: re.DOTALL para padrões multilinha em HCL

re.search(padrao, codigo, re.DOTALL | re.IGNORECASE)

# DOTALL: '.' inclui '\n' → padrões podem cruzar linhas

# IGNORECASE: 'PASSWORD' e 'password' e 'Password' são iguais

Padrão 3: Severidade estruturada para priorização

# Ordenar por severidade antes de exibir

ORDEM = {'CRITICO': 0, 'ALTO': 1, 'MEDIO': 2, 'BAIXO': 3}

problemas.sort(key=lambda p: ORDEM.get(p['severidade'], 4))

Armadilhas

⚠️ Armadilha 1: Falsos positivos em nomes de variáveis

# "password_validation" vai matchear o padrão de PASSWORD

# Use palavra delimitadores mais precisos:

r'(?i)\bpassword\b\s*=\s*["\'][^"\']{8,}["\']'  # \b = word boundary

⚠️ Armadilha 2: Scanner de IaC baseado em string não detecta variáveis

resource "aws_s3_bucket" "data" {

  acl = var.bucket_acl  # ← "public-read" como variável não é detectado

}

Para isso, use checkov ou tfsec que fazem análise estática real do HCL.

⚠️ Armadilha 3: Relatório de compliance sem data e escopo

# Sem data e repositório, o relatório não tem validade legal

f'# Relatório de Compliance — {datetime.now().strftime("%Y-%m-%d")}\n'

f'## Escopo: repositório {repo_url}, branch {branch}'
⚗ Laboratório prático — mozak.tech
Se não for realizar o laboratório, pule para o próximo capítulo.

Ponte para o Lab

1 TODO principal no starter.py:

TODO — gerar_relatorio_compliance(analise, problemas, secrets): Complete as seções [TODO: preencher...] com os dados reais dos parâmetros:

# SOC2 CC6:

itens_acesso = [p for p in problemas if 'público' in p['nome'] or 'SSH' in p['nome']]

for item in itens_acesso:

    texto += f"❌ {item['nome']}: {item['remediacao']}\n"



# ISO27001 A.10:

itens_crypto = [p for p in problemas if 'encryption' in p['nome'].lower()]

for item in itens_crypto:

    texto += f"❌ {item['nome']}: {item['remediacao']}\n"

Rode python starter.py e verifique que o relatório inclui todas as categorias de compliance preenchidas.

Agora você está pronto para o lab.