Saltar al contenido principal

Seguridad de contenedores e infraestructura en la nube

Los contenedores y la infraestructura cloud crean nuevas superficies de ataque que la seguridad de aplicaciones tradicional no cubre. Su imagen Docker puede contener una versión vulnerable de OpenSSL. Su bucket de S3 puede ser legible públicamente. Su rol IAM puede tener permisos para acceder a todo en su cuenta de AWS. Su clúster de Kubernetes puede permitir que cualquiera despliegue cargas de trabajo.

Estas configuraciones incorrectas son los frutos fáciles que buscan los atacantes. Son sencillas de explotar y a menudo otorgan acceso inmediato a datos o sistemas sensibles. La buena noticia: también son fáciles de detectar con herramientas automatizadas. Este capítulo cubre cómo analizar imágenes de contenedor, proteger recursos cloud, proteger clústeres de Kubernetes y auditar su infraestructura antes de que los atacantes encuentren los huecos.

Por qué esto importa para las empresas pequeñas

Las configuraciones incorrectas en la nube son consistentemente una de las principales causas de brechas de datos. Y a diferencia de las vulnerabilidades de código que requieren explotación, un bucket de S3 mal configurado o una base de datos expuesta son inmediatamente accesibles — sin necesidad de desarrollar un exploit.

Los contenedores ocultan vulnerabilidades. Cuando descarga node:18 o python:3.11 de Docker Hub, está descargando una distribución Linux completa con cientos de paquetes. Cualquiera de esos paquetes puede tener vulnerabilidades conocidas. Usted no escribió ese código, pero es responsable de la seguridad de todo lo que hay en su contenedor.

Los valores predeterminados de la nube no son seguros. AWS, GCP y Azure priorizan que las cosas funcionen sobre la seguridad. La configuración predeterminada a menudo permite más acceso del necesario. Un desarrollador que levanta recursos rápidamente puede dejar almacenamiento público, puertos abiertos o cifrado deshabilitado — porque ese es el camino más rápido hacia «funciona».

Los equipos pequeños se mueven rápido y se saltan revisiones. Nadie está comprobando las configuraciones de Terraform ni revisando las políticas IAM. Los cambios de infraestructura van directamente a producción. El análisis automatizado es su red de seguridad.

Kubernetes añade complejidad. Si está ejecutando en EKS, GKE o AKS, ha añadido otra capa de configuración que puede estar mal configurada. Los valores predeterminados de Kubernetes son notoriamente permisivos.

Los atacantes escanean todo Internet. Servicios como Shodan indexan continuamente bases de datos expuestas, buckets de S3 abiertos y servidores mal configurados. Su recurso accidentalmente público será descubierto en horas, no en semanas. Investigadores de seguridad en Comparitech encontraron que las bases de datos expuestas son descubiertas por actores maliciosos en horas de estar conectadas a Internet.

Seguridad de contenedores

La seguridad de contenedores comienza por entender qué hay dentro de sus imágenes. Una imagen Docker típica contiene:

  • Paquetes del SO base (apt, yum, apk)
  • Runtime del lenguaje (Node, Python, Java, Go)
  • Dependencias de la aplicación (paquetes npm, pip)
  • El código de su aplicación

Las vulnerabilidades pueden existir en cualquier capa. Las vulnerabilidades de la imagen base son especialmente peligrosas porque afectan a cada contenedor construido sobre esa imagen.

Construcción de imágenes seguras

Antes de analizar, construya imágenes más fáciles de proteger:

Use imágenes base mínimas. Las imágenes Alpine Linux son de 5-10 MB en lugar de los 100+ MB de Debian/Ubuntu. Menos paquetes significan menos vulnerabilidades.

# Instead of this (150+ MB, hundreds of packages)
FROM node:20

# Use this (50 MB, minimal packages)
FROM node:20-alpine

Considere imágenes distroless. Las imágenes distroless de Google contienen solo su aplicación y sus dependencias de runtime — sin shell, sin gestor de paquetes, sin utilidades que los atacantes podrían usar. Son la opción más segura para producción.

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Production stage with distroless
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["dist/server.js"]

Ventajas de distroless:

  • Sin shell = los atacantes no pueden obtener acceso interactivo aunque exploten una vulnerabilidad
  • Sin gestor de paquetes = sin forma de instalar herramientas adicionales
  • Superficie de ataque mínima = menos componentes que podrían tener vulnerabilidades
  • Imágenes más pequeñas = despliegues más rápidos, menos almacenamiento

La contrapartida: la depuración es más difícil ya que no puede entrar al contenedor con shell. Para producción, eso es una característica, no un error.

Fije versiones explícitamente. No use latest — cambia sin previo aviso. Fije versiones específicas para que los builds sean reproducibles y usted controle cuándo actualizar.

# BAD: could be anything
FROM python:latest

# GOOD: explicit version, reproducible builds
FROM python:3.12.3-alpine3.19

No ejecute como root. Los procesos de contenedor que se ejecutan como root pueden escapar al host en algunas configuraciones. Cree un usuario no-root:

FROM node:20-alpine

# Create non-root user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup

# Set working directory
WORKDIR /app

# Copy and install dependencies first (better caching)
COPY package*.json ./
RUN npm ci --only=production

# Copy application code
COPY --chown=appuser:appgroup . .

# Switch to non-root user
USER appuser

EXPOSE 3000
CMD ["node", "server.js"]

Use builds multi-etapa. Mantenga las herramientas de build fuera de las imágenes de producción:

# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage — only runtime, no build tools
FROM node:20-alpine
WORKDIR /app
RUN adduser -S appuser
COPY --from=builder --chown=appuser /app/dist ./dist
COPY --from=builder --chown=appuser /app/node_modules ./node_modules
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]

Secretos en contenedores

Nunca ponga claves de API, contraseñas o certificados en Dockerfiles. Use variables de entorno o gestión de secretos en tiempo de ejecución.

# BAD: secret baked into image
ENV DATABASE_PASSWORD=supersecret

# GOOD: expect secrets at runtime
ENV DATABASE_PASSWORD=""
# Injected at runtime: docker run -e DATABASE_PASSWORD=$SECRET ...

Docker Compose con secretos:

version: '3.8'
services:
app:
image: myapp:latest
secrets:
- db_password
- api_key
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true # Managed externally

Integración con Passwork: Use passwork-cli para inyectar secretos en tiempo de ejecución del contenedor:

# Pull secrets and start container
passwork-cli exec --folder-id "<folder-id>" docker compose up -d

# Or inject specific secrets
export DB_PASSWORD=$(passwork-cli get --password-id "<id>" --field password)
docker run -e DB_PASSWORD="$DB_PASSWORD" myapp:latest

Para Kubernetes, vea la sección de secretos en Kubernetes más abajo.

Análisis de imágenes con Trivy

Trivy es la herramienta estándar para el análisis de imágenes de contenedor. Es rápida, precisa y detecta vulnerabilidades en paquetes del SO, dependencias de lenguajes y configuraciones incorrectas.

Instalar Trivy:

# macOS
brew install trivy

# Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin

# Docker
docker pull aquasec/trivy

Analizar una imagen:

# Scan local image
trivy image myapp:latest

# Scan image from registry
trivy image nginx:1.25

# Scan with severity filter
trivy image --severity HIGH,CRITICAL myapp:latest

# Output as JSON for CI integration
trivy image --format json --output results.json myapp:latest

# Scan and fail if vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL myapp:latest

Ejemplo de salida:

myapp:latest (alpine 3.19.1)
Total: 3 (HIGH: 2, CRITICAL: 1)

┌──────────────┬────────────────┬──────────┬───────────────────┐
│ Library │ Vulnerability │ Severity │ Fixed Version │
├──────────────┼────────────────┼──────────┼───────────────────┤
│ openssl │ CVE-2024-0727 │ HIGH │ 3.1.4-r5 │
│ busybox │ CVE-2023-42365 │ HIGH │ 1.36.1-r15 │
│ libcrypto3 │ CVE-2024-0727 │ CRITICAL │ 3.1.4-r5 │
└──────────────┴────────────────┴──────────┴───────────────────┘

Integración de CI/CD para el análisis de contenedores

Añada el análisis de imágenes a su pipeline para que las imágenes vulnerables nunca lleguen a producción.

GitHub Actions:

name: Container Security

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

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

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

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'table'
exit-code: '1' # Fail on HIGH/CRITICAL
severity: 'HIGH,CRITICAL'
ignore-unfixed: true

GitLab CI:

container_scanning:
stage: test
image:
name: aquasec/trivy
entrypoint: [""]
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
allow_failure: false

Firma y verificación de imágenes

Después de ataques a la cadena de suministro como SolarWinds y CodeCov, verificar la autenticidad de las imágenes se volvió crítico. La firma de imágenes garantiza que:

  1. La imagen no ha sido manipulada
  2. Fue construida por su pipeline de CI/CD, no por un atacante
  3. Solo las imágenes firmadas pueden desplegarse en producción

Cosign (de Sigstore) es la herramienta estándar para la firma de imágenes de contenedor:

# Install cosign
brew install cosign # macOS
# or download from https://github.com/sigstore/cosign/releases

# Generate a key pair (do this once, store private key securely)
cosign generate-key-pair

# Sign an image
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0

# Verify a signature
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0

Firma sin clave con Sigstore (recomendado para CI/CD):

# GitHub Actions with keyless signing
name: Build and Sign

on:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for keyless signing
packages: write

steps:
- uses: actions/checkout@v4

- name: Install cosign
uses: sigstore/cosign-installer@v3

- name: Login to registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
id: build
uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

- name: Sign image with cosign
run: |
cosign sign --yes ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}

La firma sin clave usa OIDC (OpenID Connect) — no hay claves privadas que gestionar. La firma incluye prueba de que la imagen fue construida por un flujo de trabajo específico de GitHub Actions.

Seguridad del registro de contenedores

No descargue imágenes de Docker Hub sin validación. Use un registro privado con controles de seguridad.

Opciones de registro:

RegistroMejor paraCaracterísticas
AWS ECRApps nativas de AWSIntegración IAM, análisis automático, firma de imágenes
Google Artifact RegistryApps GCPIAM, análisis de vulnerabilidades, generación de SBOM
Azure Container RegistryApps AzureIntegración AAD, geo-replicación, content trust
HarborAutoalojado, multi-cloudAnálisis de vulnerabilidades, RBAC, firma de imágenes, replicación
GitHub Container RegistryCódigo abierto, nativo de GitHubGratuito para repos públicos, integración con GitHub Actions

Lista de verificación de seguridad del registro:

  • Habilitar el análisis de vulnerabilidades al hacer push
  • Requerir firma de imágenes para imágenes de producción
  • Establecer políticas de retención para eliminar imágenes antiguas sin etiqueta
  • Usar etiquetas inmutables (no se pueden sobrescribir etiquetas existentes)
  • Habilitar el registro de auditoría para todas las operaciones de pull/push
  • Restringir quién puede hacer push de imágenes (solo cuentas de servicio CI/CD)
  • Bloquear pulls de imágenes con vulnerabilidades críticas

