🎯

eks-irsa

🎯Skill

from adaptationio/skrillz

VibeIndex|
What it does

eks-irsa skill from adaptationio/skrillz

eks-irsa

Installation

Add MarketplaceAdd marketplace to Claude Code
/plugin marketplace add adaptationio/Skrillz
Install PluginInstall plugin from marketplace
/plugin install skrillz@adaptationio-Skrillz
Claude CodeAdd plugin in Claude Code
/plugin enable skrillz@adaptationio-Skrillz
Add MarketplaceAdd marketplace to Claude Code
/plugin marketplace add /path/to/skrillz
Install PluginInstall plugin from marketplace
/plugin install skrillz@local

+ 4 more commands

πŸ“– Extracted from docs: adaptationio/skrillz
1
-
Last UpdatedJan 16, 2026

Skill Details

SKILL.md

IAM Roles for Service Accounts (IRSA) for EKS pod-level AWS permissions. Use when configuring pod IAM access, setting up AWS service integrations, implementing least-privilege security, troubleshooting OIDC trust relationships, or deploying AWS controllers.

Overview

# EKS IAM Roles for Service Accounts (IRSA)

Overview

Comprehensive guide for implementing IAM Roles for Service Accounts (IRSA) in Amazon EKS. IRSA enables fine-grained IAM permissions at the pod level using OpenID Connect (OIDC) federation, eliminating the need for node-level IAM credentials and enabling least-privilege security.

Keywords: IRSA, IAM Roles for Service Accounts, EKS security, OIDC provider, pod IAM permissions, service account annotations, least privilege, AWS integration, trust policy, cross-account access

Status: Production-ready (2025 best practices)

When to Use This Skill

  • Setting up pod-level AWS permissions in EKS
  • Configuring AWS service integrations (S3, DynamoDB, Secrets Manager, SQS, SNS)
  • Installing EKS add-ons (AWS Load Balancer Controller, EBS CSI Driver, External DNS)
  • Implementing least-privilege security architecture
  • Troubleshooting OIDC trust relationship issues
  • Cross-account IAM role assumption from EKS
  • Migrating from node IAM roles to pod-level permissions
  • Blue/green cluster upgrades with IRSA

What is IRSA?

IAM Roles for Service Accounts (IRSA) allows Kubernetes workloads to assume IAM roles securely without relying on node-level credentials.

How IRSA Works

```

  1. Pod starts with annotated ServiceAccount
  2. EKS mutating webhook injects AWS_WEB_IDENTITY_TOKEN_FILE
  3. AWS SDK reads JWT token from injected file
  4. SDK calls STS::AssumeRoleWithWebIdentity
  5. OIDC provider validates token against trust policy
  6. Temporary credentials issued (automatically rotated)
  7. Pod uses scoped IAM permissions

```

Key Benefits

Security:

  • Pod-level permissions (not node-level)
  • Prevents privilege escalation
  • Automatic credential rotation
  • No long-lived credentials

Compliance:

  • Least-privilege principle
  • Audit trail via CloudTrail
  • Compliance requirements met
  • Fine-grained access control

Operational:

  • Each app gets own IAM role
  • Modify permissions without node changes
  • Better resource isolation
  • Supports multi-tenancy

Quick Start

Prerequisites

  1. OIDC Provider Enabled (automatic with terraform-aws-modules/eks)
  2. IAM Role Created with trust policy for OIDC
  3. ServiceAccount Annotated with role ARN
  4. Pod Configured to use ServiceAccount

30-Second Setup (Terraform)

```hcl

# 1. Enable IRSA in EKS module (automatic OIDC setup)

module "eks" {

source = "terraform-aws-modules/eks/aws"

version = "~> 20.0"

cluster_name = "production"

enable_irsa = true # Creates OIDC provider automatically

}

# 2. Create IAM role for S3 access

module "s3_access_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

version = "~> 5.0"

role_name = "my-app-s3-access"

role_policy_arns = {

s3_read = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"

}

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["production:my-app-sa"]

}

}

}

# 3. Create Kubernetes ServiceAccount

resource "kubernetes_service_account" "my_app" {

metadata {

name = "my-app-sa"

namespace = "production"

annotations = {

"eks.amazonaws.com/role-arn" = module.s3_access_irsa.iam_role_arn

}

}

}

# 4. Use ServiceAccount in pod

resource "kubernetes_deployment" "my_app" {

spec {

template {

spec {

service_account_name = "my-app-sa" # βœ… IRSA enabled!

containers {

name = "app"

image = "my-app:latest"

# AWS SDK automatically uses IRSA credentials

}

}

}

}

}

```

Verify IRSA Setup

