InfraSec Lab – Securing AWS EKS with IRSA

Practical Kubernetes & Cloud Security Architecture

⬅ Back to main site

Project Information

Type: Cloud Security / Kubernetes Security / Infrastructure as Code

Stack: AWS EKS, IAM, IRSA, Fargate, Terraform, Kubernetes RBAC

Project Summary

InfraSec Lab is a hands-on security laboratory designed to demonstrate how to secure Kubernetes workloads on AWS EKS using IAM Roles for Service Accounts (IRSA).

The project focuses on eliminating static credentials, enforcing least-privilege access, and isolating application permissions at the pod level using AWS IAM and Kubernetes ServiceAccounts.

Security Challenges

Architecture & Solution

Each Kubernetes workload runs in its own namespace and uses a dedicated ServiceAccount linked to a specific IAM Role via IRSA. This allows pods to authenticate to AWS securely using short-lived tokens.

Pods run on AWS Fargate inside private subnets and access the internet through a NAT Gateway when required (image pull, external APIs).

EKS IRSA Security Architecture Diagram

IAM Policies – Least Privilege Design

To secure pod-to-AWS communication, this project applies the principle of least privilege using IAM policies attached to Kubernetes ServiceAccounts via IRSA (IAM Roles for Service Accounts).

External Secrets Operator

Allows secure read-only access to AWS Secrets Manager and SSM Parameter Store.


############################
# IAM Policies (Least Privilege)
############################

# External Secrets Operator
resource "aws_iam_policy" "external_secrets" {
  name = "eks-external-secrets-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Action = [
        "secretsmanager:GetSecretValue",
        "ssm:GetParameter",
        "ssm:GetParameters"
      ]
      Resource = "*"
    }]
  })
}
  

Application Backend

Backend pods can only read and write to specific DynamoDB tables and send messages to authorized SQS queues.


# Backend applicatif
resource "aws_iam_policy" "app_backend" {
  name = "eks-app-backend-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "dynamodb:GetItem",
          "dynamodb:PutItem"
        ]
        Resource = "arn:aws:dynamodb:us-east-1:*:table/app-*"
      },
      {
        Effect = "Allow"
        Action = ["sqs:SendMessage"]
        Resource = "arn:aws:sqs:us-east-1:*:app-*"
      }
    ]
  })
}
  

Log Collector

Log collection pods can only push logs to a dedicated S3 bucket and Firehose delivery stream.


# Log collector
resource "aws_iam_policy" "log_collector" {
  name = "eks-log-collector-policy"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["s3:PutObject"]
        Resource = "arn:aws:s3:::eks-logs-bucket/*"
      },
      {
        Effect = "Allow"
        Action = ["firehose:PutRecord"]
        Resource = "*"
      }
    ]
  })
}
  

Each policy is attached to a dedicated IAM role and mapped to a Kubernetes ServiceAccount, ensuring strict workload isolation and preventing lateral privilege escalation.

EKS IRSA Security Architecture Diagram

Kubernetes ServiceAccounts & IRSA

In this architecture, each Kubernetes workload uses a dedicated ServiceAccount mapped to an AWS IAM role. This mechanism is called IRSA (IAM Roles for Service Accounts) and allows pods to authenticate securely to AWS without static credentials.

ServiceAccount to IAM Role Mapping

The annotation eks.amazonaws.com/role-arn tells EKS which IAM role a pod should assume when it runs using this ServiceAccount.


############################
# ServiceAccounts Kubernetes (IRSA)
############################

resource "kubernetes_service_account" "sa" {
  for_each = local.pod_roles

  metadata {
    name      = "${each.key}-sa"
    namespace = each.value.namespace

    annotations = {
      "eks.amazonaws.com/role-arn" = aws_iam_role.pod_role[each.key].arn
    }
  }
}
  

How Authentication Works

  1. The pod starts using its assigned ServiceAccount
  2. EKS injects a projected OIDC token into the pod
  3. AWS STS validates the token against the EKS OIDC provider
  4. STS returns temporary credentials for the mapped IAM role
  5. The AWS SDK automatically refreshes credentials when needed
EKS IRSA Security Architecture Diagram

Security Testing & Validation ( with App service account )

Authorized Actions

Unauthorized Actions (Expected Failures)

IRSA Authorization Tests

Security Benefits

GitHub Repository

👉 View the project on GitHub