IAM descentralizado y seguridad multi-cloud: construyendo Zero Trust a escala
IAM descentralizado y seguridad multi-cloud: construyendo Zero Trust a escala
La era del modelo de seguridad perimetral tradicional (castle-and-moat) ha terminado. Cuando su infraestructura abarca AWS, GCP, Azure y entornos on-premise, el perímetro deja de existir. En esta realidad, el IAM descentralizado y la seguridad multi-cloud no son solo un patrón arquitectónico, sino la única defensa viable contra el movimiento lateral y los ataques sofisticados a la cadena de suministro. La identidad del solicitante, ya sea humano o máquina, es el nuevo límite.
La mayoría de las organizaciones fallan en esto. Intentan adaptar proveedores de identidad (IdPs) centralizados heredados a clústeres dinámicos de Kubernetes multi-cloud, lo que resulta en integraciones frágiles, permisos excesivos y puntos únicos de fallo. En este artículo, analizamos el problema, proponemos una arquitectura y le mostramos exactamente cómo implementarla sin comprometer la velocidad de desarrollo de los ingenieros.
El problema: la trampa de la identidad en estrella (Hub-and-Spoke Identity Trap)
Cuando las empresas adoptan por primera vez una estrategia multi-cloud, suelen enrutar toda la autenticación y autorización a través de un único directorio centralizado (por ejemplo, Active Directory o una única instancia de Okta). Esto crea la trampa de la identidad en estrella.
Cada servicio en AWS que intenta acceder a una base de datos en GCP debe autenticarse contra el hub central. Este diseño introduce tres fallas críticas:
- Latencia: Una arquitectura de microservicios que realiza cientos de llamadas a APIs internas por segundo no puede permitirse la latencia de ida y vuelta a un IdP central.
- Disponibilidad: Si el IdP central se cae, toda la infraestructura multi-cloud se detiene.
- Radio de impacto (Blast Radius): Un directorio central comprometido otorga al atacante las llaves de todo el reino, en todas las nubes.
Es necesario que las identidades se verifiquen localmente, pero se gestionen de forma global.
Por qué es difícil el IAM descentralizado y la seguridad multi-cloud
Descentralizar la identidad significa distribuir la confianza, y distribuir la confianza requiere pruebas criptográficas que se validen continuamente. Cuando tiene una carga de trabajo en AWS EKS que necesita leer un objeto en un bucket de Google Cloud Storage, ¿cómo sabe GCP que puede confiar en el pod de AWS?
El enfoque ingenuo es el uso de credenciales estáticas de larga duración (por ejemplo, claves de acceso de AWS o archivos JSON de cuentas de servicio de GCP) almacenados en Vault o Kubernetes Secrets. Este es un grave patrón erróneo. Las credenciales estáticas se filtran, rara vez se rotan y rompen el principio básico de Zero Trust: acceso efímero y delimitado.
El desafío consiste en establecer la federación de identidades de carga de trabajo (workload identity federation) a través de diferentes dominios de confianza. Debe mapear una identidad en el Dominio A (proveedor OIDC de AWS) a un rol en el Dominio B (IAM de GCP) sin intercambiar secretos de larga duración.
La arquitectura propuesta: federación de identidades de carga de trabajo
Defendemos una arquitectura en la que cada entorno actúa como su propio proveedor de identidad (IdP) para las cargas de trabajo que aloja. Estos IdPs locales federan la confianza con otros entornos de nube utilizando OpenID Connect (OIDC).
Nuestra arquitectura de referencia utiliza:
- Kubernetes (EKS v1.30): Aloja las cargas de trabajo.
- AWS IAM OIDC Provider: El IdP local para EKS.
- GCP Workload Identity Federation: Confía en el proveedor OIDC de AWS.
- SPIFFE/SPIRE (v1.8.0): Para mTLS interno de servicio a servicio y emisión de identidades.
En lugar de pasar secretos, la carga de trabajo solicita un token de corta duración a su entorno local. Ese token está firmado criptográficamente por el IdP local. El entorno de destino (GCP) verifica la firma, mapea la reclamación (claim) de OIDC a un rol de IAM local y otorga acceso temporal.
Implementación: de AWS EKS a GCP BigQuery
Veamos una implementación concreta. Tenemos un servicio de ingesta de datos que se ejecuta en un clúster de AWS EKS y necesita escribir en un dataset de GCP BigQuery.
1. Configurar el proveedor OIDC de AWS EKS
Primero, asegúrese de que su clúster de EKS tenga asociado un proveedor de IAM OIDC. Esto permite que las cuentas de servicio de Kubernetes asuman roles de IAM, pero lo más importante es que nos proporciona una URL emisora en la que GCP puede confiar.
# Terraform v1.8.0
# AWS Provider v5.40.0
data "tls_certificate" "eks" {
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
resource "aws_iam_openid_connect_provider" "eks" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = [data.tls_certificate.eks.certificates[0].sha1_fingerprint]
url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
2. Crear el Workload Identity Pool en GCP
En GCP, creamos un Workload Identity Pool y un Proveedor. El Proveedor apunta a la URL emisora del OIDC de AWS EKS. Mapeamos la reclamación sub (que contiene el namespace de Kubernetes y el nombre de la cuenta de servicio) a un sujeto de Google IAM.
# GCP Provider v5.20.0
resource "google_iam_workload_identity_pool" "aws_pool" {
workload_identity_pool_id = "aws-eks-pool"
display_name = "AWS EKS Trust Pool"
description = "Identity pool for EKS workloads"
}
resource "google_iam_workload_identity_pool_provider" "aws_provider" {
workload_identity_pool_id = google_iam_workload_identity_pool.aws_pool.workload_identity_pool_id
workload_identity_pool_provider_id = "aws-eks-provider"
display_name = "AWS EKS OIDC Provider"
attribute_mapping = {
"google.subject" = "assertion.sub"
"attribute.namespace" = "assertion['kubernetes.io']['namespace']"
}
oidc {
issuer_uri = aws_eks_cluster.main.identity[0].oidc[0].issuer
}
}
3. Vincular la cuenta de servicio de GCP
Ahora creamos una cuenta de servicio de GCP que tenga permisos para escribir en BigQuery y permitimos que la cuenta de servicio de Kubernetes específica (a través del Identity Pool) se haga pasar por ella.
resource "google_service_account" "bq_writer" {
account_id = "bq-writer-sa"
display_name = "BigQuery Writer Service Account"
}
resource "google_project_iam_member" "bq_data_editor" {
project = var.project_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:${google_service_account.bq_writer.email}"
}
resource "google_service_account_iam_member" "workload_identity_user" {
service_account_id = google_service_account.bq_writer.name
role = "roles/iam.workloadIdentityUser"
# La cadena del miembro coincide con el mapeo del sujeto de Google del proveedor
# formato: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT
member = "principal://iam.googleapis.com/${google_iam_workload_identity_pool.aws_pool.name}/subject/system:serviceaccount:data-ingest:bq-writer"
}
4. El código de la aplicación
La aplicación que se ejecuta en EKS utiliza el SDK de Google Cloud. El SDK detecta automáticamente el token de la cuenta de servicio proyectado provisto por EKS, lo utiliza para autenticarse contra el GCP Workload Identity Pool y recupera un token de acceso de corta duración para bq-writer-sa. No se requieren claves estáticas.
# Definición de la ServiceAccount y el Pod de Kubernetes
apiVersion: v1
kind: ServiceAccount
metadata:
name: bq-writer
namespace: data-ingest
annotations:
# Opcional: Si también necesita permisos de AWS
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/bq-writer-role
---
apiVersion: v1
kind: Pod
metadata:
name: bq-writer-app
namespace: data-ingest
spec:
serviceAccountName: bq-writer
containers:
- name: app
image: my-registry/bq-writer:v1.2.0
env:
# Indicar al SDK de Google dónde encontrar la configuración de credenciales
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /var/run/secrets/google/credentials.json
volumeMounts:
- name: google-cloud-key
mountPath: /var/run/secrets/google
- name: k8s-token
mountPath: /var/run/secrets/tokens
volumes:
- name: google-cloud-key
configMap:
name: workload-identity-config
- name: k8s-token
projected:
sources:
- serviceAccountToken:
path: oidc-token
expirationSeconds: 3600
audience: sts.amazonaws.com # O su audiencia de GCP
Errores a evitar
La implementación de esta arquitectura no está exenta de riesgos. Estos son los modos de fallo comunes que observamos cuando los equipos adoptan un IAM descentralizado:
1. Mapeo de reclamaciones (Claim Mapping) demasiado amplio
Al configurar el mapeo de atributos del Workload Identity Provider, no mapee reclamaciones amplias. Si mapea "google.subject" = "assertion.aud", estará permitiendo que cualquier carga de trabajo en el clúster de EKS se haga pasar por la cuenta de servicio de GCP. Mapee siempre hasta el sub (sujeto) específico que incluye el namespace y el nombre de la cuenta de servicio (system:serviceaccount:namespace:sa-name).
2. Ignorar la expiración del token
Los tokens de cuentas de servicio proyectados en Kubernetes expiran. Su aplicación debe ser capaz de recargar dinámicamente las credenciales. La mayoría de los SDKs modernos manejan esto automáticamente, pero la lógica de autenticación personalizada a menudo almacena los tokens en caché indefinidamente, lo que genera fallas difíciles de depurar cuando el token expira después de una hora.
3. Descuidar los logs de auditoría
La descentralización dificulta la visibilidad. Debe agregar los logs de auditoría de AWS CloudTrail, GCP Cloud Logging y el servidor de API de Kubernetes en un SIEM centralizado. Si se compromete una identidad de carga de trabajo, debe poder rastrear sus acciones a través de los límites de la nube. Asegúrese de correlacionar la reclamación sub del token OIDC con las llamadas a la API resultantes en el entorno de destino.
El resultado: la seguridad como facilitador
Migrar a una arquitectura de IAM federada y descentralizada cambia fundamentalmente la postura de seguridad de una organización de ingeniería.
Al eliminar las credenciales estáticas, erradica el vector principal para ataques a la cadena de suministro. Cuando un desarrollador necesita que un nuevo servicio acceda a un recurso en otra nube, no solicita una clave al equipo de seguridad; escribe un módulo de Terraform para establecer la relación de confianza y definir la política.
La seguridad se convierte en código. La confianza se vuelve efímera. La infraestructura se vuelve resiliente. Este es el único camino a seguir para los equipos de ingeniería serios que operan a escala.
Servicio de Seven Labs
Pruebas de Penetración VAPT y Ciberseguridad