```bash

# Check OIDC provider exists

aws iam list-open-id-connect-providers

# Verify IAM role trust policy

aws iam get-role --role-name my-app-s3-access

# Test from pod

kubectl exec -it my-pod -- env | grep AWS

# Should show:

# AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

# AWS_ROLE_ARN=arn:aws:iam::123456789012:role/my-app-s3-access

# Test AWS access

kubectl exec -it my-pod -- aws s3 ls

```

Common IRSA Patterns

1. AWS Load Balancer Controller

What it needs: Create/manage ALBs and NLBs

```hcl

module "lb_controller_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "aws-load-balancer-controller"

attach_load_balancer_controller_policy = true # Pre-built policy!

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]

}

}

}

```

2. EBS CSI Driver

What it needs: Create/attach/delete EBS volumes

```hcl

module "ebs_csi_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "ebs-csi-controller"

attach_ebs_csi_policy = true # Pre-built policy!

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]

}

}

}

```

3. External DNS

What it needs: Manage Route53 records

```hcl

module "external_dns_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "external-dns"

attach_external_dns_policy = true # Pre-built policy!

external_dns_hosted_zone_arns = ["arn:aws:route53:::hostedzone/Z123456789"]

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["kube-system:external-dns"]

}

}

}

```

4. Cluster Autoscaler

What it needs: Modify Auto Scaling Groups

```hcl

module "cluster_autoscaler_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "cluster-autoscaler"

attach_cluster_autoscaler_policy = true # Pre-built policy!

cluster_autoscaler_cluster_names = [module.eks.cluster_name]

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["kube-system:cluster-autoscaler"]

}

}

}

```

5. Karpenter (Recommended Autoscaler)

What it needs: Provision EC2 instances, manage instance profiles

```hcl

module "karpenter" {

source = "terraform-aws-modules/eks/aws//modules/karpenter"

cluster_name = module.eks.cluster_name

irsa_oidc_provider_arn = module.eks.oidc_provider_arn

# Includes pre-configured IRSA role!

}

```

6. External Secrets Operator

What it needs: Read secrets from AWS Secrets Manager

```hcl

module "external_secrets_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "external-secrets"

attach_external_secrets_policy = true # Pre-built policy!

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["kube-system:external-secrets"]

}

}

}

```

7. Custom Application (S3 + DynamoDB)

```hcl

module "app_irsa" {

source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"

role_name = "my-app"

role_policy_arns = {

s3 = aws_iam_policy.app_s3_policy.arn

dynamodb = aws_iam_policy.app_dynamodb_policy.arn

}

oidc_providers = {

main = {

provider_arn = module.eks.oidc_provider_arn

namespace_service_accounts = ["production:my-app-sa"]

}

}

}

# Custom policies with least privilege

resource "aws_iam_policy" "app_s3_policy" {

name = "my-app-s3-access"

policy = jsonencode({

Version = "2012-10-17"

Statement = [

{

Effect = "Allow"

Action = [

"s3:GetObject",

"s3:PutObject"

]

Resource = "arn:aws:s3:::my-bucket/my-app/*"

}

]

})

}

```

Application Code Examples

Python (Boto3)

```python

import boto3

# AWS SDK automatically detects IRSA credentials

# No configuration needed!

s3 = boto3.client('s3')

response = s3.list_buckets()

print(response['Buckets'])

# The SDK:

# 1. Reads AWS_WEB_IDENTITY_TOKEN_FILE env var

# 2. Reads AWS_ROLE_ARN env var

# 3. Calls STS::AssumeRoleWithWebIdentity

# 4. Uses temporary credentials automatically

```

Node.js (AWS SDK v3)

```javascript

import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";

// AWS SDK automatically detects IRSA credentials

const s3Client = new S3Client({ region: "us-east-1" });

const response = await s3Client.send(new ListBucketsCommand({}));

console.log(response.Buckets);

```

Go (AWS SDK v2)

```go

import (

"context"

"github.com/aws/aws-sdk-go-v2/config"

"github.com/aws/aws-sdk-go-v2/service/s3"

)

func main() {

// AWS SDK automatically detects IRSA credentials

cfg, _ := config.LoadDefaultConfig(context.TODO())

client := s3.NewFromConfig(cfg)

resp, _ := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})

fmt.Println(resp.Buckets)

}

```

Detailed Documentation

For in-depth guides on specific IRSA topics:

  • OIDC Setup: [references/oidc-setup.md](references/oidc-setup.md)

- OIDC provider configuration

- Trust relationship anatomy

- Thumbprint calculation

- Blue/green cluster upgrades

  • Role Creation: [references/role-creation.md](references/role-creation.md)

- IAM role patterns for common services

- Custom policy examples

- Session tags for ABAC

