Guía Completa de Seguridad en aplicaciones cloud-native
Las aplicaciones cloud-native — construidas sobre contenedores, microservicios y orquestadores como Kubernetes — introducen un modelo de seguridad radicalmente diferente al de las aplicaciones monoliticas tradicionales. La superficie de ataque se multiplica: cada contenedor, cada comunicación entre servicios, cada secreto almacenado y cada imagen base representan un vector potencial. Asegurar este tipo de arquitectura requiere un enfoque que abarque desde el build de la imagen hasta el runtime en producción, pasando por la red, la identidad y la gestión de secretos.
Seguridad de Contenedores
La seguridad de contenedores comienza con la imagen y se extiende a todo su ciclo de vida.
Construir Imagenes Seguras
Una imagen de contenedor insegura es una bomba de tiempo. Las prácticas esenciales para construir imagenes seguras incluyen:
Usar imagenes base minimales: Preferir imagenes distroless o Alpine en lugar de imagenes completas como Ubuntu. Menos paquetes instalados significa menos vulnerabilidades potenciales.
# Mal: imagen base completa con cientos de paquetes
FROM node:20
# Mejor: imagen slim con lo minimo necesario
FROM node:20-slim
# Optimo: multi-stage con distroless para produccion
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["dist/main.js"]
No ejecutar como root: El contenedor debe correr con un usuario sin privilegios. Esto limita el impacto de un escape de contenedor.
FROM node:20-slim
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
USER appuser
CMD ["node", "server.js"]
No incluir secretos en la imagen: Nunca copiar archivos .env, credenciales o tokens en las capas de la imagen. Incluso si los eliminas en una capa posterior, las capas anteriores los retienen.
Escaneo de Imagenes
El escaneo de imagenes detecta vulnerabilidades conocidas (CVEs) en los paquetes del sistema operativo y las dependencias de la aplicación.
# GitHub Actions: escanear imagen con Trivy
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan image for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
Herramientas principales para escaneo de imagenes:
- Trivy: Open-source, rápido, soporta OS packages y dependencias de aplicación
- Grype: De Anchore, enfocado en vulnerabilidades de dependencias
- Snyk Container: Ofrece recomendaciones de imagenes base alternativas con menos CVEs
- Amazon ECR Image Scanning: Integrado nativamente si usas ECR como registro
Políticas de Admision en Kubernetes
Kyverno y OPA Gatekeeper permiten definir políticas que bloquean el despliegue de contenedores que no cumplen los requisitos de seguridad.
# Kyverno: bloquear contenedores que corren como root
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-root-user
spec:
validationFailureAction: Enforce
rules:
- name: check-runAsNonRoot
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Containers must not run as root"
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true
Protección en Runtime
La seguridad no termina cuando la imagen pasa el escaneo. En runtime, es necesario detectar y prevenir comportamientos anomalos.
Falco para Detección de Amenazas
Falco, proyecto de la CNCF, monitorea las syscalls del kernel para detectar actividad sospechosa en contenedores en tiempo real.
# Regla Falco: detectar shell ejecutado en contenedor
- rule: Terminal shell in container
desc: A shell was used as the entrypoint/exec in a container
condition: >
spawned_process and container and
shell_procs and proc.tty != 0 and
container_entrypoint
output: >
Shell opened in container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname
cmdline=%proc.cmdline image=%container.image.repository)
priority: WARNING
tags: [container, shell, mitre_execution]
Security Contexts en Kubernetes
Los Security Contexts de Kubernetes controlan los privilegios a nivel de pod y contenedor:
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
Puntos clave del ejemplo anterior:
runAsNonRoot: Fuerza ejecución como usuario no rootreadOnlyRootFilesystem: El filesystem del contenedor es de solo lecturacapabilities: drop ALL: Elimina todas las Linux capabilitiesallowPrivilegeEscalation: false: Previene escalación de privilegiosseccompProfile: RuntimeDefault: Aplica perfil seccomp por defecto que bloquea syscalls peligrosas
Seguridad de Service Mesh y mTLS
En arquitecturas de microservicios, la comunicación entre servicios es un punto crítico de seguridad. Un service mesh como Istio o Linkerd proporciona mTLS (mutual TLS) automático, cifrando y autenticando toda la comunicación interna.
mTLS con Istio
Con Istio, mTLS se habilita a nivel de namespace o de forma global:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT
En modo STRICT, todo el tráfico entre servicios dentro del namespace debe estar cifrado con mTLS. Cualquier comunicación sin TLS es rechazada.
Authorization Policies
Istio permite definir políticas de autorización granulares que controlan que servicio puede comunicarse con cual:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-api-policy
namespace: production
spec:
selector:
matchLabels:
app: backend-api
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/production/sa/frontend"
- "cluster.local/ns/production/sa/api-gateway"
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/v1/*"]
Esta política permite que solo el frontend y el api-gateway accedan al backend-api, y unicamente a las rutas y métodos especificados.
Gestión de Secretos
Los secretos (credenciales de base de datos, API keys, certificados TLS) deben gestionarse con herramientas dedicadas, nunca hardcodeados en código o configuraciones.
External Secrets Operator
External Secrets Operator sincroniza secretos desde proveedores externos (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) hacia Kubernetes Secrets:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database
property: username
- secretKey: password
remoteRef:
key: production/database
property: password
Vault con Sidecar Injector
HashiCorp Vault puede inyectar secretos directamente en los pods mediante un sidecar:
apiVersion: v1
kind: Pod
metadata:
name: app
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "my-app-role"
vault.hashicorp.com/agent-inject-secret-db-creds: "secret/data/production/db"
vault.hashicorp.com/agent-inject-template-db-creds: |
{{- with secret "secret/data/production/db" -}}
DB_HOST={{ .Data.data.host }}
DB_USER={{ .Data.data.username }}
DB_PASS={{ .Data.data.password }}
{{- end -}}
spec:
containers:
- name: app
image: myapp:latest
RBAC en Kubernetes
Role-Based Access Control (RBAC) en Kubernetes controla quien puede realizar que acciones dentro del cluster.
# Role: permisos dentro de un namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: development
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"] # Solo lectura de secrets
---
# RoleBinding: asignar el Role a un grupo
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: development
subjects:
- kind: Group
name: "developers"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
Principios Zero Trust en Cloud-Native
Zero Trust parte de la premisa de que ninguna entidad — interna o externa — es confiable por defecto. En el contexto cloud-native, esto se traduce en:
- Verificar siempre: Cada request entre servicios se autentica y autoriza, incluso dentro del cluster
- Privilegio mínimo: Cada servicio tiene acceso solo a los recursos que necesita
- Asumir la brecha: Disenar la arquitectura asumiendo que cualquier componente puede estar comprometido
- Cifrar todo: mTLS para comunicación entre servicios, cifrado en reposo para datos persistidos
- Microsegmentación: Network Policies que restringen el tráfico a nivel de pod
# NetworkPolicy: el pod solo puede comunicarse con la base de datos
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgresql
ports:
- port: 5432
protocol: TCP
- to: # Permitir DNS
- namespaceSelector: {}
ports:
- port: 53
protocol: UDP
OWASP Top 10 para Cloud-Native
OWASP ha publicado un Top 10 específico para aplicaciones cloud-native. Los riesgos mas relevantes incluyen:
- Configuración insegura de la nube: Buckets S3 publicos, security groups abiertos, servicios sin cifrado
- Inyección de código y dependencias maliciosas: Supply chain attacks a traves de imagenes base o paquetes npm/pip comprometidos
- Autenticación y autorización deficiente: Tokens sin expiración, RBAC demasiado permisivo, ausencia de MFA
- Falta de cifrado: Comunicaciones entre microservicios sin TLS, datos en reposo sin cifrar
- Gestión inadecuada de secretos: Credenciales en variables de entorno, secrets de Kubernetes sin cifrado at-rest
Para cada riesgo, la mitigación pasa por los controles descritos en las secciones anteriores: escaneo de imagenes, mTLS, RBAC estricto, External Secrets y políticas de admision.
Conclusion
La seguridad en aplicaciones cloud-native no es un producto que se instala ni una fase que se ejecuta una vez. Es una disciplina continua que abarca el ciclo completo: desde la construcción de imagenes seguras con escaneo automatizado, pasando por políticas de admision que previenen despliegues inseguros, hasta la detección de amenazas en runtime con herramientas como Falco. Los pilares de mTLS, RBAC, gestión externa de secretos y Network Policies conforman las capas de defensa que hacen viable operar microservicios en producción con confianza. La clave es automatizar estos controles para que sean parte del flujo de desarrollo, no una barrera que los equipos intentan evitar.