Módulo 7: Eks Specifics For Production
5. IRSA y su sucesor, EKS Pod Identity
Descripción
Dos guías hermanas de este ecosistema ya resolvieron una versión de este mismo problema: cicd-and-gitops-on-aws-guide (Módulo 4) le dio a un job de GitHub Actions una identidad temporal en AWS, sin ningún secreto de larga vida guardado en ningún lado, usando OIDC. cloud-security-and-guardrails-guide (Módulo 2) construyó ese mismo patrón a fondo — el proveedor OIDC, la trust policy, el intercambio de un JWT de corta vida por credenciales temporales — como el reemplazo correcto de una AWS_ACCESS_KEY_ID hardcodeada. Esta lección toma exactamente esa misma idea de fondo y la aplica a un lugar nuevo: no un job de CI que corre unos minutos y termina, sino un Pod de Kubernetes que corre indefinidamente, dentro de tu clúster, necesitando hablarle a AWS con una identidad propia.
Conexión con el módulo
Antes de esta lección, andes-cargo-status-api nunca necesitó hablarle a ningún servicio de AWS en este laboratorio — todo lo que hace es servir HTTP y leer una tabla que, en kind, vive en LocalStack. En un EKS real, contra la tabla Shipments real de DynamoDB, ese Pod necesita una identidad de AWS legítima para hacer dynamodb:GetItem — exactamente el permiso que aws-serverless-and-containers-guide ya diseñó, sin ejecutarlo nunca, bajo el nombre StatusApiTaskRole. Esta lección cierra ese círculo.
El mismo patrón OIDC, un contexto nuevo
Repasa la idea de fondo, sin repetir la mecánica completa que las dos guías hermanas ya construyeron: en vez de distribuir una credencial de AWS de larga vida a algo que la necesita (un job de CI, un Pod), ese "algo" presenta un token firmado, de corta vida, emitido por un sistema en el que AWS ya confía —GitHub, en el caso de las guías hermanas; el propio clúster de Kubernetes, en el caso de esta lección—, y AWS lo intercambia por credenciales temporales, sin que ningún secreto estático haya existido nunca.
EL MISMO PRINCIPIO, TRES CONTEXTOS DISTINTOS
cicd-and-gitops-on-aws-guide (M4) cloud-security-and-guardrails
────────────────────────────── -guide (M2)
Un job de GitHub Actions ────────────────────────────
presenta un JWT de GitHub El mismo JWT de GitHub,
→ AWS STS AssumeRoleWithWebIdentity evaluado con más profundidad
→ credenciales temporales (condiciones de trust policy,
mínimo privilegio)
kubernetes-and-eks-in-production-guide (M7, este)
──────────────────────────────────────────────────
Un Pod presenta un JWT emitido por el
propio clúster EKS (IRSA) o recibe
credenciales de un agente en su nodo
(EKS Pod Identity)
→ AWS STS / EKS Auth Service
→ credenciales temporales
El JWT cambia de emisor —de GitHub al propio clúster de Kubernetes—, y el mecanismo exacto de intercambio cambia según elijas IRSA o EKS Pod Identity (la siguiente sección lo diferencia con precisión), pero el principio de fondo es idéntico al que ya conoces: nunca una credencial estática, siempre un token de corta vida, intercambiado en el momento en que se necesita.
IRSA: el mecanismo tradicional, todavía vigente
IRSA (IAM Roles for Service Accounts) es el mecanismo original de EKS para este problema, construido directamente sobre OIDC — el mismo estándar que ya usaste con GitHub Actions. Cada clúster EKS puede tener un proveedor OIDC propio, único por clúster (lo confirmaste en la lección 2 de este módulo: identity.oidc.issuer en la salida de describe-cluster). Una vez que ese proveedor existe, IRSA vincula un rol IAM a un ServiceAccount de Kubernetes mediante una anotación:
Con eksctl (representativo) — crea el ServiceAccount y el rol IAM en un solo comando, adjuntando una policy existente:
eksctl create iamserviceaccount \
--name status-api-service-account \
--namespace andes-cargo \
--cluster andes-cargo-cluster \
--role-name StatusApiTaskRole \
--attach-policy-arn arn:aws:iam::000000000000:policy/StatusApiReadOnlyPolicy \
--approve
El resultado, verificado contra la documentación oficial de AWS, es un ServiceAccount con una anotación específica que el SDK de AWS reconoce automáticamente dentro del Pod:
apiVersion: v1
kind: ServiceAccount
metadata:
name: status-api-service-account
namespace: andes-cargo
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::000000000000:role/StatusApiTaskRole
Y la trust policy del rol —la pieza que responde "¿quién tiene permitido asumir este rol?"— confía específicamente en el proveedor OIDC de este clúster, condicionado a que el token venga exactamente de este ServiceAccount, en este namespace:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::000000000000:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:andes-cargo:status-api-service-account",
"oidc.eks.us-east-1.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
}
}
}
]
}
Fíjate en la condición :sub — es, con otro proveedor, la misma idea exacta que ya viste en cloud-security-and-guardrails-guide M2 restringiendo la trust policy de GitHub Actions a un repositorio y una rama específicos: aquí, en vez de un repositorio de GitHub, la condición ata el rol a un namespace y un ServiceAccount exactos de este clúster. Un Pod en otro namespace, o un Pod que use un ServiceAccount distinto, nunca podría asumir este rol, aunque corriera en el mismo clúster.
EKS Pod Identity: el sucesor recomendado para carga nueva
EKS Pod Identity es el mecanismo más reciente, y AWS lo documenta explícitamente como más simple que IRSA —la propia documentación oficial lo dice sin rodeos:
"EKS Pod Identity is a simpler method than IAM roles for service accounts, as this method doesn't use OIDC identity providers."
La diferencia técnica de fondo: en vez de que cada clúster tenga su propio proveedor OIDC al que IAM debe aprender a confiar individualmente, EKS Pod Identity introduce un único principal de servicio (pods.eks.amazonaws.com) que cualquier rol puede confiar de una vez, sin importar en qué clúster corra el Pod:
{
"Principal": {
"Service": "pods.eks.amazonaws.com"
}
}
Y en vez de que cada SDK de AWS, dentro de cada Pod, negocie el intercambio de token directamente contra AWS STS, un agente (Amazon EKS Pod Identity Agent, un DaemonSet que corre en cada nodo) centraliza ese trabajo — la documentación lo describe así: "Each set of temporary credentials is assumed by the EKS Auth service in EKS Pod Identity, instead of each AWS SDK that you run in each pod... the load is reduced to once for each node and isn't duplicated in each pod."
Con eksctl (representativo) — la sintaxis equivalente para EKS Pod Identity:
eksctl create podidentityassociation \
--cluster andes-cargo-cluster \
--namespace andes-cargo \
--service-account-name status-api-service-account \
--role-name StatusApiTaskRole \
--permission-policy-arns arn:aws:iam::000000000000:policy/StatusApiReadOnlyPolicy
Fíjate en lo que desaparece frente a IRSA: no hay ningún proveedor OIDC que crear una sola vez por clúster, no hay ninguna condición :sub/:aud que escribir a mano en la trust policy — la asociación entre el ServiceAccount y el rol vive del lado de EKS, no codificada dentro de la política de IAM.
La comparación exacta, verificada contra AWS Docs
| IRSA | EKS Pod Identity | |
|---|---|---|
| Necesita un proveedor OIDC por clúster | Sí | No |
| Principal de la trust policy | Único por clúster (el issuer de ese OIDC provider) | Único y reutilizable: pods.eks.amazonaws.com, el mismo para cualquier clúster |
| Quién negocia el intercambio de credenciales | Cada SDK de AWS, dentro de cada Pod | Un agente centralizado (DaemonSet), una vez por nodo |
| Compatible con Fargate | Sí | No — restringido a nodos Linux EC2 (verificado: "Linux and Windows pods that run on AWS Fargate aren't supported") |
| Quién administra qué | Equipos separados pueden administrar el proveedor OIDC (infraestructura) y las policies de IAM (seguridad) de forma independiente | Configuración de la asociación vive en EKS; permisos de IAM viven en IAM — "clean separation of duties", en palabras de AWS |
| Fecha de baja anunciada para IRSA | Ninguna — verificado contra docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html, documentación completa y vigente, sin ningún aviso de deprecación | No aplica |
| Guía práctica de la industria (2026) | Recomendado para clústeres existentes que ya lo usan, y obligatorio para Fargate | Recomendado por AWS para carga nueva sobre nodos EC2 |
La fila que más vale la pena retener con precisión, porque es fácil sacar la conclusión equivocada: IRSA no tiene ninguna fecha de baja anunciada. La documentación oficial de AWS que describe IRSA, al momento de escribir esta lección, sigue completa, vigente, y sin ningún aviso de "deprecated" o "legacy" en ningún lugar visible. La guía práctica —"Pod Identity para carga nueva sobre EC2, IRSA para Fargate y para clústeres existentes que ya lo tienen funcionando"— es una síntesis razonable de cómo la industria y la propia estructura de la documentación de AWS presentan la elección en 2026, no una cita textual única de un párrafo de AWS que diga esa frase exacta con esas palabras. Los dos mecanismos coexisten sin conflicto: nada impide que un clúster tenga algunos ServiceAccount usando IRSA (heredados) y otros usando EKS Pod Identity (nuevos) al mismo tiempo.
Cierra el círculo: StatusApiTaskRole, de ECS-solo-documentado a rol de un ServiceAccount
aws-serverless-and-containers-guide, Módulo 1, diseñó StatusApiTaskRole con un propósito exacto y acotado: permiso de solo lectura (dynamodb:GetItem, opcionalmente dynamodb:Query) sobre la tabla Shipments — nada de escribir, nada de borrar, nada sobre ningún otro recurso. Ese rol se creó, en la práctica, solo como JSON representativo: la trust policy confiaba en ecs-tasks.amazonaws.com, porque la intención original era que una tarea de ECS lo asumiera. ECS nunca llegó a correr en ese laboratorio (LocalStack Hobby no lo cubre), así que ese rol nunca tuvo, hasta ahora, un consumidor real que lo asumiera.
En este módulo, ese mismo nombre y ese mismo propósito se retoman, con un consumidor distinto: no una tarea de ECS, sino un ServiceAccount de Kubernetes, vía IRSA o EKS Pod Identity. Lo único que cambia es la trust policy —de ecs-tasks.amazonaws.com a pods.eks.amazonaws.com (Pod Identity) o al proveedor OIDC del clúster (IRSA)—; los permisos (la permission policy, dynamodb:GetItem sobre el ARN exacto de Shipments) son, en espíritu, exactamente los mismos que la guía anterior ya diseñó:
StatusApiTaskRole — MISMO NOMBRE, MISMO PROPÓSITO,
DISTINTO CONSUMIDOR
aws-serverless-and-containers-guide (nunca aplicado)
──────────────────────────────────────────────────────
trust policy: Principal.Service = "ecs-tasks.amazonaws.com"
consumidor: una tarea de ECS (nunca corrió)
permisos: dynamodb:GetItem sobre Shipments
kubernetes-and-eks-in-production-guide (M7, representativo)
──────────────────────────────────────────────────────
trust policy: Principal.Service = "pods.eks.amazonaws.com" (Pod Identity)
o Federated = OIDC provider del clúster (IRSA)
consumidor: el ServiceAccount de andes-cargo-status-api
permisos: dynamodb:GetItem sobre Shipments ── SIN CAMBIOS
Este es el mismo patrón narrativo que el Módulo 1 de esta guía ya estableció con andes-cargo-cluster y status-api-service: un nombre que la guía anterior dejó documentado, nunca ejecutado, retomado aquí con su propósito intacto — solo que, esta vez, ni siquiera esta guía llega a ejecutarlo contra una cuenta real, por la misma razón declarada en la lección 1 de este módulo. Lo que sí cambia, y es el punto real de esta lección, es quién asume el rol: ya no es una infraestructura de contenedores gestionada centralmente por ECS, es un ServiceAccount de Kubernetes, con la misma disciplina de mínimo privilegio.
Errores comunes
Pensar que EKS Pod Identity "reemplaza" a IRSA de forma obligatoria, y que IRSA hay que migrarlo ya (de urgencia mal calibrada). Qué pasa: alguien, al enterarse de que existe un mecanismo "más simple", asume que tiene que migrar cualquier ServiceAccount existente con IRSA de inmediato. Cómo detectarlo: si tu plan de trabajo incluye "migrar todo IRSA a Pod Identity" sin ninguna fecha de baja real que lo justifique. Cómo corregirlo: esta lección confirmó, contra documentación oficial vigente, que no hay ninguna fecha de baja anunciada para IRSA — los dos mecanismos coexisten sin conflicto. La guía práctica es usar Pod Identity para carga nueva, no migrar retroactivamente algo que ya funciona sin una razón técnica concreta (por ejemplo, simplificar la administración multi-cuenta).
Intentar usar EKS Pod Identity con Fargate profiles, sin verificar la restricción primero (técnico). Qué pasa: un equipo que decidió usar Fargate profiles (lección 3 de este módulo) para andes-cargo-status-api intenta también configurar EKS Pod Identity para ese mismo Pod. Cómo detectarlo: si tu plan combina Fargate profiles con EKS Pod Identity sin haber revisado esta restricción. Cómo corregirlo: la documentación de AWS confirma explícitamente que EKS Pod Identity no soporta Pods que corren en Fargate — un servicio que use Fargate profiles necesita usar IRSA para su identidad de AWS, no Pod Identity. Es una de las pocas combinaciones donde IRSA sigue siendo, no solo válido, sino la única opción.
Confundir el rol de StatusApiTaskRole con el Pod execution role de un Fargate profile (de superposición de conceptos vecinos, retomado de la lección 3). Qué pasa: alguien mezcla el rol que necesita tu código (StatusApiTaskRole, vía IRSA/Pod Identity) con el rol que necesita la infraestructura de Fargate para arrancar el Pod (el Pod execution role de la lección 3). Cómo detectarlo: si intentas usar StatusApiTaskRole como el Pod execution role de un Fargate profile, o viceversa. Cómo corregirlo: son, otra vez, la misma distinción de "Pregunta 1 / Pregunta 2" que ya viste con ECS (EcsTaskExecutionRole vs StatusApiTaskRole) y con el Pod execution role de Fargate en la lección 3 de este módulo — un rol para que la infraestructura pueda arrancar el Pod, un rol completamente distinto para lo que el código de ese Pod puede hacer una vez corriendo. Nunca es el mismo rol.
Ejercicios
Ejercicio 1 — Completa la tabla de memoria. Sin mirar la sección de comparación de esta lección, responde: ¿cuál de los dos mecanismos necesita un proveedor OIDC por clúster? ¿Cuál es compatible con Fargate? ¿Cuál tiene una fecha de baja anunciada?
Ver solución
IRSA necesita un proveedor OIDC propio por clúster; EKS Pod Identity no lo necesita, usa un único principal de servicio reutilizable (pods.eks.amazonaws.com). Solo IRSA es compatible con Fargate — EKS Pod Identity está restringido a nodos Linux EC2. Ninguno de los dos tiene fecha de baja anunciada: ambos están completamente soportados y vigentes en la documentación oficial de AWS.
Ejercicio 2 — Explica la elección de mecanismo para un caso real, sin usar la palabra "simple". Un colega te pregunta cuál de los dos mecanismos elegir para un ServiceAccount nuevo, en un clúster EKS nuevo, sin ningún Fargate profile de por medio. Respóndele en una frase, sin usar la palabra "simple" ni "simplicidad".
Ver solución
Una respuesta completa suena, más o menos, así: "Para carga completamente nueva, sin restricción de Fargate, EKS Pod Identity es la vía que AWS documenta como la recomendada — no necesitas crear ni mantener un proveedor OIDC, y la asociación entre el ServiceAccount y el rol IAM vive centralizada en EKS en vez de codificada dentro de la trust policy del rol."
Ejercicio 3 — Predice qué mecanismo usaría andes-cargo-status-api si el equipo hubiera elegido Fargate profiles en la lección 3. Basándote en la restricción exacta de esta lección, predice qué mecanismo de identidad tendría que usar andes-cargo-status-api si, en vez de un managed node group, el equipo hubiera elegido correrlo sobre un Fargate profile.
Ver solución
IRSA, sin alternativa. La documentación oficial de AWS confirma que EKS Pod Identity no soporta Pods que corren en AWS Fargate (Linux ni Windows) — así que un servicio corriendo sobre un Fargate profile necesita, obligatoriamente, el mecanismo de proveedor OIDC de IRSA para obtener credenciales de AWS, sin importar que EKS Pod Identity sea, en general, la vía recomendada para carga nueva sobre EC2.
Resumen y siguiente paso
Esta lección aplicó, por primera vez en este ecosistema, el patrón OIDC de identidad federada a un Pod de Kubernetes en vez de a un job de CI —el mismo principio de fondo que cicd-and-gitops-on-aws-guide M4 y cloud-security-and-guardrails-guide M2 ya construyeron para GitHub Actions—. Comparaste, con sintaxis real de eksctl y citas exactas de AWS Docs, IRSA (el mecanismo tradicional, con proveedor OIDC por clúster, todavía sin fecha de baja) frente a EKS Pod Identity (el sucesor recomendado para carga nueva, sin OIDC provider, con la restricción real de no soportar Fargate). Cerraste el círculo con StatusApiTaskRole: el mismo nombre, el mismo propósito de mínimo privilegio que aws-serverless-and-containers-guide diseñó para ECS y nunca aplicó, retomado aquí con un consumidor nuevo — un ServiceAccount de Kubernetes, no una tarea de ECS.
Antes de avanzar deberías poder: explicar, sin confundirlos, qué necesita cada mecanismo (proveedor OIDC vs principal único); citar la restricción real de EKS Pod Identity con Fargate; y describir qué cambia y qué no cambia de StatusApiTaskRole al pasar de ECS a un ServiceAccount.
Siguiente lección: el AWS Load Balancer Controller — el Ingress real de producción. Ahí vas a ver el contraste directo con ingress-nginx, que instalaste y ejecutaste de verdad en el Módulo 4: mismo objeto Ingress, distinto controlador por debajo.
Recursos
- Amazon EKS — IAM roles for service accounts — la referencia oficial de IRSA, verificada para confirmar que no anuncia ninguna fecha de baja.
- Amazon EKS — Learn how EKS Pod Identity grants pods access to AWS services — la fuente exacta de la cita "simpler method than IAM roles for service accounts" y de la restricción con Fargate.
- Amazon EKS — Assign IAM roles to Kubernetes service accounts — sintaxis completa de
eksctl create iamserviceaccount, la fuente del ejemplo representativo de esta lección. cicd-and-gitops-on-aws-guide(NIEVA), Módulo 4 — el patrón OIDC original aplicado a GitHub Actions, la base conceptual de esta lección.cloud-security-and-guardrails-guide(NIEVA), Módulo 2 — la profundización de ese mismo patrón (trust policy condicionada, mínimo privilegio) que esta lección reaplica a un Pod.aws-serverless-and-containers-guide(NIEVA), Módulo 1, lección 6 — el diseño original deStatusApiTaskRole, retomado aquí sin cambios en sus permisos.