- Cross-account access

  • Pod Configuration: [references/pod-configuration.md](references/pod-configuration.md)

- ServiceAccount annotations

- Pod specifications

- Environment variables

- Troubleshooting

Security Best Practices

1. Use Dedicated Service Accounts

```yaml

# ❌ BAD: Sharing service account

apiVersion: v1

kind: ServiceAccount

metadata:

name: shared-sa # Used by multiple apps

annotations:

eks.amazonaws.com/role-arn: arn:aws:iam::123:role/shared-role

# βœ… GOOD: One service account per app

apiVersion: v1

kind: ServiceAccount

metadata:

name: payment-service-sa

annotations:

eks.amazonaws.com/role-arn: arn:aws:iam::123:role/payment-service

---

apiVersion: v1

kind: ServiceAccount

metadata:

name: email-service-sa

annotations:

eks.amazonaws.com/role-arn: arn:aws:iam::123:role/email-service

```

2. Restrict IMDS Access

```hcl

# Prevent pods from accessing node IAM credentials

module "eks" {

source = "terraform-aws-modules/eks/aws"

eks_managed_node_groups = {

main = {

# Require IMDSv2 (prevents container escape to node credentials)

metadata_options = {

http_endpoint = "enabled"

http_tokens = "required" # IMDSv2 only

http_put_response_hop_limit = 1

}

}

}

}

```

3. Least Privilege Policies

```json

{

"Version": "2012-10-17",

"Statement": [

{

"Effect": "Allow",

"Action": [

"s3:GetObject",

"s3:PutObject"

],

"Resource": "arn:aws:s3:::my-bucket/my-app/*",

"Condition": {

"StringEquals": {

"aws:PrincipalAccount": "123456789012"

}

}

}

]

}

```

4. Regular Auditing

```bash

# Find all IRSA roles

aws iam list-roles --query 'Roles[?contains(AssumeRolePolicyDocument.Statement[0].Principal.Federated, oidc-provider)]'

# Check CloudTrail for AssumeRoleWithWebIdentity calls

aws cloudtrail lookup-events \

--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \

--max-results 50

```

Troubleshooting Quick Reference

| Issue | Cause | Fix |

|-------|-------|-----|

| AccessDenied | Missing IAM permissions | Check role policy allows action |

| AssumeRoleWithWebIdentity failed | Trust policy mismatch | Verify OIDC provider ARN matches cluster |

| InvalidIdentityToken | Wrong namespace/SA in trust | Check StringEquals condition |

| Pod can't assume role | ServiceAccount not annotated | Add eks.amazonaws.com/role-arn annotation |

| Using node credentials | Pod not using ServiceAccount | Set serviceAccountName in pod spec |

| OIDC provider not found | IRSA not enabled | Set enable_irsa = true in EKS module |

eksctl Quick Setup

```bash

# Create cluster with OIDC enabled

eksctl create cluster \

--name production \

--region us-east-1 \

--with-oidc

# Create IRSA role + ServiceAccount in one command

eksctl create iamserviceaccount \

--name my-app-sa \

--namespace production \

--cluster production \

--attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \

--approve

# Verify

kubectl get sa my-app-sa -n production -o yaml

```

Blue/Green Cluster Upgrades

Problem: IRSA trust policies include cluster OIDC endpoint

Solution: Update trust policies during upgrade

```hcl

# Support both blue and green clusters temporarily

resource "aws_iam_role" "app" {

assume_role_policy = jsonencode({

Version = "2012-10-17"

Statement = [

{

Effect = "Allow"

Principal = {

Federated = [

module.eks_blue.oidc_provider_arn, # Old cluster

module.eks_green.oidc_provider_arn # New cluster

]

}

Action = "sts:AssumeRoleWithWebIdentity"

Condition = {

StringEquals = {

"${module.eks_blue.oidc_provider}:sub" = "system:serviceaccount:prod:app-sa"

"${module.eks_green.oidc_provider}:sub" = "system:serviceaccount:prod:app-sa"

}

}

}

]

})

}

```

EKS Pod Identity (New Alternative)

Note: EKS Pod Identity is the new simplified alternative to IRSA (GA 2024).

Differences:

  • No OIDC provider needed
  • Simpler trust policies
  • Managed by AWS entirely
  • Recommended for new deployments

IRSA vs Pod Identity:

  • IRSA: Proven, mature, widely used (2019+)
  • Pod Identity: Simpler, newer, AWS-managed (2024+)
  • Both work, Pod Identity is easier for new clusters

Migration Path: Keep IRSA for existing clusters, use Pod Identity for new ones.

---

Version: 2025 Best Practices

Terraform Module: terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks

Status: Production-ready

Last Updated: November 2025