Segurança de Infraestrutura

Defense in Depth

Segurança não é um produto que você instala. É uma propriedade emergente do sistema inteiro. O modelo de Defense in Depth assume que qualquer camada individual pode falhar — e projeta múltiplas camadas independentes para que a falha de uma não comprometa o sistema.

┌── Defense in Depth ─────────────────────────────────────────────────┐
│                                                                      │
│  Camada 1: Perímetro (Network)                                      │
│  ├── Firewall, WAF, DDoS protection, rate limiting                  │
│  │                                                                   │
│  Camada 2: Rede Interna (Network Segmentation)                      │
│  ├── VPC subnets, security groups, NACLs, mTLS                     │
│  │                                                                   │
│  Camada 3: Host (Server Hardening)                                  │
│  ├── CIS Benchmarks, SELinux/AppArmor, auditd, patches             │
│  │                                                                   │
│  Camada 4: Aplicação (Application Security)                         │
│  ├── AuthN/AuthZ, input validation, SAST/DAST, WAF rules           │
│  │                                                                   │
│  Camada 5: Dados (Data Protection)                                  │
│  ├── Encryption at rest/in transit, backup, access control          │
│  │                                                                   │
│  Camada 6: Monitoramento (Detection & Response)                     │
│  ├── Audit logs, alertas, incident response, SIEM                   │
│                                                                      │
│  Se o atacante passar pela camada 1, encontra a camada 2.           │
│  Se passar pela 2, encontra a 3. E assim por diante.               │
└──────────────────────────────────────────────────────────────────────┘

Threat Modeling com STRIDE

Antes de proteger, você precisa entender o que está protegendo e de quem. O STRIDE é um framework da Microsoft para categorizar ameaças:

┌──────────────────────┬──────────────────────────────────────────────┐
│ Ameaça               │ Descrição                                     │
├──────────────────────┼──────────────────────────────────────────────┤
│ Spoofing             │ Fingir ser outra entidade (user, service)     │
│ Tampering            │ Modificar dados em trânsito ou em repouso    │
│ Repudiation          │ Negar ter feito uma ação (sem audit trail)   │
│ Information Disclosure│ Vazamento de dados sensíveis                 │
│ Denial of Service    │ Tornar o sistema indisponível                │
│ Elevation of Privilege│ Ganhar acesso além do autorizado             │
└──────────────────────┴──────────────────────────────────────────────┘

Para cada componente do sistema, pergunte:
- Quem pode acessar isso?
- O que acontece se os dados forem modificados?
- Temos logs suficientes para auditoria?
- O que acontece se este serviço ficar fora do ar?
- Um usuário comum pode escalar privilégios?

Princípio do Menor Privilégio

Cada componente, usuário ou serviço deve ter apenas as permissões estritamente necessárias para sua função. Nada mais.

# IAM Policy: princípio do menor privilégio
# Ruim: acesso total ao S3
resource "aws_iam_policy" "bad_example" {
  policy = jsonencode({
    Statement = [{
      Effect   = "Allow"
      Action   = "s3:*"              # Tudo no S3
      Resource = "*"                  # Todos os buckets
    }]
  })
}

# Bom: apenas o necessário
resource "aws_iam_policy" "good_example" {
  policy = jsonencode({
    Statement = [{
      Effect   = "Allow"
      Action   = [
        "s3:GetObject",              # Apenas leitura
        "s3:PutObject"               # E escrita
      ]
      Resource = "arn:aws:s3:::my-app-uploads/*"  # Apenas neste bucket
    }]
  })
}

Security through obscurity (esconder como o sistema funciona) nunca funciona como estratégia primária. O atacante vai descobrir. Segurança real assume que o atacante conhece seu sistema por completo — e mesmo assim não consegue comprometê-lo.


Hardening de Servidores

Hardening é o processo de reduzir a superfície de ataque de um servidor. Cada serviço rodando, cada porta aberta, cada usuário com acesso é um vetor potencial.

CIS Benchmarks

O Center for Internet Security publica benchmarks detalhados para hardening de sistemas operacionais. São centenas de controles específicos:

# Exemplos de controles CIS para Ubuntu/Debian

# 1. Desabilitar filesystems desnecessários
cat >> /etc/modprobe.d/CIS.conf << 'EOF'
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
EOF

# 2. Configurar permissões em arquivos críticos
chmod 644 /etc/passwd
chmod 600 /etc/shadow
chmod 644 /etc/group
chmod 600 /etc/gshadow

# 3. Garantir que root é a única conta UID 0
awk -F: '($3 == 0) { print }' /etc/passwd
# Deve retornar apenas: root:x:0:0:root:/root:/bin/bash

# 4. Configurar login timeout
echo "TMOUT=900" >> /etc/profile.d/timeout.sh
# Sessões inativas são desconectadas após 15 min

# 5. Desabilitar core dumps
echo "* hard core 0" >> /etc/security/limits.conf
echo "fs.suid_dumpable = 0" >> /etc/sysctl.conf

Kernel Hardening

# /etc/sysctl.d/99-security.conf

# Proteção contra IP spoofing
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Desabilitar IP source routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Ignorar ICMP redirects (previne MITM)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Ignorar ICMP broadcasts (previne Smurf attack)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Log pacotes marcianos (IPs impossíveis)
net.ipv4.conf.all.log_martians = 1

# Proteção contra SYN flood
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048

# Desabilitar IP forwarding (se não for router/gateway)
net.ipv4.ip_forward = 0

# ASLR (Address Space Layout Randomization) — dificulta exploits
kernel.randomize_va_space = 2

# Restringir acesso a dmesg
kernel.dmesg_restrict = 1

# Restringir acesso a kernel pointers
kernel.kptr_restrict = 2

AppArmor e SELinux

São sistemas de controle de acesso mandatório (MAC) que restringem o que processos podem fazer, mesmo que rodem como root.

# AppArmor (Ubuntu/Debian) — verificar status
sudo aa-status

