Capitulo 18: Seguridad
Capitulo 18: Seguridad
< Volver al Indice del Tutorial
Seguridad por Capas
La seguridad en Kubernetes no es un unico mecanismo sino multiples capas que se complementan:
- Red: Controlar que pods pueden comunicarse entre si
- Pod: Restringir privilegios de los contenedores
- Acceso: Limitar que usuarios y ServiceAccounts pueden hacer
- Datos: Encriptar secrets en reposo
- Infraestructura: Hardening del cluster y sus componentes
Cada capa agrega proteccion independiente. Si una falla, las demas siguen protegiendo el cluster.
Network Policies
Por defecto, todos los pods pueden comunicarse con todos los demas pods del cluster. Las Network Policies restringen este trafico.
Requisito: Network Plugin Compatible
K3s usa Flannel por defecto, que no soporta Network Policies. Para habilitarlas necesitas un plugin compatible:
# Instalar K3s con Canal (Flannel + Calico para policies)
curl -sfL https://get.k3s.io | sh -s - --flannel-backend=none \
--disable-network-policy
# Luego instalar Calico
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
Default Deny: Bloquear Todo por Defecto
La primera politica en cualquier namespace de produccion debe ser bloquear todo el trafico entrante:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: mi-app
spec:
podSelector: {}
policyTypes:
- Ingress
Con esto, ningun pod en el namespace mi-app recibe trafico a menos que una politica lo permita explicitamente.
Permitir Trafico Especifico
Solo el frontend puede hablar con el backend:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: mi-app
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
Solo el backend puede hablar con la base de datos:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-db
namespace: mi-app
spec:
podSelector:
matchLabels:
app: database
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- port: 5432
Pod Security Standards
Kubernetes define tres niveles de seguridad para pods:
| Nivel | Descripcion |
|---|---|
| Privileged | Sin restricciones. Solo para componentes del sistema |
| Baseline | Previene escalaciones conocidas. Minimo recomendado |
| Restricted | Hardening completo. Recomendado para produccion |
Configurar por Namespace
Se aplican con labels en el namespace:
apiVersion: v1
kind: Namespace
metadata:
name: produccion
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
Los modos son:
- enforce: Rechaza pods que violan la politica
- warn: Permite pero muestra advertencia
- audit: Registra en logs de auditoria
Una estrategia comun es empezar con warn para detectar problemas y luego activar enforce.
Pod Compatible con Restricted
apiVersion: v1
kind: Pod
metadata:
name: app-segura
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: mi-app:1.0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
runAsNonRoot: true
RBAC Avanzado
Principio de Menor Privilegio
Cada usuario o servicio debe tener solo los permisos que necesita. Audita los permisos existentes:
# Que puede hacer el ServiceAccount "deploy-sa" en el namespace "staging"
kubectl auth can-i --list --as=system:serviceaccount:staging:deploy-sa -n staging
# Puede este usuario crear deployments
kubectl auth can-i create deployments [email protected] -n produccion
Roles Granulares por Equipo
Role para el equipo de desarrollo (solo lectura + logs):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: desarrollador
namespace: staging
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch"]
Role para el equipo de operaciones (gestion completa):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operaciones
namespace: produccion
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["*"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
Nota que operaciones puede hacer todo excepto ver el contenido de los secrets (solo listarlos).
Vincular Roles
kubectl create rolebinding dev-binding \
--role=desarrollador \
[email protected] \
-n staging
Secrets Encryption at Rest
Por defecto, los secrets se almacenan en texto plano en la base de datos. Para encriptarlos:
# Al instalar K3s
curl -sfL https://get.k3s.io | sh -s - server --secrets-encryption
Para un cluster existente:
# Habilitar encriptacion
k3s secrets-encrypt enable
# Reencriptar secrets existentes
k3s secrets-encrypt reencrypt
# Verificar estado
k3s secrets-encrypt status
Despues de habilitar la encriptacion, los nuevos secrets se almacenan encriptados con AES-CBC. Los existentes necesitan reencriptarse manualmente.
CIS Benchmark para K3s
El CIS Benchmark es un conjunto de recomendaciones de seguridad para Kubernetes. K3s tiene su propio perfil CIS.
Ejecutar kube-bench
# Instalar kube-bench
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
# Ver resultados
kubectl logs job/kube-bench
kube-bench evalua la configuracion del cluster contra las recomendaciones CIS y reporta que pasa, que falla y que necesita atencion manual.
Iniciar K3s en Modo CIS
curl -sfL https://get.k3s.io | sh -s - server \
--protect-kernel-defaults \
--secrets-encryption
El flag --protect-kernel-defaults hace que K3s falle si los parametros del kernel no cumplen con los requisitos de seguridad en lugar de modificarlos silenciosamente.
Hardening Basico
Deshabilitar Acceso Anonimo
K3s deshabilita el acceso anonimo por defecto, pero verifica:
kubectl auth can-i --list --as=system:anonymous
Si ves permisos asignados a anonymous, revisa los ClusterRoleBindings.
Rotar Tokens
Los tokens de los nodos no rotan automaticamente. Para rotar:
# Regenerar token del server
k3s token rotate
# Los agents necesitan reconectarse con el nuevo token
Limitar Acceso al API Server
Usa firewall para que solo IPs autorizadas accedan al puerto 6443:
# Con iptables
iptables -A INPUT -p tcp --dport 6443 -s 10.0.0.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6443 -j DROP
Checklist de Seguridad
- Network Policies con default deny en cada namespace
- Pod Security Standards en modo enforce
- RBAC con menor privilegio
- Secrets encriptados at rest
- kube-bench ejecutado y remediado
- Acceso al API server restringido por firewall
- Tokens rotados periodicamente
- Audit logging habilitado
Siguiente: Capitulo 19: GitOps con Flux —>