Ejemplo con AWS ECR:

# Enable scanning on push
aws ecr put-image-scanning-configuration \
--repository-name myapp \
--image-scanning-configuration scanOnPush=true

# Set lifecycle policy (delete untagged images after 7 days)
aws ecr put-lifecycle-policy \
--repository-name myapp \
--lifecycle-policy-text '{
"rules": [{
"rulePriority": 1,
"description": "Delete untagged images",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
}]
}'

Seguridad en tiempo de ejecución

El análisis de imágenes detecta vulnerabilidades conocidas. Pero ¿qué hay de:

  • Exploits de día cero
  • Atacantes que entraron por vulnerabilidades de la aplicación
  • Cryptominers desplegados a través de dependencias comprometidas
  • Intentos de exfiltración de datos

Las herramientas de seguridad en tiempo de ejecución monitorizan el comportamiento del contenedor y alertan sobre anomalías.

Falco es la herramienta de seguridad en tiempo de ejecución de código abierto estándar:

# Install Falco
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco --namespace falco --create-namespace

Falco detecta:

  • Shell ejecutada dentro del contenedor
  • Acceso a archivos sensibles (/etc/passwd, /etc/shadow)
  • Conexiones de red a destinos inusuales
  • Intentos de escalada de privilegios
  • Procesos de cryptomining

Ejemplo de alertas de Falco:

15:23:45.123 Warning: Shell spawned in container (container_id=abc123 container_name=myapp shell=/bin/sh)
15:24:01.456 Critical: Sensitive file opened for reading (file=/etc/shadow container=myapp)
15:25:33.789 Warning: Outbound connection to known cryptomining pool (dest=pool.minexmr.com container=myapp)

Ejemplo de regla de Falco:

# Detect when someone runs shell in production container
- rule: Shell in Production Container
desc: Detect shell execution in production containers
condition: >
spawned_process and
container and
proc.name in (bash, sh, zsh, ksh) and
container.image.repository contains "prod"
output: >
Shell spawned in production container
(user=%user.name container=%container.name shell=%proc.name)
priority: WARNING

Comparación de herramientas de seguridad en tiempo de ejecución:

HerramientaLicenciaMejor paraEnlace
FalcoApache 2.0Kubernetes, detección de runtime generalfalco.org
SysdigComercial (nivel gratuito)Empresarial, cumplimiento, forensesysdig.com
AquaComercialSeguridad completa del ciclo de vida del contenedoraquasec.com
TetragonApache 2.0Basado en eBPF, bajo overheadtetragon.io

Para equipos pequeños, comience con Falco. Es gratuito, bien documentado y detecta la mayoría de las amenazas en tiempo de ejecución.

Referencia de herramientas de análisis de contenedores

HerramientaMejor paraLicenciaEnlace
TrivyAnálisis todo en uno, fácil configuraciónApache 2.0trivy.dev
GrypeAnálisis rápido de CVE, funciona con SyftApache 2.0github.com/anchore/grype
ClairIntegración con registro, escala empresarialApache 2.0github.com/quay/clair
Docker ScoutIntegración con Docker Hub, nativoNivel gratuito disponibledocker.com/products/docker-scout
Snyk ContainerAmigable para desarrolladores, asesoramiento de remediaciónNivel gratuito disponiblesnyk.io/product/container-security

Para equipos pequeños, Trivy es la opción clara. Es gratuito, rápido y detecta la mayoría de las vulnerabilidades. Si usa Docker Hub, Docker Scout es conveniente ya que está integrado en el CLI de Docker (docker scout cves myimage:tag).

Seguridad en Kubernetes

Si está ejecutando contenedores en Kubernetes (EKS, GKE, AKS o autoalojado), tiene otra capa de seguridad que configurar. Los valores predeterminados de Kubernetes son permisivos — diseñados para comenzar rápidamente, no para la seguridad en producción.

Fundamentos de seguridad en Kubernetes

La superficie de ataque:

ComponenteRiesgo si está mal configurado
API ServerAcceso completo al clúster, puede desplegar cualquier carga de trabajo
etcdContiene todos los secretos y el estado del clúster
KubeletAcceso a nivel de nodo, puede ejecutar cualquier contenedor
PodsEscape del contenedor, escalada de privilegios
RedAtaques entre pods, exfiltración de datos
RBACEscalada de privilegios, acceso no autorizado
SecretsRobo de credenciales, exposición de datos

Seguridad de pods

Kubernetes 1.25+ usa Pod Security Standards aplicados por Pod Security Admission:

NivelQué permiteCaso de uso
PrivilegedTodoSolo componentes del sistema
BaselinePreviene escaladas de privilegios conocidasLa mayoría de las aplicaciones
RestrictedMáxima seguridad, mínimos privilegiosCargas de trabajo sensibles

Habilitar Pod Security Admission:

# Namespace with restricted pod security
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

Especificación de pod segura:

apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:v1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"

Mejores prácticas de RBAC

El Control de Acceso Basado en Roles (RBAC) determina quién puede hacer qué en su clúster.

Auditar los permisos existentes:

# Who can create pods?
kubectl auth can-i create pods --all-namespaces --list

# What can a specific service account do?
kubectl auth can-i --list --as=system:serviceaccount:default:myapp