# Exemplo de profile AppArmor para nginx
# /etc/apparmor.d/usr.sbin.nginx
/usr/sbin/nginx {
  # Pode ler configuração
  /etc/nginx/** r,

  # Pode ler conteúdo web
  /var/www/** r,

  # Pode escrever logs
  /var/log/nginx/** w,

  # Pode escutar em portas de rede
  network inet stream,

  # Não pode acessar /home, /root, /etc/shadow, etc.
  # Tudo que não está explicitamente permitido é bloqueado
}

# SELinux (RHEL/CentOS) — verificar status
getenforce   # Enforcing, Permissive, Disabled

# SELinux labels: contexto de segurança em cada arquivo/processo
ls -Z /var/www/html/
# system_u:object_r:httpd_sys_content_t:s0 index.html

# Se nginx não pode ler um arquivo, verifique o contexto SELinux
chcon -t httpd_sys_content_t /var/www/html/new-file.html
# Ou melhor, use semanage para regras permanentes

Infraestrutura Imutável

A abordagem moderna para hardening: não corrija servidores, substitua-os. Servidores são descartáveis. Se precisa de atualização, crie uma nova imagem e faça deploy.

# Packer — criar golden images automaticamente
# server-image.pkr.hcl
source "amazon-ebs" "ubuntu" {
  ami_name      = "hardened-ubuntu-{{timestamp}}"
  instance_type = "t3.micro"
  region        = "us-east-1"

  source_ami_filter {
    filters = {
      name                = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*"
      root-device-type    = "ebs"
      virtualization-type = "hvm"
    }
    owners      = ["099720109477"]  # Canonical
    most_recent = true
  }

  ssh_username = "ubuntu"
}

build {
  sources = ["source.amazon-ebs.ubuntu"]

  # Aplicar hardening CIS
  provisioner "shell" {
    script = "scripts/cis-hardening.sh"
  }

  # Instalar agentes necessários
  provisioner "shell" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y cloudwatch-agent fail2ban auditd",
      "sudo apt-get autoremove -y",
      "sudo apt-get clean"
    ]
  }

  # Remover credenciais SSH temporárias
  provisioner "shell" {
    inline = [
      "sudo rm -f /home/ubuntu/.ssh/authorized_keys",
      "sudo rm -f /root/.ssh/authorized_keys",
      "sudo shred -u /etc/ssh/*_key /etc/ssh/*_key.pub"
    ]
  }
}

SSH Hardening

# /etc/ssh/sshd_config — configuração segura

# Desabilitar login como root
PermitRootLogin no

# Apenas autenticação por chave (nunca senha)
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no

# Algoritmos seguros apenas
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Timeout e limites
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3
MaxSessions 3
LoginGraceTime 30

# Restringir usuários e grupos
AllowGroups ssh-users

# Desabilitar forwarding desnecessário
AllowTcpForwarding no
X11Forwarding no
AllowStreamLocalForwarding no

Para ambientes maiores, use SSH com certificados em vez de chaves públicas individuais:

# SSH Certificate Authority — centralizar confiança

# 1. Criar CA (uma vez)
ssh-keygen -t ed25519 -f /etc/ssh/ca_host_key -C "Host CA"
ssh-keygen -t ed25519 -f /etc/ssh/ca_user_key -C "User CA"

# 2. Assinar chave do servidor (cada servidor)
ssh-keygen -s /etc/ssh/ca_host_key -I "web-server-01" \
  -h -n web-server-01.internal \
  -V +52w \
  /etc/ssh/ssh_host_ed25519_key.pub

# 3. Assinar chave do usuário (cada desenvolvedor)
ssh-keygen -s /etc/ssh/ca_user_key -I "lucas@company" \
  -n ubuntu,deploy \
  -V +8h \
  ~/.ssh/id_ed25519.pub
# Certificado válido por 8 horas apenas

# 4. Configurar servidor para confiar na CA
echo "TrustedUserCAKeys /etc/ssh/ca_user_key.pub" >> /etc/ssh/sshd_config

Bastion Host / Jump Box

┌── Internet ──┐       ┌── VPC ────────────────────────────────────┐
│               │       │                                            │
│  Developer ───┼──SSH──▶  Bastion Host (public subnet)             │
│               │       │  ├── Único ponto de entrada SSH           │
│               │       │  ├── MFA obrigatório                      │
│               │       │  ├── Sessões logadas (auditd)             │
│               │       │  └───SSH──▶ App servers (private subnet)  │
│               │       │            ├── Server 1                   │
│               │       │            ├── Server 2                   │
│               │       │            └── Server 3                   │
│               │       │                                            │
│               │       │  Security Group do Bastion:               │
│               │       │  Inbound: 22/tcp de VPN CIDR apenas       │
│               │       │                                            │
│               │       │  Security Group dos App Servers:           │
│               │       │  Inbound: 22/tcp APENAS do Bastion SG     │
└───────────────┘       └────────────────────────────────────────────┘

# Alternativa moderna: AWS SSM Session Manager
# Sem necessidade de bastion, sem porta SSH aberta
aws ssm start-session --target i-0abc123def456

System Auditing com auditd

# /etc/audit/rules.d/audit.rules

# Monitorar alterações em arquivos de autenticação
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers

# Monitorar alterações em configuração SSH
-w /etc/ssh/sshd_config -p wa -k sshd_config

# Monitorar execuções com sudo
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -k privileged_commands

# Monitorar modificações de data/hora
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
-a always,exit -F arch=b64 -S clock_settime -k time-change

# Monitorar mount/unmount de filesystems
-a always,exit -F arch=b64 -S mount -F auid>=1000 -k mounts

# Monitorar deleção de arquivos
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -k delete

# Tornar regras imutáveis (requer reboot para alterar)
-e 2

Network Security

Firewall: iptables e nftables

# iptables — regras básicas de servidor web

# Política padrão: negar tudo
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Permitir loopback
iptables -A INPUT -i lo -j ACCEPT

# Permitir conexões estabelecidas (respostas)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Permitir SSH apenas de rede interna
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT

# Permitir HTTP/HTTPS de qualquer origem
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Rate limiting para prevenir brute force SSH
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
  -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
  -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

# Log pacotes descartados (debugging)
iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A INPUT -j DROP
# nftables — substituto moderno do iptables
# /etc/nftables.conf

table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;

    # Loopback e conexões estabelecidas
    iif lo accept
    ct state established,related accept

    # SSH rate limited
    tcp dport 22 ip saddr 10.0.0.0/8 ct state new \
      limit rate 3/minute accept

    # HTTP/HTTPS
    tcp dport { 80, 443 } accept

    # Log e dropar o resto
    log prefix "nftables-drop: " counter drop
  }

  chain output {
    type filter hook output priority 0; policy accept;
  }
}

Network Segmentation

┌── Arquitetura DMZ ──────────────────────────────────────────────────┐
│                                                                      │
│  Internet                                                            │
│     │                                                                │
│     ▼                                                                │
│  ┌── DMZ (Zona Desmilitarizada) ──────────────────────────────────┐ │
│  │  Firewall Externo                                                │ │
│  │  ├── WAF / Load Balancer                                        │ │
│  │  ├── Reverse Proxy (nginx)                                      │ │
│  │  └── Apenas portas 80/443 abertas                               │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│     │ (apenas tráfego HTTP para app servers)                        │
│     ▼                                                                │
│  ┌── Application Zone ────────────────────────────────────────────┐ │
│  │  Firewall Interno                                                │ │
│  │  ├── App servers (portas 3000, 8080)                            │ │
│  │  ├── Workers / Message consumers                                │ │
│  │  └── Sem acesso direto da internet                              │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│     │ (apenas portas de DB)                                         │
│     ▼                                                                │
│  ┌── Data Zone ───────────────────────────────────────────────────┐ │
│  │  ├── Databases (5432, 3306, 27017)                              │ │
│  │  ├── Cache (6379)                                               │ │
│  │  └── Sem rota para internet (air-gapped)                        │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│                                                                      │
│  Regra: cada zona só fala com a zona adjacente.                     │
│  DMZ nunca acessa Data Zone diretamente.                            │
└──────────────────────────────────────────────────────────────────────┘

VPN e WireGuard

# WireGuard — VPN moderna, rápida e simples
# Muito mais simples que OpenVPN, performance superior

# Instalar (servidor)
apt install wireguard

# Gerar chaves (cada peer)
wg genkey | tee privatekey | wg pubkey > publickey

# Configuração do servidor (/etc/wireguard/wg0.conf)
[Interface]
Address = 10.200.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key>

# Regras de firewall automáticas
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \
         iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \
           iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# Peer: desenvolvedor
[Peer]
PublicKey = <developer_public_key>
AllowedIPs = 10.200.0.2/32

# Peer: outro desenvolvedor
[Peer]
PublicKey = <dev2_public_key>
AllowedIPs = 10.200.0.3/32
# Configuração do cliente (desenvolvedor)
[Interface]
Address = 10.200.0.2/24
PrivateKey = <developer_private_key>
DNS = 10.0.0.2   # DNS interno da empresa

[Peer]
PublicKey = <server_public_key>
Endpoint = vpn.company.com:51820
AllowedIPs = 10.0.0.0/8   # Rotear apenas tráfego interno pela VPN
PersistentKeepalive = 25

# Ativar
sudo wg-quick up wg0

Service Mesh Security (mTLS)

# Istio — mTLS automático entre todos os serviços
# PeerAuthentication: exigir mTLS no namespace
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT   # Apenas conexões mTLS aceitas

---
# AuthorizationPolicy: controle fino de acesso
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: api-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: api-server
  rules:
    - from:
        - source:
            principals:
              - "cluster.local/ns/production/sa/frontend"
              - "cluster.local/ns/production/sa/mobile-bff"
      to:
        - operation:
            methods: ["GET", "POST"]
            paths: ["/api/*"]
    # Apenas frontend e mobile-bff podem acessar o api-server
    # Todo o resto é negado implicitamente

WAF (Web Application Firewall)

# AWS WAF com regras customizadas
resource "aws_wafv2_web_acl" "main" {
  name  = "production-waf"
  scope = "REGIONAL"

  default_action { allow {} }

  # Regra 1: Bloquear SQL Injection
  rule {
    name     = "SQLInjection"
    priority = 1
    action { block {} }
    statement {
      sqli_match_statement {
        field_to_match {
          body {}
        }
        text_transformation {
          priority = 1
          type     = "URL_DECODE"
        }
        text_transformation {
          priority = 2
          type     = "HTML_ENTITY_DECODE"
        }
      }
    }
    visibility_config {
      sampled_requests_enabled   = true
      cloudwatch_metrics_enabled = true
      metric_name                = "SQLInjection"
    }
  }

  # Regra 2: Regras gerenciadas AWS (OWASP Top 10)
  rule {
    name     = "AWSManagedRules"
    priority = 2
    override_action { none {} }
    statement {
      managed_rule_group_statement {
        vendor_name = "AWS"
        name        = "AWSManagedRulesCommonRuleSet"
      }
    }
    visibility_config {
      sampled_requests_enabled   = true
      cloudwatch_metrics_enabled = true
      metric_name                = "AWSManagedRules"
    }
  }

  # Regra 3: Rate limiting por IP
  rule {
    name     = "RateLimit"
    priority = 3
    action { block {} }
    statement {
      rate_based_statement {
        limit              = 1000
        aggregate_key_type = "IP"
      }
    }
    visibility_config {
      sampled_requests_enabled   = true
      cloudwatch_metrics_enabled = true
      metric_name                = "RateLimit"
    }
  }

  visibility_config {
    sampled_requests_enabled   = true
    cloudwatch_metrics_enabled = true
    metric_name                = "ProductionWAF"
  }
}

DDoS Protection

Estratégia em camadas contra DDoS:

1. Camada de Rede (L3/L4):
   ├── AWS Shield Standard (gratuito, automático)
   ├── Rate limiting no firewall
   └── Blackhole routing para IPs atacantes

2. Camada de Aplicação (L7):
   ├── AWS Shield Advanced (pago, com suporte DRT)
   ├── WAF rate limiting por IP
   ├── CloudFront como primeiro ponto de contato
   └── Regras de bot detection

3. Camada de DNS:
   ├── Route 53 com anycast (distribui globalmente)
   └── DNS rate limiting

4. Arquitetura resiliente:
   ├── Auto-scaling: absorver tráfego legítimo durante ataque
   ├── CDN: edge locations absorvem bulk do tráfego
   ├── Queues: buffer para proteger backend
   └── Circuit breakers: isolar serviços sob pressão

O objetivo não é bloquear 100% do ataque — é manter o serviço
disponível para usuários legítimos durante o ataque.

Secrets Management

Por que Variáveis de Ambiente Não São Suficientes

# Problema com env vars:

# 1. Visíveis no processo listing
ps aux -e    # Mostra env vars de todos os processos

# 2. Herdadas por processos filhos (incluindo maliciosos)
# Um child process de debug ou log pode capturar todas as env vars

# 3. Sem audit trail — ninguém sabe quem acessou

# 4. Sem rotação automática — trocar uma env var requer redeploy

# 5. Em container orchestrators, ficam no manifesto
# kubectl get deployment api -o yaml
# ... mostra DATABASE_URL em plaintext no spec

# 6. Aparecem em crash dumps, logs, e error reports
# Error: connect ECONNREFUSED postgresql://admin:S3cr3t@db:5432/app
#                                      ^^^^^^^^^^^^^^^^
#                                      Senha no log de erro

HashiCorp Vault

┌── Vault Architecture ───────────────────────────────────────────────┐
│                                                                      │
│  ┌─── Client (App) ───┐     ┌─── Vault Server ──────────────────┐ │
│  │                     │     │                                     │ │
│  │  1. Autenticar      │────▶│  Auth Methods:                     │ │
│  │  (JWT, K8s SA,      │     │  ├── Kubernetes Service Account   │ │
│  │   AWS IAM role)     │     │  ├── AWS IAM Role                  │ │
│  │                     │     │  ├── JWT/OIDC                      │ │
│  │  2. Receber token   │◀────│  └── AppRole                      │ │
│  │                     │     │                                     │ │
│  │  3. Ler secrets     │────▶│  Secrets Engines:                  │ │
│  │     com token       │     │  ├── KV (key-value)               │ │
│  │                     │     │  ├── Database (dynamic creds)      │ │
│  │  4. Usar secret     │◀────│  ├── PKI (certificados)           │ │
│  │     (TTL limitado)  │     │  └── Transit (encryption as API)  │ │
│  │                     │     │                                     │ │
│  └─────────────────────┘     │  Storage Backend:                  │ │
│                              │  ├── Consul, Raft, PostgreSQL      │ │
│                              │  └── Encrypted at rest             │ │
│                              └─────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
# Vault: secrets dinâmicos para PostgreSQL
# Vault gera credenciais temporárias sob demanda

# Configurar engine de database
vault secrets enable database

vault write database/config/myapp-db \
  plugin_name="postgresql-database-plugin" \
  allowed_roles="readonly","readwrite" \
  connection_url="postgresql://{{username}}:{{password}}@db.internal:5432/myapp" \
  username="vault_admin" \
  password="initial-password"

# Definir role (template de credenciais)
vault write database/roles/readonly \
  db_name="myapp-db" \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' \
    VALID UNTIL '{{expiration}}'; \
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  revocation_statements="REVOKE ALL ON ALL TABLES IN SCHEMA public FROM \"{{name}}\"; \
    DROP ROLE IF EXISTS \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# Aplicação solicita credenciais
vault read database/creds/readonly
# Key                Value
# ---                -----
# lease_id           database/creds/readonly/abc123
# lease_duration     1h
# username           v-app-readonly-x7k2j3
# password           A1b2C3d4E5-randomized

# Credenciais expiram automaticamente em 1 hora
# Cada instância da app recebe credenciais únicas
# Audit log registra quem pediu e quando
# Vault Transit: encryption as a service
# Sua app não gerencia chaves — Vault faz isso

# Ativar transit engine
vault secrets enable transit
vault write -f transit/keys/user-data

# Criptografar (app envia plaintext, Vault retorna ciphertext)
vault write transit/encrypt/user-data \
  plaintext=$(echo "cpf:123.456.789-00" | base64)
# ciphertext: vault:v1:8SDd3WHDOjf7mq69CyCqYjBXAiQQAVZRkFM

# Descriptografar
vault write transit/decrypt/user-data \
  ciphertext="vault:v1:8SDd3WHDOjf7mq69CyCqYjBXAiQQAVZRkFM"

# Benefícios:
# - App nunca tem acesso à chave de criptografia
# - Rotação de chaves sem re-criptografar dados
# - Audit trail de todas as operações de criptografia

AWS Secrets Manager e Parameter Store

# Secrets Manager: para credenciais com rotação automática
resource "aws_secretsmanager_secret" "db_credentials" {
  name                    = "production/database/credentials"
  recovery_window_in_days = 7
}

resource "aws_secretsmanager_secret_rotation" "db" {
  secret_id           = aws_secretsmanager_secret.db_credentials.id
  rotation_lambda_arn = aws_lambda_function.rotate_secret.arn

  rotation_rules {
    automatically_after_days = 30  # Rotação automática a cada 30 dias
  }
}

# Parameter Store: para configurações (mais barato)
resource "aws_ssm_parameter" "api_key" {
  name  = "/production/api/stripe-key"
  type  = "SecureString"          # Criptografado com KMS
  value = var.stripe_api_key
  tier  = "Standard"              # Grátis até 10.000 parâmetros
}

Kubernetes Secrets e External Secrets

# Kubernetes Secrets: base64, NÃO criptografado
# Qualquer pessoa com acesso ao namespace pode ler
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  # Isso é base64, não criptografia
  # echo -n "minha-senha" | base64 → bWluaGEtc2VuaGE=
  password: bWluaGEtc2VuaGE=

# Para secrets reais, use External Secrets Operator
---
# External Secrets: sincroniza secrets de fontes externas
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: password
      remoteRef:
        key: production/database/credentials
        property: password
    - secretKey: username
      remoteRef:
        key: production/database/credentials
        property: username

# O secret no Kubernetes é atualizado automaticamente
# quando o secret no AWS Secrets Manager muda

SOPS para Secrets em Git

# SOPS (Secrets OPerationS) — criptografar arquivos no git
# Suporta KMS, GCP KMS, Azure Key Vault, age, PGP

# Instalar
brew install sops age

# Gerar chave age (mais simples que PGP)
age-keygen -o keys.txt
# Public key: age1abc123...

# Criar arquivo de configuração
# .sops.yaml
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: \.enc\.yaml$
    age: >-
      age1abc123...,age1def456...
  - path_regex: \.enc\.json$
    age: >-
      age1abc123...
EOF

# Criptografar
sops -e secrets.yaml > secrets.enc.yaml

# O arquivo criptografado mantém as chaves em plaintext
# mas criptografa os valores:
# database:
#   password: ENC[AES256_GCM,data:abc123...,tag:xyz...]
#   host: ENC[AES256_GCM,data:def456...,tag:uvw...]

# Editar (descriptografa, abre editor, re-criptografa)
sops secrets.enc.yaml

# Descriptografar para uso
sops -d secrets.enc.yaml > secrets.yaml

# No CI/CD: export a chave age como variável secreta
# SOPS_AGE_KEY=AGE-SECRET-KEY-1abc... sops -d secrets.enc.yaml

Rotação de Secrets

Estratégia de rotação:

1. Rotação automática (ideal):
   ├── Vault dynamic secrets: novo secret a cada request
   ├── AWS Secrets Manager: Lambda de rotação
   └── Certificados: cert-manager com auto-renewal

2. Rotação manual com zero downtime:
   ├── Passo 1: Gerar novo secret
   ├── Passo 2: Configurar sistema para aceitar AMBOS (old + new)
   ├── Passo 3: Atualizar todas as aplicações para usar o novo
   ├── Passo 4: Verificar que ninguém usa o antigo
   └── Passo 5: Revogar o secret antigo

3. Frequência recomendada:
   ├── Database passwords: 30-90 dias
   ├── API keys: 90 dias
   ├── TLS certificates: 90 dias (Let's Encrypt padrão)
   ├── SSH keys: 6-12 meses
   └── Encryption keys: 12 meses (com re-wrap, não re-encrypt)

Container Security

Scanning de Imagens

# Trivy — scanner open-source da Aqua Security
# Detecta vulnerabilidades em imagens, filesystem, IaC

# Scan de imagem
trivy image myapp:latest

# Scan com severidade mínima e fail no CI
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest

# Scan de filesystem (detectar secrets, vulnerabilidades em deps)
trivy fs --security-checks vuln,secret,config .

# Scan de IaC (Terraform, Kubernetes manifests)
trivy config ./terraform/

# Exemplo de output:
# myapp:latest (ubuntu 22.04)
# ============================
# Total: 3 (HIGH: 2, CRITICAL: 1)
#
# ┌──────────────┬────────────────┬──────────┬─────────────────────┐
# │   Library    │ Vulnerability  │ Severity │  Fixed Version      │
# ├──────────────┼────────────────┼──────────┼─────────────────────┤
# │ openssl      │ CVE-2024-1234  │ CRITICAL │ 3.0.13-1            │
# │ curl         │ CVE-2024-5678  │ HIGH     │ 8.5.0-2             │
# │ libxml2      │ CVE-2024-9012  │ HIGH     │ 2.12.4-1            │
# └──────────────┴────────────────┴──────────┴─────────────────────┘

Containers Seguros

# Dockerfile com práticas de segurança

# 1. Usar imagem base específica e minimal
FROM node:22-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# 2. Multi-stage: imagem final sem ferramentas de build
FROM gcr.io/distroless/nodejs22-debian12

# 3. Nunca rodar como root
# Distroless já roda como nonroot por padrão

WORKDIR /app

# 4. Copiar apenas o necessário
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./

EXPOSE 3000

CMD ["dist/server.js"]
# Kubernetes: Pod com security context restritivo
apiVersion: v1
kind: Pod
metadata:
  name: secure-app
spec:
  securityContext:
    runAsNonRoot: true           # Proibir root
    runAsUser: 1000              # UID específico
    runAsGroup: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault       # Seccomp padrão do runtime

  containers:
    - name: app
      image: myapp:v1.2.3        # Tag específica, nunca :latest
      securityContext:
        allowPrivilegeEscalation: false   # Bloquear setuid
        readOnlyRootFilesystem: true      # Filesystem read-only
        capabilities:
          drop:
            - ALL                          # Remover todas as capabilities
      resources:
        limits:
          cpu: "500m"
          memory: "256Mi"
        requests:
          cpu: "100m"
          memory: "128Mi"
      volumeMounts:
        - name: tmp
          mountPath: /tmp                  # Único dir com escrita

  volumes:
    - name: tmp
      emptyDir:
        sizeLimit: 100Mi

Pod Security Standards

# Pod Security Admission: enforce no nível do namespace
# Três níveis: privileged, baseline, restricted

# Forçar modo restricted no namespace production
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

# restricted proíbe:
# - Containers como root
# - Privilege escalation
# - Host networking/ports/PID
# - Capabilities perigosas
# - Volumes hostPath
# - Seccomp profiles inseguros

Supply Chain Security

# Cosign — assinar e verificar imagens de container
# Parte do projeto Sigstore

# Gerar chave
cosign generate-key-pair

# Assinar imagem após build
cosign sign --key cosign.key myregistry.com/myapp:v1.2.3

# Verificar antes de deploy
cosign verify --key cosign.pub myregistry.com/myapp:v1.2.3

# Keyless signing (recomendado): usa OIDC identity
cosign sign myregistry.com/myapp:v1.2.3
# Autentica via GitHub Actions, GitLab CI, etc.

# SBOM: gerar lista de componentes
syft myregistry.com/myapp:v1.2.3 -o spdx-json > sbom.json

# Scan do SBOM para vulnerabilidades
grype sbom:./sbom.json
# Kyverno: policy para exigir imagens assinadas
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
    - name: verify-cosign-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "myregistry.com/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
                      -----END PUBLIC KEY-----

Imagens Base Seguras

Escolha de imagem base (menor = mais seguro):

┌─────────────────────┬──────────┬──────────────────────────────────┐
│ Imagem              │ Tamanho  │ Quando usar                       │
├─────────────────────┼──────────┼──────────────────────────────────┤
│ scratch             │ 0 MB     │ Go/Rust binários estáticos       │
│ distroless          │ ~20 MB   │ Java, Node.js, Python (produção) │
│ alpine              │ ~5 MB    │ Quando precisa de shell          │
│ ubuntu/debian slim  │ ~80 MB   │ Quando precisa de apt/ferramentas│
│ ubuntu/debian full  │ ~200 MB  │ Evitar em produção               │
└─────────────────────┴──────────┴──────────────────────────────────┘

Menos pacotes = menos vulnerabilidades = menor superfície de ataque

distroless não tem:
- Shell (sh, bash)
- Package manager (apt, apk)
- Ferramentas de debug (curl, wget, netcat)

Isso é feature, não bug: se o atacante conseguir RCE,
não tem shell para usar.

CI/CD Security

SAST (Static Application Security Testing)

# GitHub Actions: pipeline com security scanning
name: Security Pipeline
on: [push, pull_request]

jobs:
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Semgrep: SAST rápido e configurável
      - name: Semgrep Scan
        uses: semgrep/semgrep-action@v1
        with:
          config: >-
            p/security-audit
            p/secrets
            p/owasp-top-ten
        env:
          SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

      # CodeQL: análise profunda do GitHub
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: javascript, python

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3

SCA (Software Composition Analysis)

  dependency-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Trivy para vulnerabilidades em dependências
      - name: Trivy Dependency Scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'

      # Snyk como segunda opinião
      - name: Snyk Test
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

Secret Scanning em Commits

  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # Histórico completo para scan

      # gitleaks: detectar secrets em código
      - name: Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      # Exemplos do que gitleaks detecta:
      # - AWS Access Keys (AKIA...)
      # - Private keys (-----BEGIN RSA PRIVATE KEY-----)
      # - Tokens (ghp_, sk_live_, etc.)
      # - Database connection strings com senha
      # - .env files commitados acidentalmente
# Pre-commit hook: prevenir antes de commitar
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

# Instalar
pip install pre-commit
pre-commit install

# Agora, git commit roda gitleaks automaticamente
# Se detectar um secret, o commit é bloqueado

DAST (Dynamic Application Security Testing)

  dast:
    runs-on: ubuntu-latest
    needs: deploy-staging
    steps:
      # OWASP ZAP: scan dinâmico contra ambiente de staging
      - name: OWASP ZAP Baseline Scan
        uses: zaproxy/action-baseline@v0.12.0
        with:
          target: 'https://staging.myapp.com'
          rules_file_name: '.zap-rules.tsv'
          fail_action: 'warn'  # Ou 'fail' para bloquear

      # ZAP testa:
      # - SQL Injection
      # - XSS (Cross-Site Scripting)
      # - CSRF
      # - Headers de segurança faltando
      # - Information disclosure
      # - Server misconfiguration

SLSA Framework e Signed Builds

SLSA (Supply-chain Levels for Software Artifacts):

┌────────┬───────────────────────────────────────────────────────────┐
│ Level  │ Requisitos                                                 │
├────────┼───────────────────────────────────────────────────────────┤
│ SLSA 1 │ Build process documentado                                 │
│ SLSA 2 │ Build service hospedado + logs retidos                    │
│ SLSA 3 │ Build service hardened + provenance verificável           │
│ SLSA 4 │ Hermético, reproduzível, two-person review                │
└────────┴───────────────────────────────────────────────────────────┘

Provenance: metadados que descrevem COMO um artefato foi construído.
- Qual código fonte?
- Qual pipeline de build?
- Quais dependências?
- Em qual ambiente?
# GitHub Actions: gerar SLSA provenance
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write    # Para OIDC
      contents: read
      attestations: write

    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Generate SLSA Provenance
        uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
        with:
          image: myapp
          digest: ${{ steps.build.outputs.digest }}

Policy as Code com OPA/Gatekeeper

# Gatekeeper: OPA para Kubernetes
# Constraint Template: definir a regra
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Labels obrigatórias faltando: %v", [missing])
        }

---
# Constraint: aplicar a regra
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
  parameters:
    labels:
      - "team"
      - "environment"
      - "cost-center"

# Deploy sem essas labels sera rejeitado pelo admission controller

Zero Trust Architecture

Além do Perímetro

Modelo Tradicional (Castle and Moat):
┌─────────────────────────────────────────────────┐
│  Firewall (moat)                                 │
│  ┌─────────────────────────────────────────────┐ │
│  │  Rede Interna = CONFIÁVEL                   │ │
│  │  ├── Todos os serviços se comunicam livre   │ │
│  │  ├── VPN = dentro do "castelo"              │ │
│  │  └── Movimentação lateral trivial           │ │
│  └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
Problema: se o atacante entra, tem acesso a tudo.

Modelo Zero Trust:
┌─────────────────────────────────────────────────┐
│  Nenhuma rede é confiável                        │
│  ┌───────┐  mTLS  ┌───────┐  mTLS  ┌───────┐  │
│  │ Svc A │◄──────►│ Svc B │◄──────►│ Svc C │  │
│  │ AuthZ │        │ AuthZ │        │ AuthZ │   │
│  └───────┘        └───────┘        └───────┘   │
│                                                  │
│  Cada request:                                   │
│  ├── Identidade verificada (quem está pedindo?) │
│  ├── Autorização verificada (pode fazer isso?)  │
│  ├── Criptografado em trânsito (mTLS)           │
│  └── Logado e auditado                           │
└─────────────────────────────────────────────────┘

BeyondCorp: Zero Trust na Prática

Princípios do BeyondCorp (Google):

1. Acesso não depende da rede:
   - Estar na VPN corporativa NÃO te dá acesso
   - Estar em um cafe com WiFi pública NÃO te nega acesso
   - Acesso depende de identidade + contexto

2. Contexto de acesso:
   ├── Quem: identidade verificada (MFA obrigatório)
   ├── O quê: dispositivo saudável (patches, disk encryption)
   ├── Onde: localização (risk scoring)
   ├── Quando: horário usual vs suspeito
   └── Como: tipo de acesso (API, browser, CLI)

3. Access Proxy:
   - Todo acesso passa por um proxy central
   - Proxy verifica identidade + dispositivo + contexto
   - Decisão de acesso a cada request (não por sessão)
   - Sem conceito de "dentro da rede"

Ferramentas:
├── Google BeyondCorp Enterprise
├── Cloudflare Access
├── Tailscale + ACLs
└── Pomerium (open-source)

SPIFFE/SPIRE: Identidade de Workload

SPIFFE (Secure Production Identity Framework for Everyone):
Identidade para serviços, não só para pessoas.

┌── SPIRE Server ──────────────────────────────────────────────┐
│                                                                │
│  Registra workloads e emite identidades (SVIDs)               │
│  SVID = SPIFFE Verifiable Identity Document                   │
│  Formato: spiffe://trust-domain/path                          │
│                                                                │
│  Exemplos:                                                     │
│  spiffe://company.com/production/api-server                   │
│  spiffe://company.com/production/payment-service              │
│  spiffe://company.com/staging/api-server                      │
│                                                                │
│  ┌── SPIRE Agent (cada node) ──────────────────────────────┐ │
│  │  - Atesta identidade do workload (PID, K8s SA, etc.)    │ │
│  │  - Entrega X.509 certificate ou JWT com SVID            │ │
│  │  - Rotação automática de certificados                    │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘

# Com SPIFFE, cada serviço sabe quem está chamando:
# api-server recebe request com certificado:
#   Subject: spiffe://company.com/production/frontend
# api-server verifica: frontend pode acessar /api/users? Sim → allow

Network Policies no Kubernetes

# Default deny: bloquear todo tráfego no namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}     # Aplica a todos os pods
  policyTypes:
    - Ingress
    - Egress

---
# Permitir apenas tráfego específico
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-server-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api-server
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # Aceitar tráfego apenas do frontend e do ingress controller
    - from:
        - podSelector:
            matchLabels:
              app: frontend
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 3000
  egress:
    # Pode acessar apenas o database e o cache
    - to:
        - podSelector:
            matchLabels:
              app: postgresql
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    # Permitir DNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

Microsegmentation

Microsegmentação: firewall rules entre cada par de serviços.
Diferente de segmentação de rede (subnets), microsegmentação
opera no nível do workload individual.

Antes (flat network):
┌─────────────────────────────────────┐
│  Todos os serviços se comunicam     │
│  ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐   │
│  │ A │↔│ B │↔│ C │↔│ D │↔│ E │   │
│  └───┘ └───┘ └───┘ └───┘ └───┘   │
└─────────────────────────────────────┘

Depois (microsegmented):
┌─────────────────────────────────────┐
│  Apenas fluxos autorizados           │
│  ┌───┐  ┌───┐  ┌───┐               │
│  │ A │─→│ B │─→│ C │               │
│  └───┘  └───┘  └───┘               │
│                   │                  │
│                   ▼                  │
│         ┌───┐  ┌───┐               │
│         │ D │←─│ E │               │
│         └───┘  └───┘               │
│                                      │
│  A→B: permitido    A→C: bloqueado   │
│  B→C: permitido    D→A: bloqueado   │
│  C→E: permitido    E→B: bloqueado   │
└─────────────────────────────────────┘

Implementações:
├── Kubernetes Network Policies (CNI: Calico, Cilium)
├── Service mesh (Istio AuthorizationPolicy)
├── Cilium com eBPF (L3/L4/L7 policies)
└── Cloud-native: AWS Security Groups referencing SGs

Compliance e Governanca

Frameworks de Compliance

┌──────────────┬─────────────────────────────────────────────────────┐
│ Framework    │ O que é                                              │
├──────────────┼─────────────────────────────────────────────────────┤
│ SOC 2        │ Controles de segurança para SaaS.                   │
│ Type I       │ Design dos controles em um ponto no tempo.          │
│ Type II      │ Efetividade dos controles durante 6-12 meses.       │
│              │ Maioria dos clientes enterprise exige Type II.      │
├──────────────┼─────────────────────────────────────────────────────┤
│ ISO 27001    │ Sistema de gestão de segurança da informação.       │
│              │ Certificação internacional. Cobre políticas,        │
│              │ processos, controles técnicos.                      │
├──────────────┼─────────────────────────────────────────────────────┤
│ LGPD         │ Lei Geral de Proteção de Dados (Brasil).            │
│              │ Consentimento, direito ao acesso/exclusão,          │
│              │ DPO obrigatório, notificação de vazamento.          │
├──────────────┼─────────────────────────────────────────────────────┤
│ GDPR         │ Equivalente europeu da LGPD.                        │
│              │ Multas de até 4% do revenue global.                 │
├──────────────┼─────────────────────────────────────────────────────┤
│ PCI-DSS      │ Obrigatório se processa/armazena dados de cartão.  │
│              │ 12 requisitos rigorosos.                            │
│              │ Penalidades severas por non-compliance.             │
└──────────────┴─────────────────────────────────────────────────────┘

LGPD para Engenheiros

O que a LGPD exige na prática (para engenharia):

1. Minimização de dados:
   - Colete apenas o necessário
   - Não guarde dados "caso precise no futuro"
   - Defina TTL para dados pessoais

2. Criptografia:
   - Dados pessoais criptografados at rest e in transit
   - Pseudonimização quando possível

3. Direito ao acesso e exclusão:
   - API para exportar dados do usuário
   - API para deletar dados do usuário (todos os sistemas!)
   - Cascata de deleção em todos os serviços e backups

4. Audit trail:
   - Log de quem acessou dados pessoais
   - Log de consentimento (quando e para quê)

5. Notificação de vazamento:
   - Prazo: "prazo razoável" (ANPD recomenda 2 dias úteis)
   - Ter runbook de incident response pronto

6. Privacy by Design:
   - Segurança e privacidade desde o design, não como patch
   - Data Protection Impact Assessment para novos features

Infrastructure Compliance Scanning

# Checkov: scan de IaC para compliance
pip install checkov

# Scan de arquivos Terraform
checkov -d ./terraform/
# Checks:
# - S3 bucket sem encryption ❌
# - Security group com 0.0.0.0/0 no SSH ❌
# - RDS sem backup habilitado ❌
# - CloudTrail sem log file validation ❌

# Scan com framework específico
checkov -d ./terraform/ --framework terraform --check CIS_AWS

# tfsec: análise estática de Terraform (agora parte do Trivy)
trivy config --severity HIGH,CRITICAL ./terraform/
# Exemplo: Terraform configurado para compliance

# CloudTrail: audit log obrigatório
resource "aws_cloudtrail" "main" {
  name                          = "main-trail"
  s3_bucket_name                = aws_s3_bucket.cloudtrail.id
  include_global_service_events = true
  is_multi_region_trail         = true
  enable_log_file_validation    = true  # Checkov CKV_AWS_36

  cloud_watch_logs_group_arn = "${aws_cloudwatch_log_group.trail.arn}:*"
  cloud_watch_logs_role_arn  = aws_iam_role.cloudtrail.arn

  event_selector {
    read_write_type           = "All"
    include_management_events = true

    data_resource {
      type   = "AWS::S3::Object"
      values = ["arn:aws:s3"]
    }
  }

  kms_key_id = aws_kms_key.cloudtrail.arn  # Criptografar logs
}

# AWS Config: monitorar compliance contínua
resource "aws_config_configuration_recorder" "main" {
  name     = "main"
  role_arn = aws_iam_role.config.arn

  recording_group {
    all_supported                 = true
    include_global_resource_types = true
  }
}

# Config Rule: detectar recursos não-compliant
resource "aws_config_config_rule" "encrypted_volumes" {
  name = "encrypted-volumes"
  source {
    owner             = "AWS"
    source_identifier = "ENCRYPTED_VOLUMES"
  }
  # Alerta se algum EBS volume não está criptografado
}

Audit Logs e Evidence Collection

Audit logs servem para duas coisas:
1. Investigar incidentes (o que aconteceu?)
2. Provar compliance para auditores (podemos provar que os controles funcionam?)

O que logar:
├── Autenticação: login, logout, MFA, failed attempts
├── Autorização: acesso negado, escalação de privilégio
├── Mudanças: CRUD em dados sensíveis, mudanças de config
├── Acesso a dados: quem leu dados pessoais e quando
└── Sistema: deploy, scaling, mudanças de infra

Onde centralizar:
├── CloudTrail → S3 + Athena (AWS API calls)
├── VPC Flow Logs → S3 ou CloudWatch (rede)
├── Application logs → CloudWatch/Datadog/Elastic
├── Audit logs → SIEM (Splunk, Elastic Security, Datadog)
└── Kubernetes audit logs → Falco + SIEM

Retenção:
├── SOC 2: mínimo 1 ano
├── PCI-DSS: mínimo 1 ano (3 meses online)
├── LGPD: não especifica, mas "razoável"
└── Prática: 1 ano hot, 7 anos cold (S3 Glacier)

Incident Response Plan

Incident Response — todo time de infra precisa de um plano.
Não é para ler durante o incidente. É para treinar antes.

┌── Fases do Incident Response ────────────────────────────────────┐
│                                                                    │
│  1. Preparação                                                    │
│     ├── Runbooks documentados                                     │
│     ├── Canais de comunicação definidos (Slack channel, bridge)   │
│     ├── Roles: Incident Commander, Scribe, Technical Lead         │
│     ├── Ferramentas prontas (acesso a logs, dashboards)           │
│     └── Game days regulares (simular incidentes)                  │
│                                                                    │
│  2. Identificação                                                 │
│     ├── Alertas automáticos (monitoria)                           │
│     ├── Classificar severidade (SEV1-4)                           │
│     └── Abrir incident ticket                                     │
│                                                                    │
│  3. Contenção                                                     │
│     ├── Curto prazo: isolar sistema comprometido                  │
│     ├── Network isolation, revoke credentials                     │
│     └── Preservar evidências (não deletar logs!)                  │
│                                                                    │
│  4. Erradicação                                                   │
│     ├── Identificar root cause                                    │
│     ├── Remover acesso do atacante                                │
│     └── Patchar vulnerabilidade explorada                         │
│                                                                    │
│  5. Recuperação                                                   │
│     ├── Restaurar serviços                                        │
│     ├── Monitorar de perto                                        │
│     └── Verificar que atacante não manteve acesso                 │
│                                                                    │
│  6. Post-mortem                                                   │
│     ├── Timeline detalhada                                        │
│     ├── Root cause analysis (blameless)                           │
│     ├── Action items com owners e deadlines                       │
│     └── Compartilhar aprendizados com a empresa                   │
└────────────────────────────────────────────────────────────────────┘

Exercicios

Exercicio 1: Hardening de Servidor com CIS Benchmark

Crie um script de hardening baseado nos CIS Benchmarks para Ubuntu 22.04. O script deve:

#!/bin/bash
# hardening.sh — CIS Level 1 Benchmark (subset)
set -euo pipefail

echo "=== CIS Hardening Script ==="

# 1. Desabilitar filesystems desnecessários
echo "install cramfs /bin/true" >> /etc/modprobe.d/CIS.conf
echo "install squashfs /bin/true" >> /etc/modprobe.d/CIS.conf
echo "install udf /bin/true" >> /etc/modprobe.d/CIS.conf

# 2. Configurar sysctl (kernel hardening)
cat >> /etc/sysctl.d/99-cis.conf << 'EOF'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.tcp_syncookies = 1
kernel.randomize_va_space = 2
kernel.dmesg_restrict = 1
EOF
sysctl --system

# 3. Configurar SSH
sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/#MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
sed -i 's/X11Forwarding yes/X11Forwarding no/' /etc/ssh/sshd_config
echo "ClientAliveInterval 300" >> /etc/ssh/sshd_config
echo "ClientAliveCountMax 2" >> /etc/ssh/sshd_config
systemctl restart sshd

# 4. Configurar auditd
apt install -y auditd
cat >> /etc/audit/rules.d/cis.rules << 'EOF'
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /etc/ssh/sshd_config -p wa -k sshd
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -k privileged
EOF
systemctl enable auditd
systemctl restart auditd

# 5. Remover serviços desnecessários
systemctl disable --now avahi-daemon 2>/dev/null || true
systemctl disable --now cups 2>/dev/null || true
systemctl disable --now rpcbind 2>/dev/null || true
apt purge -y telnet rsh-client 2>/dev/null || true

# 6. Configurar fail2ban
apt install -y fail2ban
cat > /etc/fail2ban/jail.local << 'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
EOF
systemctl enable --now fail2ban

# 7. Permissões de arquivos críticos
chmod 644 /etc/passwd
chmod 600 /etc/shadow
chmod 644 /etc/group
chmod 600 /etc/gshadow

echo "=== Hardening completo. Verifique com: sudo lynis audit system ==="

Valide o resultado com Lynis:

# Instalar Lynis (auditor de segurança)
apt install -y lynis

# Rodar audit
lynis audit system

# Score alvo: >80 (sem hardening fica ~60)

Exercicio 2: Vault para Credenciais Dinamicas de Database

Configure o HashiCorp Vault para gerar credenciais PostgreSQL dinamicas com TTL de 1 hora:

# 1. Subir Vault em modo dev (apenas para exercício)
docker run -d --name vault \
  -p 8200:8200 \
  -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' \
  hashicorp/vault:latest

export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='myroot'

# 2. Subir PostgreSQL
docker run -d --name postgres \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=adminpassword \
  -e POSTGRES_DB=myapp \
  postgres:16

# 3. Configurar engine de database no Vault
vault secrets enable database

vault write database/config/myapp \
  plugin_name="postgresql-database-plugin" \
  allowed_roles="readonly","readwrite" \
  connection_url="postgresql://{{username}}:{{password}}@host.docker.internal:5432/myapp?sslmode=disable" \
  username="postgres" \
  password="adminpassword"

# 4. Criar role readonly
vault write database/roles/readonly \
  db_name="myapp" \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' \
    VALID UNTIL '{{expiration}}'; \
    GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  revocation_statements="REVOKE ALL ON ALL TABLES IN SCHEMA public FROM \"{{name}}\"; \
    DROP ROLE IF EXISTS \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# 5. Criar role readwrite
vault write database/roles/readwrite \
  db_name="myapp" \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' \
    VALID UNTIL '{{expiration}}'; \
    GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="4h"

# 6. Testar: solicitar credenciais
vault read database/creds/readonly
# username: v-token-readonly-abc123
# password: randomized-password
# lease_duration: 1h

# 7. Conectar com as credenciais dinâmicas
psql "postgresql://v-token-readonly-abc123:randomized-password@localhost:5432/myapp"

# 8. Verificar: credencial expira automaticamente após 1h
vault lease revoke -prefix database/creds/

Exercicio 3: Pipeline de CI/CD com Security Gates

Crie um GitHub Actions workflow que integra scanning de seguranca como gates obrigatorios:

# .github/workflows/security-pipeline.yml
name: Security Pipeline

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  # Gate 1: Secret scanning (bloqueia se encontrar secrets)
  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  # Gate 2: Dependency vulnerabilities
  dependency-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Trivy Dependency Scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'

  # Gate 3: SAST (static analysis)
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: semgrep/semgrep-action@v1
        with:
          config: p/security-audit p/owasp-top-ten

  # Gate 4: Container image scan
  container-scan:
    runs-on: ubuntu-latest
    needs: [secret-scan, dependency-scan, sast]
    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .

      - name: Trivy Image Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'

      - name: Sign image with cosign
        if: github.ref == 'refs/heads/main'
        uses: sigstore/cosign-installer@v3
      - run: cosign sign --yes myregistry.com/myapp:${{ github.sha }}
        if: github.ref == 'refs/heads/main'

  # Gate 5: IaC compliance scan
  iac-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Checkov IaC Scan
        uses: bridgecrewio/checkov-action@master
        with:
          directory: ./terraform/
          framework: terraform
          soft_fail: false

  # Deploy: apenas se todos os gates passarem
  deploy:
    runs-on: ubuntu-latest
    needs: [container-scan, iac-scan]
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - name: Deploy to production
        run: echo "All security gates passed. Deploying..."

Exercicio 4: Network Policy Zero Trust no Kubernetes

Implemente Network Policies que seguem o modelo Zero Trust para uma aplicacao com frontend, API e database:

# 1. Default deny em todo o namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: myapp
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

---
# 2. Frontend: recebe do ingress, acessa apenas a API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
  namespace: myapp
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 80
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 3000
    - to:   # DNS
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

---
# 3. API: recebe do frontend, acessa database e redis
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
  namespace: myapp
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 3000
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgresql
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    - to:   # DNS
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53

---
# 4. Database: recebe APENAS da API, sem egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgresql-policy
  namespace: myapp
spec:
  podSelector:
    matchLabels:
      app: postgresql
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 5432
  # Sem regras de egress = sem saída permitida

# Teste: kubectl exec frontend -- curl api:3000       (funciona)
# Teste: kubectl exec frontend -- curl postgresql:5432 (bloqueado)
# Teste: kubectl exec api -- curl frontend:80          (bloqueado)

Seguranca de infraestrutura nao e um destino, e uma jornada. Nao existe “seguro” como estado binario — existe “mais seguro” e “menos seguro”. O objetivo e tornar o custo de um ataque maior que o valor do que voce esta protegendo, em cada camada, o tempo todo. Comece pelo basico (secrets management, scanning automatizado, least privilege), e evolua para zero trust e compliance conforme a maturidade do time e os requisitos do negocio exigirem.


Referencias e Fontes