IRSA vs. EKS Pod Identity

Hello World 🙂
En la entrada de hoy hablaremos sobre un tema muy importante dentro del ecosistema de Amazon EKS: IRSA y EKS Pod Identity.
IRSA vs. EKS Pod Identity: cómo dar acceso seguro a servicios de AWS desde nuestros pods
Ambos mecanismos nos permiten resolver un problema muy común: cómo hacer que nuestros pods tengan una identidad propia dentro de AWS y puedan acceder de forma segura a servicios que se encuentran fuera del clúster.
A lo largo de esta entrada veremos cómo funciona cada uno, cuáles son sus principales diferencias, qué ventajas ofrecen y, por supuesto, algunos ejemplos prácticos que nos ayudarán a entender mejor de qué estamos hablando.
Cuando una aplicación se ejecuta dentro de Amazon EKS, tarde o temprano puede necesitar comunicarse con algún servicio de AWS.
Por ejemplo, un pod puede necesitar:
- Leer archivos almacenados en Amazon S3.
- Recuperar secretos desde AWS Secrets Manager.
Una posible solución sería almacenar credenciales de AWS dentro de un Secret de Kubernetes y entregarlas posteriormente a la aplicación como variables de entorno.
Sin embargo, esto implicaría manejar credenciales de larga duración, gestionar su rotación y asumir un riesgo de seguridad innecesario. En definitiva, no sería una buena práctica.
Amazon EKS nos ofrece dos mecanismos principales para resolver este problema utilizando credenciales temporales:
- IAM Roles for Service Accounts (IRSA).
- Amazon EKS Pod Identity.
Ambos mecanismos permiten relacionar una ServiceAccount de Kubernetes con permisos de IAM, de manera que los pods que utilicen esa ServiceAccount puedan obtener credenciales temporales y acceder únicamente a los recursos de AWS que necesitan.
Aunque ambos persiguen el mismo objetivo, su funcionamiento y configuración son diferentes.
El problema con el IAM Role de los nodos
Antes de hablar de IRSA y Pod Identity, es importante entender el problema que intentan resolver.
Cuando utilizamos worker nodes basados en EC2 dentro de un clúster de EKS, estos nodos tienen asociado un IAM Role. Este rol les proporciona los permisos necesarios para realizar determinadas operaciones dentro de AWS, como por ejemplo registrarse correctamente en el clúster y utilizar algunos de los servicios que necesitan para funcionar.
Hasta aquí, todo bien.
El problema aparece cuando empezamos a utilizar ese mismo IAM Role como mecanismo para dar acceso a servicios de AWS a las aplicaciones que se ejecutan dentro de los pods.
Por ejemplo, imaginemos que una aplicación necesita leer objetos desde un bucket de S3.
Podríamos simplemente agregar al IAM Role de los worker nodes una política que permita acceder a ese bucket.
La aplicación funcionaría, pero estaríamos creando un problema de seguridad.
¿Por qué?
Porque esos permisos no estarían siendo otorgados solamente a esa aplicación. Todos los pods que tengan la posibilidad de utilizar las credenciales del IAM Role de esos nodos podrían terminar teniendo acceso al mismo recurso.
Lo mismo podría ocurrir si agregamos permisos para:
- AWS Secrets Manager.
- DynamoDB.
- Amazon SQS.
- Parameter Store, etc.
A medida que agregamos políticas al rol del nodo para cubrir las necesidades de diferentes aplicaciones, terminamos construyendo un IAM Role con una gran cantidad de permisos compartidos por múltiples workloads.
Y es aquí donde empezamos a alejarnos de uno de los principios fundamentales de seguridad en AWS: el principio de mínimo privilegio.
La idea debería ser muy diferente:
Aplicación A → solamente permisos para S3
Aplicación B → solamente permisos para Secrets Manager
Aplicación C → solamente permisos para DynamoDB
Cada aplicación debería tener únicamente los permisos que realmente necesita para realizar su trabajo.
Para conseguirlo necesitamos que los pods puedan utilizar una identidad de AWS independiente del IAM Role del nodo donde se están ejecutando.
Y aquí es precisamente donde entran en juego las ServiceAccount, IRSA y EKS Pod Identity.
ServiceAccount como identidad del workload
En Kubernetes, una ServiceAccount proporciona una identidad a los procesos que se ejecutan dentro de un pod.
Por ejemplo, podemos tener diferentes cuentas de servicio para distintas aplicaciones:
orders-api-sa
payments-api-sa
Y asociar cada pod con la ServiceAccount correspondiente.
Por sí sola, una ServiceAccount pertenece al mundo de Kubernetes y no proporciona permisos sobre servicios de AWS.
Sin embargo, IRSA y EKS Pod Identity utilizan esa identidad de Kubernetes como punto de unión con IAM.
De esta manera podemos conseguir algo como esto:
Pod --> ServiceAccount --> IAM Role --> IAM Policy --> Servicio de AWS
Por ejemplo:
orders-api --> orders-api-sa --> OrdersIAMRole --> Permisos únicamente sobre un bucket de S3
Mientras que otra aplicación podría utilizar:
payments-api --> payments-api-sa --> PaymentsIAMRole --> Permisos únicamente sobre Secrets Manager
De esta forma dejamos de depender del IAM Role del nodo para entregar permisos a nuestras aplicaciones y podemos aplicar el principio de mínimo privilegio de una manera mucho más precisa.
El objetivo de IRSA y EKS Pod Identity es exactamente ese: permitir que nuestros workloads dentro de EKS obtengan credenciales temporales de AWS asociadas a la identidad de la aplicación y no a la identidad del worker node donde se están ejecutando.
A partir de aquí podemos empezar a analizar cómo funciona cada mecanismo y cuáles son las diferencias entre ambos.
¿Qué es IRSA?
IRSA significa IAM Roles for Service Accounts.
Con IRSA asociamos un IAM Role con una ServiceAccount de Kubernetes mediante una anotación.
Cuando un pod utiliza esa ServiceAccount, Kubernetes genera un token firmado. El AWS SDK que se ejecuta dentro del contenedor utiliza ese token para llamar a AWS STS mediante la operación:
AssumeRoleWithWebIdentity
AWS STS valida el token mediante el proveedor OpenID Connect, u OIDC, asociado con el clúster y devuelve credenciales temporales.
El flujo simplificado sería el siguiente:
Pod --> ServiceAccount token --> AWS SDK --> AssumeRoleWithWebIdentity --> AWS STS --> Credenciales temporales --> Servicio de AWS
Para utilizar IRSA, cada clúster debe tener registrado en IAM un proveedor OIDC correspondiente al issuer OIDC del clúster.
Componentes de IRSA
La implementación de IRSA involucra los siguientes componentes:
EKS Cluster
│
├── OIDC Provider
│
├── Kubernetes ServiceAccount
│ └── eks.amazonaws.com/role-arn
│
├── Pod
│ └── serviceAccountName
│
└── IAM Role
├── Trust policy
└── IAM permissions
OIDC Provider
Permite que IAM confíe en los tokens generados por el clúster de Kubernetes.
Cada clúster EKS tiene su propio OIDC issuer. Para utilizar IRSA, debemos registrar ese issuer como proveedor de identidad dentro de IAM.
ServiceAccount
Representa la identidad del workload dentro de Kubernetes.
La ServiceAccount incluye una anotación con el ARN del IAM Role:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/EksIrsaS3ReadRole
IAM Role
El IAM Role contiene dos elementos importantes:
- Una política de permisos que indica qué operaciones puede realizar.
- Una trust policy que indica qué
ServiceAccountpuede asumirlo.
Pod
El pod debe especificar la ServiceAccount:
spec:
serviceAccountName: s3-reader-irsa
Ventajas de IRSA
Permisos específicos por aplicación
Cada aplicación puede utilizar una ServiceAccount diferente y recibir únicamente los permisos que necesita.
Credenciales temporales
Las aplicaciones no necesitan almacenar AWS_ACCESS_KEY_ID ni AWS_SECRET_ACCESS_KEY.
El AWS SDK obtiene y renueva automáticamente las credenciales temporales.
Integración con el AWS SDK
Cuando la aplicación utiliza la cadena de credenciales predeterminada del AWS SDK, no es necesario modificar su código.
Por ejemplo, una aplicación en Python puede crear un cliente de S3 de esta forma:
import boto3
s3 = boto3.client("s3")
El SDK descubrirá automáticamente las credenciales proporcionadas mediante IRSA, siempre que no configuremos otro proveedor de credenciales manualmente.
Compatibilidad amplia
IRSA no depende directamente de la API de EKS y puede utilizarse en diferentes implementaciones de Kubernetes compatibles con AWS, incluyendo Amazon EKS, EKS Anywhere y clústeres autogestionados sobre EC2. También continúa siendo una opción importante para workloads ejecutados sobre EKS Fargate.
Auditoría
Las llamadas realizadas por los pods pueden consultarse en AWS CloudTrail, permitiendo identificar el rol utilizado y analizar las acciones realizadas.
Desventajas de IRSA
Requiere un proveedor OIDC por clúster
Cada clúster debe registrar su propio proveedor OIDC en IAM.
Esto agrega pasos adicionales y puede convertirse en una limitación cuando administramos una gran cantidad de clústeres.
Trust policies más complejas
La trust policy del IAM Role debe incluir:
- El ARN del proveedor OIDC.
- El namespace.
- El nombre de la
ServiceAccount. - La audiencia del token.
Además, si reutilizamos el mismo IAM Role en varios clústeres, debemos agregar el proveedor OIDC de cada clúster a la trust policy.
Llamadas directas a AWS STS
Cada AWS SDK intercambia el token del pod por credenciales temporales mediante AssumeRoleWithWebIdentity.
En entornos con una gran cantidad de pods o reinicios frecuentes, esto puede incrementar las llamadas a AWS STS y, en casos extremos, generar throttling.
Límites de IAM
IAM tiene límites relacionados con:
- Cantidad de proveedores OIDC por cuenta.
- Tamaño máximo de las trust policies.
- Cantidad de roles disponibles.
La documentación de EKS indica que IAM tiene, de forma predeterminada, un límite de 100 proveedores OIDC por cuenta. Las trust policies también tienen un tamaño predeterminado de 2048 caracteres, lo que limita la cantidad de clústeres y cuentas de servicio que podemos agregar a un mismo rol.
Ejemplo práctico con IRSA
En este ejemplo crearemos un pod que podrá listar los objetos de un bucket de Amazon S3.
Utilizaremos las siguientes variables:
export AWS_REGION="eu-west-2"
export CLUSTER_NAME="my-eks-cluster"
export NAMESPACE="aws-access-demo"
export BUCKET_NAME="my-eks-demo-bucket"
export IRSA_SERVICE_ACCOUNT="s3-reader-irsa"
export IRSA_ROLE_NAME="EksIrsaS3ReadRole"
export POLICY_NAME="EksS3ReadOnlyDemoPolicy"
export ACCOUNT_ID=$(aws sts get-caller-identity \
--query Account \
--output text)
El bucket debe tener un nombre globalmente único.
Paso 1: crear el namespace
kubectl create namespace "${NAMESPACE}"
Paso 2: crear el bucket de prueba
El siguiente comando asume que utilizamos una región diferente de us-east-1:
aws s3api create-bucket \
--bucket "${BUCKET_NAME}" \
--region "${AWS_REGION}" \
--create-bucket-configuration LocationConstraint="${AWS_REGION}"
Creamos un archivo de prueba:
echo "Archivo utilizado para probar IRSA y Pod Identity" > test.txt
aws s3 cp test.txt "s3://${BUCKET_NAME}/test.txt"
Paso 3: crear la política de permisos
Creamos el archivo s3-read-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBucket",
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::REPLACE_BUCKET_NAME"
},
{
"Sid": "ReadObjects",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::REPLACE_BUCKET_NAME/*"
}
]
}
Sustituimos el nombre del bucket:
sed -i "s/REPLACE_BUCKET_NAME/${BUCKET_NAME}/g" s3-read-policy.json
Creamos la política:
export POLICY_ARN=$(aws iam create-policy \
--policy-name "${POLICY_NAME}" \
--policy-document file://s3-read-policy.json \
--query 'Policy.Arn' \
--output text)
Si la política ya existe, podemos recuperar su ARN:
export POLICY_ARN="arn:aws:iam::${ACCOUNT_ID}:policy/${POLICY_NAME}"
Paso 4: asociar el proveedor OIDC
Podemos registrar el proveedor OIDC utilizando eksctl:
eksctl utils associate-iam-oidc-provider \
--cluster "${CLUSTER_NAME}" \
--region "${AWS_REGION}" \
--approve
Este procedimiento solamente debe realizarse una vez por clúster.
Paso 5: obtener el OIDC issuer
export OIDC_PROVIDER=$(aws eks describe-cluster \
--name "${CLUSTER_NAME}" \
--region "${AWS_REGION}" \
--query "cluster.identity.oidc.issuer" \
--output text | sed -e "s/^https:\/\///")
Podemos verificarlo:
echo "${OIDC_PROVIDER}"
La salida tendrá un formato similar a este:
oidc.eks.eu-west-2.amazonaws.com/id/EXAMPLE123456789
Paso 6: crear la trust policy de IRSA
Creamos el archivo irsa-trust-policy.json:
cat > irsa-trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowServiceAccountToAssumeRole",
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com",
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${NAMESPACE}:${IRSA_SERVICE_ACCOUNT}"
}
}
}
]
}
EOF
La condición sub restringe el rol a una única combinación de namespace y ServiceAccount:
system:serviceaccount:aws-access-demo:s3-reader-irsa
De esta manera, otra ServiceAccount del clúster no podrá asumir el rol.
Paso 7: crear el IAM Role
aws iam create-role \
--role-name "${IRSA_ROLE_NAME}" \
--assume-role-policy-document file://irsa-trust-policy.json
Asociamos la política de acceso a S3:
aws iam attach-role-policy \
--role-name "${IRSA_ROLE_NAME}" \
--policy-arn "${POLICY_ARN}"
Paso 8: crear y anotar la ServiceAccount
kubectl create serviceaccount "${IRSA_SERVICE_ACCOUNT}" \
--namespace "${NAMESPACE}"
Agregamos el ARN del IAM Role:
kubectl annotate serviceaccount "${IRSA_SERVICE_ACCOUNT}" \
--namespace "${NAMESPACE}" \
eks.amazonaws.com/role-arn="arn:aws:iam::${ACCOUNT_ID}:role/${IRSA_ROLE_NAME}"
Podemos comprobar la anotación:
kubectl describe serviceaccount "${IRSA_SERVICE_ACCOUNT}" \
--namespace "${NAMESPACE}"
Paso 9: crear el pod de prueba
Creamos el archivo pod-irsa.yaml:
apiVersion: v1
kind: Pod
metadata:
name: s3-reader-irsa
namespace: aws-access-demo
spec:
serviceAccountName: s3-reader-irsa
restartPolicy: Never
containers:
- name: aws-cli
image: public.ecr.aws/aws-cli/aws-cli:latest
command:
- /bin/sh
- -c
args:
- |
echo "Identidad utilizada:"
aws sts get-caller-identity
echo "Objetos encontrados:"
aws s3 ls s3://REPLACE_BUCKET_NAME/
Sustituimos el bucket:
sed -i "s/REPLACE_BUCKET_NAME/${BUCKET_NAME}/g" pod-irsa.yaml
Creamos el pod:
kubectl apply -f pod-irsa.yaml
Paso 10: validar el resultado
kubectl logs \
--namespace "${NAMESPACE}" \
s3-reader-irsa
La identidad debería corresponder al IAM Role de IRSA:
{
"UserId": "AROAXXXXXXXXXXXXX:botocore-session",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/EksIrsaS3ReadRole/botocore-session"
}
También deberíamos ver el archivo almacenado en S3:
2026-07-21 20:10:00 52 test.txt
¿Qué es EKS Pod Identity?
EKS Pod Identity es un mecanismo más reciente diseñado específicamente para Amazon EKS.
Al igual que IRSA, permite asociar un IAM Role con una ServiceAccount, pero elimina la necesidad de:
- Crear un proveedor OIDC en IAM.
- Agregar el issuer OIDC del clúster en la trust policy.
- Anotar la
ServiceAccountcon el ARN del rol.
En su lugar, creamos una Pod Identity Association mediante la API de EKS.
La asociación relaciona directamente estos cuatro elementos:
EKS Cluster
Namespace
ServiceAccount
IAM Role
El flujo simplificado es el siguiente:
Pod --> Token y variables inyectadas por EKS --> EKS Pod Identity Agent --> AssumeRoleForPodIdentity --> EKS Auth API --> Credenciales temporales --> AWS SDK --> Servicio de AWS
El EKS Pod Identity Agent se ejecuta como un DaemonSet en los nodos. Cuando se inicia un pod que utiliza una ServiceAccount asociada, EKS inyecta un token y variables como AWS_CONTAINER_CREDENTIALS_FULL_URI. El AWS SDK utiliza esas variables para obtener las credenciales temporales desde el agente local.
Componentes de EKS Pod Identity
EKS Cluster
│
├── EKS Pod Identity Agent
│
├── Pod Identity Association
│ ├── Namespace
│ ├── ServiceAccount
│ └── IAM Role
│
├── Kubernetes ServiceAccount
│ └── Sin anotación IAM
│
├── Pod
│ └── serviceAccountName
│
└── IAM Role
├── pods.eks.amazonaws.com
└── IAM permissions
EKS Pod Identity Agent
Es un add-on que se ejecuta en los nodos del clúster.
El agente obtiene las credenciales desde la API EKS Auth y las entrega a los pods que se ejecutan en ese nodo.
Los nodos deben tener permiso para ejecutar:
eks-auth:AssumeRoleForPodIdentity
La política administrada AmazonEKSWorkerNodePolicy puede proporcionar este permiso, aunque también podemos crear una política personalizada más restrictiva.
Pod Identity Association
Es un recurso administrado mediante la API de EKS.
No se almacena como un objeto de Kubernetes y no aparece en el YAML de la ServiceAccount. Tampoco requiere anotaciones.
IAM Role
La trust policy utiliza el principal de servicio:
pods.eks.amazonaws.com
El rol debe permitir:
sts:AssumeRole
sts:TagSession
ServiceAccount
La ServiceAccount es una cuenta de Kubernetes normal:
apiVersion: v1
kind: ServiceAccount
metadata:
name: s3-reader-pod-identity
namespace: aws-access-demo
No contiene ninguna referencia al IAM Role.
Ventajas de EKS Pod Identity
Configuración más sencilla
No necesitamos crear ni administrar un proveedor OIDC por clúster.
Tampoco necesitamos construir complejas trust policies con el issuer OIDC, namespace y nombre de la ServiceAccount.
Separación de responsabilidades
El equipo de IAM puede crear roles que confíen en:
pods.eks.amazonaws.com
Posteriormente, el administrador de EKS puede crear las asociaciones sin modificar nuevamente la trust policy.
Esto facilita separar las responsabilidades entre los equipos que administran IAM y los equipos responsables de Kubernetes.
Reutilización de roles
El mismo IAM Role puede utilizarse en varios clústeres sin agregar el OIDC issuer de cada clúster a su trust policy.
Para reutilizarlo, solamente debemos crear una Pod Identity Association en cada clúster.
Mayor escalabilidad
Con IRSA, cada SDK intercambia directamente su token con AWS STS.
Con Pod Identity, el servicio de EKS realiza la asunción del rol y el agente distribuye las credenciales a los pods del nodo. Esto reduce las llamadas directas a STS realizadas por las aplicaciones y mejora la escalabilidad en entornos con una gran cantidad de workloads.
Session tags y ABAC
EKS Pod Identity agrega etiquetas a las sesiones temporales, incluyendo información como:
eks-cluster-name
eks-cluster-arn
kubernetes-namespace
kubernetes-service-account
kubernetes-pod-name
Estas etiquetas pueden utilizarse en políticas IAM para implementar control de acceso basado en atributos, conocido como ABAC.
Por ejemplo, podríamos permitir acceso a un recurso solamente cuando el namespace del pod coincida con una determinada etiqueta del recurso.
Recomendación actual de AWS
AWS recomienda utilizar EKS Pod Identity para entregar permisos de AWS a los pods siempre que la plataforma y el tipo de workload sean compatibles.
Desventajas y limitaciones de EKS Pod Identity
Requiere el agente
En clústeres EKS tradicionales debemos instalar el add-on eks-pod-identity-agent.
En EKS Auto Mode esta funcionalidad viene integrada y no es necesario instalarlo por separado.
Solamente está disponible en Amazon EKS
A diferencia de IRSA, Pod Identity depende directamente de la API de EKS.
No puede utilizarse en:
- EKS Anywhere.
- Clústeres Kubernetes autogestionados sobre EC2.
- Otros proveedores de Kubernetes.
No funciona con EKS Fargate
EKS Pod Identity solamente puede entregar credenciales a pods que se ejecutan en nodos Linux basados en Amazon EC2.
Actualmente no está disponible para:
- Pods Linux ejecutados en EKS Fargate.
- Pods Windows ejecutados en EKS Fargate.
- Pods ejecutados en nodos Windows EC2.
- AWS Outposts.
Para workloads sobre EKS Fargate, IRSA continúa siendo la alternativa apropiada.
El rol asociado debe pertenecer a la cuenta del clúster
La Pod Identity Association debe apuntar inicialmente a un IAM Role de la misma cuenta de AWS en la que se encuentra el clúster.
Para acceder a recursos de otra cuenta debemos utilizar role chaining: el rol de Pod Identity asume un segundo IAM Role en la cuenta destino.
Requiere versiones compatibles del AWS SDK
La aplicación debe utilizar una versión del AWS SDK que soporte el container credentials provider empleado por Pod Identity.
Por ejemplo, las versiones mínimas documentadas incluyen:
Boto3: 1.34.41
AWS SDK for Java v2: 2.21.30
AWS SDK for Java v1: 1.12.746
AWS SDK for Go v1: 1.47.11
Las aplicaciones nuevas normalmente ya utilizan versiones compatibles, pero debemos verificar workloads antiguos o imágenes que lleven mucho tiempo sin actualizarse.
Ejemplo práctico con EKS Pod Identity
Utilizaremos el mismo bucket y la misma política IAM del ejemplo anterior.
Definimos las variables:
export AWS_REGION="eu-west-2"
export CLUSTER_NAME="my-eks-cluster"
export NAMESPACE="aws-access-demo"
export BUCKET_NAME="my-eks-demo-bucket"
export POD_IDENTITY_SERVICE_ACCOUNT="s3-reader-pod-identity"
export POD_IDENTITY_ROLE_NAME="EksPodIdentityS3ReadRole"
export ACCOUNT_ID=$(aws sts get-caller-identity \
--query Account \
--output text)
export POLICY_ARN="arn:aws:iam::${ACCOUNT_ID}:policy/EksS3ReadOnlyDemoPolicy"
Paso 1: instalar el EKS Pod Identity Agent
Creamos el add-on:
aws eks create-addon \
--cluster-name "${CLUSTER_NAME}" \
--addon-name eks-pod-identity-agent \
--region "${AWS_REGION}"
Si el add-on ya existe, podemos actualizarlo:
aws eks update-addon \
--cluster-name "${CLUSTER_NAME}" \
--addon-name eks-pod-identity-agent \
--resolve-conflicts PRESERVE \
--region "${AWS_REGION}"
Validamos que el agente se encuentre ejecutándose:
kubectl get pods \
--namespace kube-system | grep eks-pod-identity-agent
Deberíamos tener una instancia del agente por cada nodo compatible.
Los nodos privados también deben poder comunicarse con la API EKS Auth. En clústeres sin salida a Internet puede ser necesario crear el endpoint de AWS PrivateLink correspondiente.
Paso 2: crear la ServiceAccount
kubectl create serviceaccount "${POD_IDENTITY_SERVICE_ACCOUNT}" \
--namespace "${NAMESPACE}"
En este caso no agregamos ninguna anotación:
kubectl get serviceaccount "${POD_IDENTITY_SERVICE_ACCOUNT}" \
--namespace "${NAMESPACE}" \
--output yaml
Paso 3: crear la trust policy
Creamos el archivo pod-identity-trust-policy.json:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
Esta trust policy no contiene:
- El nombre del clúster.
- El OIDC issuer.
- El namespace.
- El nombre de la
ServiceAccount.
La relación concreta entre estos elementos se configura en la Pod Identity Association.
En entornos productivos también conviene evaluar condiciones adicionales, como restricciones por organización o cuenta de origen, para reducir el riesgo de confused deputy.
Paso 4: crear el IAM Role
aws iam create-role \
--role-name "${POD_IDENTITY_ROLE_NAME}" \
--assume-role-policy-document file://pod-identity-trust-policy.json
Asociamos la política de acceso a S3:
aws iam attach-role-policy \
--role-name "${POD_IDENTITY_ROLE_NAME}" \
--policy-arn "${POLICY_ARN}"
Paso 5: crear la Pod Identity Association
aws eks create-pod-identity-association \
--cluster-name "${CLUSTER_NAME}" \
--namespace "${NAMESPACE}" \
--service-account "${POD_IDENTITY_SERVICE_ACCOUNT}" \
--role-arn "arn:aws:iam::${ACCOUNT_ID}:role/${POD_IDENTITY_ROLE_NAME}" \
--region "${AWS_REGION}"
La asociación relaciona:
Cluster: my-eks-cluster
Namespace: aws-access-demo
ServiceAccount: s3-reader-pod-identity
IAM Role: EksPodIdentityS3ReadRole
Podemos listar las asociaciones del clúster:
aws eks list-pod-identity-associations \
--cluster-name "${CLUSTER_NAME}" \
--region "${AWS_REGION}"
EKS soporta hasta 5000 Pod Identity Associations por clúster. Las asociaciones utilizan consistencia eventual, por lo que pueden tardar algunos segundos en estar disponibles después de crearlas o modificarlas.
Paso 6: crear el pod
Creamos el archivo pod-identity.yaml:
apiVersion: v1
kind: Pod
metadata:
name: s3-reader-pod-identity
namespace: aws-access-demo
spec:
serviceAccountName: s3-reader-pod-identity
restartPolicy: Never
containers:
- name: aws-cli
image: public.ecr.aws/aws-cli/aws-cli:latest
command:
- /bin/sh
- -c
args:
- |
echo "Identidad utilizada:"
aws sts get-caller-identity
echo "Objetos encontrados:"
aws s3 ls s3://REPLACE_BUCKET_NAME/
echo "Variables de Pod Identity:"
env | grep AWS_CONTAINER || true
Sustituimos el bucket:
sed -i "s/REPLACE_BUCKET_NAME/${BUCKET_NAME}/g" pod-identity.yaml
Creamos el pod:
kubectl apply -f pod-identity.yaml
Paso 7: validar el resultado
kubectl logs \
--namespace "${NAMESPACE}" \
s3-reader-pod-identity
La salida debería mostrar el IAM Role de Pod Identity:
{
"UserId": "AROAXXXXXXXXXXXXX:my-eks-cluster-aws-access-demo",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/EksPodIdentityS3ReadRole/my-eks-cluster-aws-access-demo"
}
También debería listar el archivo almacenado en S3.
En la sección de variables veremos valores similares a estos:
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials
Estas variables son inyectadas por EKS y permiten que el AWS SDK localice al Pod Identity Agent.
IRSA vs. EKS Pod Identity
| Característica | IRSA | EKS Pod Identity |
|---|---|---|
| Objetivo | Entregar permisos IAM a los pods | Entregar permisos IAM a los pods |
| Identidad de Kubernetes | ServiceAccount | ServiceAccount |
| OIDC Provider | Obligatorio por clúster | No es necesario |
| Anotación en ServiceAccount | Sí | No |
| Asociación | Anotación y trust policy IAM | Pod Identity Association en EKS |
| Operación STS | AssumeRoleWithWebIdentity |
AssumeRole, administrado mediante EKS Auth |
| Componente adicional | OIDC Provider | EKS Pod Identity Agent |
| Reutilización del IAM Role | Requiere modificar la trust policy por cada OIDC | Puede reutilizarse sin cambiar la trust policy |
| Session tags | No disponibles de la misma manera | Incluidas automáticamente |
| ABAC | Más limitado | Integración directa mediante session tags |
| EKS Fargate | Compatible | No compatible |
| Nodos Windows | Puede utilizarse según el entorno | No compatible |
| EKS Anywhere | Compatible | No compatible |
| Kubernetes autogestionado | Compatible | No compatible |
| Acceso directo cross-account | Posible mediante la configuración de confianza | El rol inicial debe estar en la cuenta del clúster |
| Escalabilidad de STS | Cada SDK llama a STS | EKS y el agente administran la obtención |
| Recomendación para nuevos workloads EKS sobre EC2 Linux | Válido | Alternativa recomendada por AWS |
Diferencias en las trust policies
Una de las diferencias más visibles se encuentra en la trust policy.
Trust policy de IRSA
{
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.eu-west-2.amazonaws.com/id/EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.eu-west-2.amazonaws.com/id/EXAMPLE:aud": "sts.amazonaws.com",
"oidc.eks.eu-west-2.amazonaws.com/id/EXAMPLE:sub": "system:serviceaccount:aws-access-demo:s3-reader-irsa"
}
}
}
La confianza está directamente vinculada con:
- Un proveedor OIDC.
- Un clúster.
- Un namespace.
- Una
ServiceAccount.
Trust policy de Pod Identity
{
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
La trust policy puede permanecer igual aunque utilicemos el rol en diferentes clústeres.
Las asociaciones específicas se administran desde EKS:
Cluster + Namespace + ServiceAccount + IAM Role
¿Cuál deberíamos utilizar?
No existe una respuesta única para todos los escenarios.
Utilizar EKS Pod Identity cuando
- Estamos creando nuevos workloads en Amazon EKS.
- Los pods se ejecutan en nodos Linux sobre EC2.
- Queremos reducir la administración de proveedores OIDC.
- Administramos muchos clústeres.
- Queremos reutilizar roles entre clústeres.
- Necesitamos session tags o políticas basadas en ABAC.
- Queremos separar la administración de IAM de la administración del clúster.
- Queremos reducir las llamadas directas a STS realizadas por las aplicaciones.
Para nuevos workloads compatibles, EKS Pod Identity debería ser normalmente la primera alternativa evaluada.
Utilizar IRSA cuando
- Los pods se ejecutan sobre EKS Fargate.
- Tenemos workloads sobre nodos Windows.
- Utilizamos EKS Anywhere.
- Utilizamos Kubernetes autogestionado sobre EC2.
- Necesitamos una solución que no dependa directamente de la API de EKS.
- Ya tenemos una implementación IRSA estable y no existe una necesidad clara de migración.
- Necesitamos determinados escenarios de acceso cross-account ya implementados directamente mediante OIDC.
IRSA continúa siendo una solución segura y completamente válida. AWS ha indicado que tanto IRSA como Pod Identity seguirán siendo mecanismos soportados.
¿Es necesario modificar el código de la aplicación?
Normalmente no.
Tanto IRSA como EKS Pod Identity funcionan con la cadena de credenciales predeterminada de los AWS SDK.
Una aplicación debe crear sus clientes sin incluir credenciales estáticas.
Ejemplo correcto con Python:
import boto3
s3 = boto3.client("s3")
response = s3.list_objects_v2(Bucket="my-eks-demo-bucket")
Ejemplo que debemos evitar:
import boto3
s3 = boto3.client(
"s3",
aws_access_key_id="ACCESS_KEY",
aws_secret_access_key="SECRET_KEY"
)
También debemos revisar que no existan variables como estas dentro del pod:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_SESSION_TOKEN
Los proveedores de credenciales tienen un orden de prioridad. Si la aplicación encuentra credenciales estáticas antes que las credenciales de IRSA o Pod Identity, utilizará las credenciales estáticas.
Consideraciones de seguridad
Aplicar mínimo privilegio
No debemos asociar políticas como:
AdministratorAccess
AmazonS3FullAccess
La política debe limitar:
- Las acciones permitidas.
- Los recursos permitidos.
- Las regiones, etiquetas o condiciones cuando sea posible.
Restringir el acceso a IMDS
Aunque utilicemos IRSA o Pod Identity, un pod podría intentar acceder al IAM Role del nodo si tiene acceso al Instance Metadata Service.
AWS recomienda restringir el acceso de los pods a IMDS para mejorar el aislamiento de credenciales. Los pods con hostNetwork: true siempre pueden alcanzar IMDS, aunque los AWS SDK compatibles priorizarán las credenciales de IRSA o Pod Identity cuando estén configuradas.
No considerar los contenedores como una frontera de seguridad
Los pods ejecutados en un mismo nodo comparten el kernel y otros recursos del sistema.
IRSA y Pod Identity mejoran el aislamiento de credenciales, pero no convierten los contenedores en una frontera de seguridad equivalente a una máquina virtual.
Utilizar una ServiceAccount por aplicación
Debemos evitar que múltiples aplicaciones sin relación compartan la misma ServiceAccount.
Una estructura más segura sería:
orders-api-sa
payments-api-sa
Cada cuenta debería tener su propio conjunto de permisos.
Revisar CloudTrail
Las llamadas a AWS deben supervisarse mediante CloudTrail.
Esto permite detectar:
- Accesos no esperados.
- Roles utilizados por aplicaciones incorrectas.
- Errores
AccessDenied. - Cambios en las asociaciones.
- Creación o eliminación de Pod Identity Associations.
Conclusiones
IRSA y EKS Pod Identity resuelven uno de los problemas más importantes de seguridad en Amazon EKS: permitir que los pods accedan a servicios de AWS sin utilizar credenciales estáticas ni heredar todos los permisos del nodo.
IRSA utiliza el estándar OIDC y la operación AssumeRoleWithWebIdentity. Es una solución madura, flexible y compatible con una mayor variedad de plataformas, incluyendo EKS Fargate y entornos Kubernetes que no dependen directamente de Amazon EKS.
EKS Pod Identity simplifica considerablemente la administración dentro de EKS. Elimina la necesidad de proveedores OIDC por clúster, permite reutilizar roles con mayor facilidad, agrega session tags y reduce las llamadas directas a STS realizadas por los workloads.
No es obligatorio migrar los workloads existentes que utilizan IRSA. Si la implementación actual funciona correctamente, aplica mínimo privilegio y está correctamente auditada, IRSA continúa siendo una solución válida.
Sin embargo, para nuevas implementaciones, yo recomendaría utilizar EKS Pod Identity, ya que ofrece una experiencia más sencilla y está alineada con la recomendación actual de AWS. En mi experiencia, la configuración de IRSA resulta un poco más compleja que la de EKS Pod Identity, algo que también hemos podido ver en los ejemplos de esta entrada.
¡Nos vemos en la próxima entrada!