# Find overly permissive ClusterRoleBindings
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'

RBAC con mínimos privilegios:

# Role with minimal permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: myapp
name: myapp-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["myapp-secrets"] # Only specific secret
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp-binding
namespace: myapp
subjects:
- kind: ServiceAccount
name: myapp
namespace: myapp
roleRef:
kind: Role
name: myapp-role
apiGroup: rbac.authorization.k8s.io

Antipatrones RBAC a evitar:

# BAD: Wildcard permissions
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]

# BAD: cluster-admin for applications
roleRef:
kind: ClusterRole
name: cluster-admin

# BAD: Default service account with permissions
# (Don't add permissions to "default" service account)

Políticas de red

Por defecto, todos los pods pueden comunicarse con todos los demás pods. Las políticas de red restringen esto.

# Deny all ingress by default
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
---
# Allow only specific traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080

Secretos en Kubernetes

Los secretos de Kubernetes están codificados en base64, no cifrados. Cualquiera con acceso a etcd o a la API puede leerlos.

Mejores opciones:

  1. Habilitar cifrado en reposo:
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
  1. Usar External Secrets Operator con Passwork:
# ExternalSecret that pulls from Passwork
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-secrets
namespace: myapp
spec:
refreshInterval: 1h
secretStoreRef:
name: passwork-store
kind: SecretStore
target:
name: app-secrets
data:
- secretKey: database-password
remoteRef:
key: database-credentials
property: password
  1. Usar los gestores de secretos del proveedor cloud:
# AWS Secrets Manager with EKS
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: aws-secrets
spec:
provider: aws
parameters:
objects: |
- objectName: "myapp/database"
objectType: "secretsmanager"

Auditoría de seguridad en Kubernetes

Kubescape analiza los clústeres contra marcos de seguridad:

# Install
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash

# Scan cluster
kubescape scan framework nsa

# Scan against CIS benchmark
kubescape scan framework cis-v1.23-t1.0.1

# Scan specific namespace
kubescape scan framework nsa --include-namespaces production

kube-bench comprueba contra el CIS Kubernetes Benchmark:

# Run as a job in the cluster
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml

# View results
kubectl logs -l app=kube-bench

Herramientas de seguridad para Kubernetes:

HerramientaQué compruebaEnlace
KubescapeNSA/CISA, MITRE ATT&CK, benchmarks CISkubescape.io
kube-benchCIS Kubernetes Benchmarkgithub.com/aquasecurity/kube-bench
PolarisMejores prácticas de configuracióngithub.com/FairwindsOps/polaris
kube-hunterPruebas de penetración para K8sgithub.com/aquasecurity/kube-hunter

Seguridad de la infraestructura cloud

Los proveedores cloud le dan los bloques de construcción, pero la seguridad es su responsabilidad. Este es el «modelo de responsabilidad compartida» — AWS/GCP/Azure protegen la infraestructura física y el hipervisor, usted protege todo lo que configura.

Configuraciones incorrectas comunes en la nube

Estos son los problemas que causan brechas:

Configuración incorrectaRiesgoCómo ocurre
Buckets S3/GCS públicosExposición de datosEl desarrollador establece acceso público «temporalmente» para pruebas
IAM excesivamente permisivoEscalada de privilegiosUsar * en políticas IAM por conveniencia
Almacenamiento sin cifrarRobo de datosCifrado predeterminado no habilitado
Grupos de seguridad abiertosAcceso no autorizadoSSH/RDP abierto a 0.0.0.0/0 durante depuración
Bases de datos expuestasBrecha de datosRDS/CloudSQL con IP pública y contraseña débil
Registro faltanteCeguera ante incidentesCloudTrail/logs de auditoría no habilitados
Claves de acceso no utilizadasCompromiso de credencialesClaves de un desarrollador antiguo nunca rotadas
Sin MFA en la cuenta rootToma de control de cuentaCredenciales root comprometidas, acceso total
Confianza entre cuentasMovimiento lateralPermisos AssumeRole demasiado amplios

Principios de seguridad para recursos cloud

Mínimos privilegios en todas partes. Cada rol IAM, cada grupo de seguridad, cada cuenta de servicio debe tener los permisos mínimos necesarios. Comience con acceso cero, añada solo lo necesario.

// BAD: Full admin access
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}

