AWS EKS Security Hardening: IRSA, Control Plane Logging, and Node Security

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
EKS security is a different problem from generic Kubernetes security. The AWS-specific attack surface -- node IAM instance profiles, the aws-auth ConfigMap, IMDS credential theft, and the absence of control plane audit logs -- is what attackers exploit after a container escape. Generic K8s hardening guides tell you to run pods as non-root and enable RBAC; EKS-specific hardening tells you how IAM mistakes let those controls be bypassed entirely. This guide covers the four highest-impact EKS security controls: IRSA to eliminate node instance profile blast radius, aws-auth lockdown to prevent IAM-to-cluster-admin escalation, control plane logging for forensic investigation, and IMDSv2 enforcement to block SSRF-based credential theft.
Replace Node Instance Profiles with IRSA
The single highest-impact EKS security change is moving pod permissions from node instance profiles to IRSA. Every minute a node has IAM permissions, every pod on it can use them.
Create an OIDC provider for the cluster
Retrieve your cluster's OIDC issuer URL: `aws eks describe-cluster --name <cluster-name> --query 'cluster.identity.oidc.issuer'`. Create an IAM OIDC identity provider for this URL: `eksctl utils associate-iam-oidc-provider --cluster <cluster-name> --approve`. This one-time setup enables IRSA for all service accounts in the cluster.
Create IAM roles with service account trust conditions
For each application that needs AWS access, create a minimal IAM role with a trust policy allowing the specific service account: the condition should match `oidc.eks.<region>.amazonaws.com/id/<oidc-id>:sub` equals `system:serviceaccount:<namespace>:<service-account-name>`. Attach only the IAM policies that application needs -- S3 read for a specific bucket, not S3FullAccess.
Annotate service accounts with the role ARN
Add the IRSA annotation to the Kubernetes service account: `kubectl annotate serviceaccount <sa-name> -n <namespace> eks.amazonaws.com/role-arn=arn:aws:iam::<account>:role/<role-name>`. The EKS Pod Identity Webhook (running in kube-system) intercepts pod creation, detects this annotation, and injects the AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE environment variables automatically.
Remove permissions from the node instance profile
Once all pods use IRSA, audit the node instance profile and remove all policies except those required for the node itself: AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, and AmazonEC2ContainerRegistryReadOnly. Remove S3, DynamoDB, SQS, and any other application-level policies. A container escape on an IRSA-only cluster yields empty credentials on the node instance profile.
Lock Down the aws-auth ConfigMap
The aws-auth ConfigMap is the most commonly misconfigured EKS security control. An overly permissive entry here maps any principal with the listed IAM role to cluster-admin.
Audit current aws-auth mappings
Run `kubectl get configmap aws-auth -n kube-system -o yaml` and review every `rolearn` and `userarn` entry. For each entry, verify: the IAM role or user actually needs cluster access, the groups mapping (system:masters grants full cluster-admin), and whether the entry is still needed. Remove any entries for decommissioned roles, contractor accounts, or automation that has been replaced.
Restrict write access to aws-auth
Create a Kubernetes RBAC policy that denies modifications to the aws-auth ConfigMap for all but the cluster administrator service account. Use OPA Gatekeeper or Kyverno to enforce: deny any request that creates or updates the aws-auth ConfigMap unless the requesting user is in a specific allow-list. This prevents a developer with kubectl access from escalating to cluster-admin by adding their IAM user to aws-auth.
Migrate to EKS Access Entries
AWS released EKS Access Entries in 2024 as a replacement for the aws-auth ConfigMap. Access Entries are managed via the EKS API (not a ConfigMap), making them auditable in CloudTrail and manageable via Terraform. Migrate by enabling the `API_AND_CONFIG_MAP` or `API` authentication mode on the cluster and creating Access Entries via `aws eks create-access-entry`. Access Entries support IAM Identity Center integration for human access and eliminate the brittle YAML-editing workflow.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Enable All Control Plane Log Types
EKS control plane logs are the forensic foundation for cluster incident investigations. Without audit logs, determining what an attacker did after compromising cluster credentials is impossible.
Enable all five log types
Enable control plane logging via the AWS CLI: `aws eks update-cluster-config --name <cluster-name> --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}'`. Logs stream to a CloudWatch Log Group named `/aws/eks/<cluster-name>/cluster`. Enable this on every cluster, including development -- attackers target dev clusters because they often have the same IAM roles as production.
Set appropriate log retention
CloudWatch Log Groups default to never expiring. Set retention to 90 days for cost management: `aws logs put-retention-policy --log-group-name /aws/eks/<cluster-name>/cluster --retention-in-days 90`. Export to S3 for long-term retention if your compliance requirements exceed 90 days. Use CloudWatch Log Insights to query audit logs for suspicious patterns: `fields @timestamp, @message | filter @logStream like 'kube-apiserver-audit' | filter objectRef.name='aws-auth'`.
Export audit logs to your SIEM
Create a CloudWatch subscription filter on the audit log stream that forwards to a Kinesis Data Firehose delivery stream pointing to S3 or directly to your SIEM. Key audit events to alert on: any modification to the aws-auth ConfigMap, ClusterRoleBinding creation granting system:masters, creation of pods in kube-system namespace, and exec commands into running pods (`verb=create resourceType=pods/exec`).
Harden Managed Node Groups
Node hardening in EKS focuses on three controls: IMDSv2 enforcement, Bottlerocket OS selection, and minimizing the node's network and IAM attack surface.
Enforce IMDSv2 via launch template
Create or update the EC2 launch template for your node group with `MetadataOptions: {HttpTokens: required, HttpPutResponseHopLimit: 1}`. The hop limit of 1 prevents container processes from reaching the IMDS endpoint via the container network namespace, blocking SSRF-based credential theft. Apply this change by creating a new node group version and rolling the nodes.
Use Bottlerocket for security-sensitive node groups
Set the AMI type in your node group to `BOTTLEROCKET_x86_64` or `BOTTLEROCKET_ARM_64`. Bottlerocket runs all workloads in containers with a minimal host OS, enforces SELinux on all processes, has a read-only root filesystem, and updates atomically. Disable direct SSH access to Bottlerocket nodes -- use SSM Session Manager for break-glass access instead.
Block node-to-IMDS access for non-privileged pods
Apply a Kubernetes NetworkPolicy or an AWS VPC security group rule (using security groups for pods) that blocks outbound TCP port 80 to 169.254.169.254 from application pod security groups. This adds a defense-in-depth layer on top of IMDSv2's hop limit restriction. Privileged infrastructure pods (monitoring agents, CNI) that legitimately need IMDS access can be exempted by pod label selector.
The bottom line
EKS security has four controls that matter more than everything else combined: IRSA to eliminate node credential blast radius, aws-auth lockdown to prevent IAM-to-cluster-admin escalation, control plane audit logging to enable forensic investigation, and IMDSv2 enforcement to block SSRF credential theft. Get these four right before spending time on anything else in the EKS security stack.
Frequently asked questions
What is IRSA and why is it better than node instance profiles for pod permissions?
IRSA (IAM Roles for Service Accounts) uses OIDC federation to let individual Kubernetes service accounts assume specific IAM roles. With a node instance profile, every pod on that node inherits the full IAM permissions of the EC2 instance -- a container escape gives the attacker all those permissions. With IRSA, each pod's service account maps to a minimal IAM role with only the permissions that pod needs. A container escape only yields the permissions of that pod's role, not the entire node's permissions.
How do you lock down the aws-auth ConfigMap?
The aws-auth ConfigMap in the kube-system namespace maps IAM roles and users to Kubernetes RBAC groups. Restrict write access to this ConfigMap to only the cluster administrator role via a Kubernetes RBAC RoleBinding -- no application team should be able to modify it. Audit it regularly: `kubectl get configmap aws-auth -n kube-system -o yaml`. Remove any `rolearn` entries that map to overly broad IAM roles (like roles with AdministratorAccess). Use EKS Access Entries (the newer API-based approach) instead of the ConfigMap to avoid the ConfigMap's manual management risks.
Which EKS control plane log types should you always enable?
Enable all five: API server (all API calls), audit (who did what, the primary forensic log), authenticator (IAM-to-RBAC token validation), controller manager (workload lifecycle events), and scheduler (pod placement decisions). The audit log is the most important -- it shows every kubectl command and API call made to the cluster. API server and authenticator logs are needed to correlate IAM authentication attempts with Kubernetes API access. Control plane logs stream to CloudWatch Log Groups and cost roughly $0.50/GB -- for most clusters this is $5-20/month.
How do you enforce IMDSv2 on EKS managed node groups?
Set `httpPutResponseHopLimit: 1` and `httpTokens: required` in the EC2 launch template associated with your EKS managed node group. With hop limit 1, the IMDSv2 token request cannot traverse container network namespaces, so a container cannot reach the node IMDS endpoint unless it has host network access. For Bottlerocket nodes, set `metadata-service.authentication = required` in the Bottlerocket node config. Verify enforcement with a test pod: `curl -s http://169.254.169.254/latest/meta-data/` should return 401 without a session token.
What is EKS Pod Identity and how does it differ from IRSA?
EKS Pod Identity is a newer AWS feature (released late 2023) that provides pod-level IAM role assignment without requiring OIDC provider setup. With IRSA, you must create an OIDC identity provider, annotate the service account, and configure trust policy conditions on the IAM role. EKS Pod Identity simplifies this: install the EKS Pod Identity Agent add-on, create a Pod Identity Association in the EKS console or CLI mapping a namespace/service-account to an IAM role, and it works. EKS Pod Identity uses a dedicated IMDS-like endpoint and does not require OIDC configuration. It is the recommended approach for new EKS deployments.
How do you secure EKS add-ons like VPC CNI and CoreDNS?
Pin all EKS add-ons to specific versions rather than using 'latest' -- add-on version updates can introduce breaking changes or configuration resets. Manage add-ons via Terraform or eksctl rather than the AWS console to track versions in code. For VPC CNI, enable network policy support (requires VPC CNI v1.14+) and apply default-deny Kubernetes NetworkPolicies to prevent unrestricted pod-to-pod traffic. For CoreDNS, restrict external DNS queries by configuring the Corefile to forward only to AWS DNS (169.254.169.253) and audit DNS query logs for exfiltration patterns.
Should you use Bottlerocket or Amazon Linux 2 for EKS nodes?
Bottlerocket is the more secure choice for new deployments. It has a minimal attack surface (no package manager, no shell in the default image), immutable root filesystem, automatic atomic updates, and is purpose-built for container workloads. The API-based management model (no SSH by default) means administrative access requires either the Bottlerocket admin container or SSM Session Manager, both of which are fully auditable. Amazon Linux 2 is familiar and has broader tooling compatibility but carries a larger attack surface. For security-sensitive workloads, Bottlerocket's SELinux enforcement and read-only root filesystem are meaningful defense-in-depth controls.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
