Avançado Cloud

Segurança serverless e container na cloud — Lambda, ECR, EKS boas práticas

Serverless e containers mudaram o modelo de operação, mas não eliminaram a superfície de ataque — apenas a redistribuíram. Em Lambda, o código ainda pode vazar segredos ou ser injetado via payload. Em containers, uma imagem com vulnerabilidades críticas chega direto em produção se não houver scanning no pipeline.

AWS Lambda — superfície de ataque e controles

Execution role com least privilege

// Ruim — role com permissões excessivas
{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}

// Bom — apenas o necessário para a função específica
{
  "Effect": "Allow",
  "Action": [
    "s3:GetObject"
  ],
  "Resource": "arn:aws:s3:::relatorios-prod/entrada/*"
}

Variáveis de ambiente criptografadas com KMS

# Criar função com variáveis criptografadas
aws lambda create-function \
  --function-name processador-pagamento \
  --runtime python3.12 \
  --role arn:aws:iam::123456789:role/lambda-pagamento-role \
  --kms-key-arn arn:aws:kms:us-east-1:123456789:key/abc-123 \
  --environment Variables='{API_KEY_SECRET_ARN=arn:aws:secretsmanager:...}' \
  --zip-file fileb://function.zip \
  --handler handler.main

Prefira referências ao Secrets Manager em vez de injetar o valor diretamente na variável de ambiente.

Resource policy — quem pode invocar

# Permitir invocação apenas do API Gateway desta conta
aws lambda add-permission \
  --function-name processador-pagamento \
  --statement-id allow-apigw \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-1:123456789:abc123/prod/POST/pagamento" \
  --source-account 123456789

Validação de input

import json, re

def handler(event, context):
    # Nunca confie no payload — valide sempre
    body = json.loads(event.get("body", "{}"))
    
    amount = body.get("amount")
    if not isinstance(amount, (int, float)) or amount <= 0 or amount > 1_000_000:
        return {"statusCode": 400, "body": "Valor inválido"}
    
    order_id = body.get("order_id", "")
    if not re.fullmatch(r"[A-Z0-9\-]{8,32}", order_id):
        return {"statusCode": 400, "body": "order_id inválido"}
    
    # Processamento seguro...

Amazon ECR — segurança de imagens

# Habilitar scan automático ao fazer push
aws ecr put-image-scanning-configuration \
  --repository-name minha-app \
  --image-scanning-configuration scanOnPush=true

# Ver resultados do scan de vulnerabilidades
aws ecr describe-image-scan-findings \
  --repository-name minha-app \
  --image-id imageTag=v1.2.3 \
  --query 'imageScanFindings.findingSeverityCounts'

# Política de ciclo de vida — remover imagens antigas não escaneadas
aws ecr put-lifecycle-policy \
  --repository-name minha-app \
  --lifecycle-policy-text '{
    "rules": [{
      "rulePriority": 1,
      "description": "Remover imagens não tagueadas com mais de 7 dias",
      "selection": {
        "tagStatus": "untagged",
        "countType": "sinceImagePushed",
        "countUnit": "days",
        "countNumber": 7
      },
      "action": { "type": "expire" }
    }]
  }'

Amazon EKS — segurança do cluster

Pod Security Admission

# Namespace com enforce restritivo
apiVersion: v1
kind: Namespace
metadata:
  name: producao
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted

IRSA — IAM Roles for Service Accounts

# Associar role IAM a um ServiceAccount do Kubernetes
eksctl create iamserviceaccount \
  --cluster meu-cluster \
  --namespace producao \
  --name sa-processador \
  --attach-policy-arn arn:aws:iam::123456789:policy/processador-policy \
  --approve
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-processador
  namespace: producao
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/processador-role

Network Policy para isolamento de pods

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolamento-backend
  namespace: producao
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes: [Ingress, Egress]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
    ports:
    - port: 5432

Checklist unificado

Lambda:
  - Execution role com least privilege (sem Action: *)
  - Variáveis sensíveis via Secrets Manager, não env var
  - Resource policy restrita ao invoker legítimo
  - Validação de input no handler
  - Timeout e concurrency limit configurados
  - VPC apenas se necessário (aumenta cold start)

ECR / Imagens:
  - Scan on push habilitado
  - Imagens base mínimas (distroless, alpine)
  - Usuário não-root no Dockerfile
  - Tag fixa — nunca :latest em produção
  - Pipeline bloqueia imagens com CRITICAL/HIGH

EKS:
  - Pod Security Admission enforce: restricted
  - IRSA para acesso AWS (sem access keys em pods)
  - Network Policies em todos os namespaces
  - RBAC com ServiceAccounts dedicadas
  - Admission controller (Kyverno, OPA Gatekeeper)
  - Runtime security: Falco para detecção de comportamento anômalo