// GOOD: Specific permissions for specific resources
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-uploads/*"
}

Cifre todo. Habilite el cifrado en reposo para todo el almacenamiento (S3, RDS, EBS, GCS). Use TLS para todos los datos en tránsito. Habilite el cifrado predeterminado para que los nuevos recursos estén protegidos automáticamente.

Sin acceso público por defecto. Bloquee el acceso público a nivel de cuenta para S3, requiera subredes privadas para bases de datos, use VPN o bastiones para el acceso administrativo.

Habilite el registro. Active CloudTrail (AWS), Cloud Audit Logs (GCP) o Activity Log (Azure) desde el primer día. No puede investigar lo que no registró.

Etiquete todo. Etiquetas como environment, owner, cost-center le ayudan a entender qué se está ejecutando y quién es responsable. Los recursos sin etiqueta suelen ser huérfanos y olvidados — blancos perfectos.

Seguridad de red en la nube

Principios de diseño de VPC:

Tres niveles de subred, cada uno replicado en zonas de disponibilidad:

  • Subredes públicas (AZ-a, AZ-b) — Load Balancer, NAT Gateway. Solo estas tienen exposición de cara a Internet.
  • Subredes privadas (AZ-a, AZ-b) — Servidores de aplicación. Sin IP pública. Internet de salida solo via NAT Gateway.
  • Subredes de base de datos (AZ-a, AZ-b) — RDS / bases de datos. Sin acceso a Internet en absoluto, accesible solo desde subredes privadas.

Lista de verificación de seguridad de red:

  • Bases de datos en subredes privadas (sin IP pública)
  • NAT Gateway para Internet de salida desde subredes privadas
  • Grupos de seguridad: denegar por defecto, permitir puertos/fuentes específicos
  • NACLs como capa adicional para filtrado a nivel de subred
  • VPC Flow Logs habilitados para análisis de tráfico
  • PrivateLink/Private Service Connect para acceso a servicios AWS/GCP
  • WAF delante de aplicaciones públicas
  • Protección DDoS (AWS Shield, Cloud Armor, Azure DDoS Protection)

Mejores prácticas para grupos de seguridad:

# BAD: SSH open to the world
aws ec2 authorize-security-group-ingress \
--group-id sg-123 \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0

# GOOD: SSH only from VPN/bastion
aws ec2 authorize-security-group-ingress \
--group-id sg-123 \
--protocol tcp \
--port 22 \
--source-group sg-bastion

Lista de verificación de seguridad para AWS

CategoríaComprobaciónCómo verificar
CuentaMFA en la cuenta rootConsole → IAM → Root account MFA
CuentaSin claves de acceso rootaws iam get-account-summary
IAMPolítica de contraseñas aplicadaaws iam get-account-password-policy
IAMSin políticas inlineaws iam list-user-policies
IAMCredenciales no usadas deshabilitadasIAM Credential Report
S3Acceso público bloqueadoaws s3control get-public-access-block
S3Cifrado predeterminado habilitadoaws s3api get-bucket-encryption
S3Registro de acceso habilitadoaws s3api get-bucket-logging
EC2Cifrado EBS por defectoaws ec2 get-ebs-encryption-by-default
EC2Sin AMIs públicasaws ec2 describe-images --owners self
RDSNo accesible públicamenteaws rds describe-db-instances
RDSCifrado en reposoaws rds describe-db-instances
CloudTrailHabilitado, multi-regiónaws cloudtrail describe-trails
ConfigGrabación habilitadaaws configservice describe-configuration-recorders
GuardDutyHabilitadoaws guardduty list-detectors

Script de victorias rápidas en AWS:

#!/bin/bash
# aws-security-quick-wins.sh

# Block public access at account level
aws s3control put-public-access-block \
--account-id $(aws sts get-caller-identity --query Account --output text) \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"

# Enable default EBS encryption
aws ec2 enable-ebs-encryption-by-default

# Enable GuardDuty
aws guardduty create-detector --enable

# Enable Security Hub
aws securityhub enable-security-hub

# Create CloudTrail (if not exists)
aws cloudtrail create-trail \
--name main-trail \
--s3-bucket-name my-cloudtrail-logs \
--is-multi-region-trail \
--enable-log-file-validation
aws cloudtrail start-logging --name main-trail

echo "AWS security quick wins applied!"

Lista de verificación de seguridad para GCP

CategoríaComprobaciónCómo verificar
IAMSin roles primitivos (Owner/Editor)gcloud projects get-iam-policy PROJECT
IAMRotación de claves de cuenta de serviciogcloud iam service-accounts keys list
StorageAcceso uniforme a nivel de bucketgsutil uniformbucketlevelaccess get
StorageSin buckets públicosgsutil iam get gs://BUCKET
ComputeSin cuenta de servicio predeterminadagcloud compute instances list
ComputeVMs blindadas habilitadasgcloud compute instances describe
LoggingRegistros de auditoría habilitadosConsole → IAM → Audit Logs
VPCPrivate Google Access habilitadogcloud compute networks subnets list
GKEClúster privadogcloud container clusters describe
GKEWorkload Identity habilitadogcloud container clusters describe

Victorias rápidas en GCP:

# Enable organization policies (requires Org Admin)
gcloud resource-manager org-policies allow \
compute.requireShieldedVm --organization=ORG_ID

gcloud resource-manager org-policies deny \
iam.allowedPolicyMemberDomains --organization=ORG_ID

# Enable audit logs for all services
# (Best done in Console: IAM → Audit Logs → Default Config)

# Check for public buckets
for bucket in $(gsutil ls); do
echo "Checking $bucket..."
gsutil iam get $bucket | grep -i allUsers && echo "WARNING: $bucket is public!"
done

Lista de verificación de seguridad para Azure

CategoríaComprobaciónCómo verificar
AADMFA aplicadoAzure AD → Security → MFA
AADPolíticas de acceso condicionalAzure AD → Security → Conditional Access
AADSin usuarios invitados con adminAzure AD → Users → Guest users
StorageTransferencia segura requeridaaz storage account show
StorageEndpoint privado habilitadoaz storage account show
SQLAutenticación Azure AD habilitadaaz sql server ad-admin list
SQLTDE habilitadoaz sql db tde show
NetworkingNSG flow logs habilitadosaz network watcher flow-log list
DefenderDefender for Cloud habilitadoaz security pricing list
KeyVaultSoft delete habilitadoaz keyvault show

Victorias rápidas en Azure:

# Enable Defender for Cloud free tier
az security pricing create --name VirtualMachines --tier free

# Check for public storage accounts
az storage account list --query "[?allowBlobPublicAccess==\`true\`].name"

# Enable secure transfer for all storage accounts
for account in $(az storage account list --query "[].name" -o tsv); do
az storage account update --name $account --https-only true
done

# Enable activity log alerts
az monitor activity-log alert create \
--name "Security Alert" \
--resource-group my-rg \
--condition category=Security

Auditoría de infraestructura cloud

Las herramientas de auditoría automatizadas comprueban su configuración cloud contra las mejores prácticas de seguridad. Comparan su configuración con benchmarks como CIS (Center for Internet Security) y señalan las configuraciones incorrectas.

ScoutSuite

ScoutSuite es una herramienta de auditoría de seguridad multi-cloud. Soporta AWS, Azure, GCP, Alibaba Cloud y Oracle Cloud.

Instalación:

pip install scoutsuite

Ejecutar auditoría:

# AWS (uses your default credentials)
scout aws

# GCP
scout gcp --user-account

# Azure
scout azure --cli

ScoutSuite genera un informe HTML con los hallazgos agrupados por servicio y gravedad. Cada hallazgo incluye el recurso afectado, por qué es un problema y cómo corregirlo.

Ejemplos de hallazgos:

  • Buckets S3 con acceso de lectura público
  • Usuarios IAM sin MFA habilitado
  • Grupos de seguridad con SSH abierto a Internet
  • Instancias RDS accesibles públicamente
  • Volúmenes EBS sin cifrar

Prowler

Prowler es específico para AWS y proporciona la evaluación de seguridad de AWS más completa. Comprueba contra el CIS AWS Foundations Benchmark, PCI-DSS, HIPAA y otros marcos de cumplimiento.

Instalación:

pip install prowler

Ejecutar auditoría:

# Full AWS audit
prowler aws

# Specific checks only
prowler aws --checks ec2_instance_public_ip,s3_bucket_public_access

# Output formats
prowler aws -M csv,html,json

# Check specific region
prowler aws -f us-east-1

# Check against specific compliance framework
prowler aws --compliance cis_2.0_aws

Integración con CI/CD:

# GitHub Actions
name: Cloud Security Audit

on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 6 AM

jobs:
prowler:
runs-on: ubuntu-latest
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1

- name: Install Prowler
run: pip install prowler

- name: Run Prowler
run: prowler aws -M json -o results/

- name: Upload results
uses: actions/upload-artifact@v4
with:
name: prowler-report
path: results/

Herramientas de seguridad nativas de la nube

Los proveedores cloud ofrecen sus propias herramientas de evaluación de seguridad:

ProveedorHerramientaCosteQué comprueba
AWSSecurity HubNivel gratuito + por hallazgoAgrega hallazgos de múltiples fuentes, benchmarks CIS
AWSTrusted AdvisorGratuito (limitado) / Business+Coste, rendimiento, seguridad, tolerancia a fallos
AWSGuardDutyPor GB analizadoDetección de amenazas, detección de anomalías
GCPSecurity Command CenterNivel gratuito disponibleVulnerabilidades, configuraciones incorrectas, amenazas
GCPSecurity Health AnalyticsGratuito con SCCViolaciones de mejores prácticas
AzureDefender for CloudNivel gratuito disponiblePostura de seguridad, cumplimiento, protección contra amenazas
AzureSecure ScoreGratuitoPuntuación general de la postura de seguridad

Para equipos pequeños, comience con las herramientas de código abierto gratuitas (ScoutSuite, Prowler) y habilite los niveles gratuitos de las herramientas nativas de la nube. Son complementarias — las herramientas nativas de la nube a menudo detectan amenazas en tiempo de ejecución que las herramientas de auditoría no detectan.

Gestión de hallazgos de seguridad

Cuando Prowler encuentra 200 problemas o Trivy reporta 50 vulnerabilidades, necesita un enfoque sistemático para priorizar y remediar.

Proceso de clasificación

Paso 1: categorizar por gravedad y explotabilidad

PrioridadCriterioPlazo de acción
P1 - CríticoExplotado activamente O con cara a Internet con exploit conocidoCorregir en 24 horas
P2 - AltoAlta gravedad, fácil de explotar, impacto en producciónCorregir en 1 semana
P3 - MedioGravedad media, requiere condiciones para explotarCorregir en 1 mes
P4 - BajoBaja gravedad, defensa en profundidadCorregir en la próxima ventana de mantenimiento
AceptarRiesgo muy bajo, sin solución disponible, controles compensatoriosDocumentar y aceptar

Paso 2: verificar que el hallazgo es real

No todos los hallazgos son problemas reales:

# Example: Prowler says S3 bucket is public
# Verify manually
aws s3api get-bucket-acl --bucket my-bucket
aws s3api get-bucket-policy --bucket my-bucket
aws s3api get-public-access-block --bucket my-bucket

# It might be intentionally public (static website hosting)
# If intentional, document and suppress future alerts

Paso 3: crear tickets de remediación

Para cada hallazgo P1-P3:

  • ¿Cuál es el problema?
  • ¿Qué recurso está afectado?
  • ¿Cómo corregirlo?
  • ¿Quién es el responsable de la corrección?
  • Plazo según la prioridad

Paso 4: rastrear la remediación

# Security Findings Tracker

| Finding ID | Description | Priority | Owner | Deadline | Status |
|------------|-------------|----------|-------|----------|--------|
| PROWLER-001 | S3 bucket public | P1 | DevOps | 2024-01-15 | Fixed |
| TRIVY-042 | OpenSSL CVE-2024-0727 | P2 | Dev | 2024-01-20 | In Progress |
| SCOUT-018 | CloudTrail not enabled | P2 | DevOps | 2024-01-22 | Open |

Supresión de falsos positivos

Cuando un hallazgo es intencional o un falso positivo, suprímalo para mantener los informes limpios:

Trivy:

# .trivyignore
# Ignore specific CVE (with reason)
CVE-2024-0727 # Fixed in next base image update, not exploitable in our context

# Ignore by package
pkg:apk/busybox

Prowler:

# Create allowlist file
prowler aws --allowlist allowlist.yaml
# allowlist.yaml
Accounts:
"123456789012":
Checks:
s3_bucket_public_access:
Regions:
- us-east-1
Resources:
- "arn:aws:s3:::my-public-website-bucket" # Intentionally public

ScoutSuite:

# scout-exceptions.json
{
"s3": {
"buckets": {
"my-public-website-bucket": ["is_public"]
}
}
}

Errores comunes a evitar

Analizar imágenes pero no corregir los hallazgos. Un análisis que encuentra 50 vulnerabilidades críticas y no pasa nada es peor que ningún análisis — crea una falsa confianza. Priorice los hallazgos CRITICAL y corríjalos.

Usar etiquetas latest en producción. Su Dockerfile dice FROM node:latest. Hoy es Node 20.12. Mañana es Node 21 con cambios incompatibles. Fije versiones.

Ignorar las actualizaciones de la imagen base. El código de su aplicación está bien, pero su imagen base de hace 6 meses tiene 20 nuevos CVEs. Reconstruya imágenes regularmente, aunque su código no haya cambiado.

Otorgar acceso de administrador «temporalmente». Un desarrollador necesita depurar algo, obtiene permisos de administrador, y esos permisos nunca se revocan. Cree permisos específicos y limitados desde el principio.

Deshabilitar los análisis de seguridad para desbloquear despliegues. Un análisis encuentra un problema, el equipo no puede corregirlo de inmediato, así que deshabilitaon el escáner. Ahora están ciegos a vulnerabilidades futuras también. Use allowlists para los riesgos aceptados.

Auditar una vez en lugar de continuamente. Ejecutar Prowler una vez al año antes de una auditoría no ayuda. La deriva de configuración ocurre diariamente. Configure análisis automatizados semanales o mensuales.

Tratar los valores predeterminados de Kubernetes como seguros. No lo son. La seguridad de pods predeterminada permite root, contenedores privilegiados, acceso a la red del host. Aplique Pod Security Standards desde el primer día.

Almacenar secretos en Kubernetes Secrets sin cifrado. Base64 no es cifrado. Habilite el cifrado en reposo o use External Secrets Operator.

Incidentes reales

Brecha de Capital One (2019): Un WAF mal configurado permitió a un atacante acceder a credenciales IAM via SSRF, lo que llevó a la exposición de 100+ millones de registros de clientes. El problema subyacente era roles IAM excesivamente permisivos que permitían el acceso a buckets de S3. Fuente: Wikipedia

Cryptomining en Tesla (2018): Un panel de control de Kubernetes expuesto (sin autenticación) permitió a los atacantes desplegar mineros de criptomonedas en la infraestructura AWS de Tesla. El panel también tenía acceso a credenciales AWS. Fuente: Wired

Brecha de datos de Uber (2016): Los atacantes encontraron credenciales AWS en un repositorio privado de GitHub, las usaron para acceder a buckets de S3 con datos de 57 millones de usuarios. Las credenciales nunca deberían haber estado en un repositorio, y los buckets de S3 deberían haber requerido autenticación adicional. Fuente: Bloomberg

Cierre de Code Spaces (2014): Los atacantes obtuvieron acceso a la consola de AWS, eliminaron todos los datos, copias de seguridad y configuraciones de máquinas. La empresa no pudo recuperarse y cerró en 12 horas. Sin MFA en las cuentas de AWS, sin copias de seguridad externas. Fuente: Info Security Magazine

Filtración del código fuente de Twitch (2021): 125GB de datos incluyendo código fuente, herramientas internas y pagos a creadores se filtraron a través de un servidor mal configurado. Fuente: The Verge

Brecha de cámaras Verkada (2021): Los atacantes accedieron a 150.000 cámaras de seguridad en hospitales, prisiones y empresas. Causa raíz: credenciales de administrador codificadas en el sistema. Fuente: Bloomberg

Taller: seguridad de contenedores y la nube

Este taller le guía a través de la configuración del análisis de contenedores, el endurecimiento de Kubernetes y la ejecución de una auditoría cloud.

Parte 1: análisis de imágenes Docker

Tarea: Añadir el análisis Trivy a su pipeline de CI/CD.

  1. Instale Trivy localmente:

    # macOS
    brew install trivy

    # Linux
    curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | \
    sh -s -- -b /usr/local/bin
  2. Analice una imagen existente:

    # Scan your application image
    trivy image your-app:latest

    # If you don't have one, scan a common base image
    trivy image node:20-alpine
    trivy image python:3.12-slim
  3. Revise los hallazgos:

    • ¿Cuántas vulnerabilidades CRITICAL?
    • ¿Cuántas tienen soluciones disponibles (compruebe la columna «Fixed Version»)?
    • ¿Qué paquete tiene más vulnerabilidades?
  4. Añada el análisis a CI/CD:

    Para GitHub Actions, añada .github/workflows/container-scan.yml:

    name: Container Scan

    on:
    push:
    branches: [main]
    pull_request:

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

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

    - name: Scan image
    uses: aquasecurity/trivy-action@master
    with:
    image-ref: 'app:${{ github.sha }}'
    exit-code: '1'
    severity: 'CRITICAL'
    ignore-unfixed: true
  5. Pruebe el pipeline: Haga push de un commit y verifique que el análisis se ejecuta.

Parte 2: seguridad en Kubernetes (si aplica)

Tarea: Auditar la seguridad de su clúster de Kubernetes.

  1. Instale Kubescape:

    curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
  2. Ejecute el análisis de seguridad:

    # Scan against NSA/CISA framework
    kubescape scan framework nsa

    # Scan specific namespace
    kubescape scan framework nsa --include-namespaces production
  3. Revise y corrija los principales problemas:

    • Contenedores ejecutándose como root
    • Límites de recursos faltantes
    • Contenedores privilegiados
    • Políticas de red faltantes
  4. Cree una plantilla de pod endurecida para que su equipo la use.

Parte 3: auditoría de infraestructura cloud

Tarea: Ejecutar ScoutSuite o Prowler contra su cuenta cloud.

  1. Para AWS con Prowler:

    pip install prowler

    # Run focused checks first (faster)
    prowler aws --checks s3_bucket_public_access,iam_user_mfa_enabled,ec2_security_group_default_restrict_traffic

    # Full audit (takes longer)
    prowler aws -M html
  2. Para multi-cloud o no-AWS:

    pip install scoutsuite

    # AWS
    scout aws

    # GCP
    scout gcp --user-account

    # Azure
    scout azure --cli
  3. Revise los hallazgos:

    • Abra el informe HTML generado
    • Concéntrese en los hallazgos de gravedad HIGH y CRITICAL
    • Agrupe por servicio (S3, IAM, EC2, etc.)
  4. Cree un plan de remediación:

    • Seleccione los 5 principales hallazgos por gravedad
    • Documente qué necesita cambiar
    • Asigne responsable y plazo

Artefactos a producir

Después de este taller, debería tener:

  1. Trivy integrado en CI/CD — archivo YAML del pipeline con análisis de imágenes
  2. Imágenes de contenedor firmadas — Cosign integrado en el pipeline de build
  3. Informe de auditoría cloud — exportación HTML/PDF de ScoutSuite o Prowler
  4. Plan de remediación — lista priorizada de hallazgos con responsables y plazos
  5. Plantilla de Dockerfile seguro — ejemplo de Dockerfile siguiendo las mejores prácticas para su pila
  6. Política de seguridad de Kubernetes (si aplica) — Pod Security Standards, reglas RBAC, políticas de red

Preguntas de autoevaluación

Antes de continuar, verifique que puede responder:

  1. ¿Cuál es la diferencia entre imágenes base Alpine y distroless?
  2. ¿Por qué debe firmar imágenes de contenedor, y cómo ayuda Cosign?
  3. ¿Qué detecta Falco que Trivy no detecta?
  4. ¿Qué son los Pod Security Standards de Kubernetes y cuáles son sus tres niveles?
  5. ¿Cómo gestionar correctamente los secretos en Kubernetes?
  6. ¿Qué es el modelo de responsabilidad compartida en la seguridad cloud?
  7. Nombre cinco configuraciones incorrectas comunes en la nube que llevan a brechas de datos.
  8. ¿Qué comprueba ScoutSuite que Prowler no comprueba (o viceversa)?
  9. ¿Cómo priorizar 200 hallazgos de seguridad de una auditoría cloud?
  10. ¿Con qué frecuencia debe ejecutar auditorías de seguridad cloud?

Cómo explicarlo a la dirección

Al presentar la seguridad de contenedores y la nube a la dirección:

Comience con el riesgo: «Ejecutamos decenas de contenedores en AWS/GCP. Una sola configuración incorrecta podría exponer datos de clientes. Estas herramientas encuentran automáticamente esas configuraciones incorrectas antes que los atacantes.»

Muestre ejemplos concretos: «Nuestra auditoría encontró 3 buckets de S3 que eran legibles públicamente. Contenían archivos de copia de seguridad. Aquí está la lista de lo que corregimos.»

Cuantifique la mejora: «Antes de estas herramientas, no teníamos visibilidad sobre nuestra postura de seguridad cloud. Ahora tenemos análisis automatizados semanales que detectan problemas como [ejemplo específico].»

Compare costes: «Estas herramientas son gratuitas. Una brecha de datos cuesta 4,45 millones de dólares de media. Las herramientas tardan pocas horas en configurarse y minutos en ejecutarse cada semana.»

Vincúlelo al cumplimiento: «Si alguna vez necesitamos la certificación SOC 2 o ISO 27001, estas auditorías son obligatorias. Empezar ahora significa que ya estaremos preparados.»

Cite incidentes reales: «Code Spaces cerró en 12 horas cuando los atacantes entraron en su consola de AWS. Ahora hemos habilitado MFA y reducido los permisos para evitar esto.»

Recursos y enlaces

Seguridad de contenedores

Seguridad en Kubernetes

Auditoría de seguridad cloud

Mejores prácticas y benchmarks

Qué sigue

Contenedores asegurados, infraestructura cloud endurecida, red segmentada. La superficie de ataque es menor — pero no cero.

Próximo capítulo: registro y monitorización de seguridad — configurar el registro centralizado y las alertas para que cuando algo llegue a pasar, lo descubra antes de que el daño se extienda.