How to Setup Amazon EBS CSI Driver on EKS with KMS Encryption Using OIDC and Deploy a Sample Application


Introduction
Amazon Elastic Block Store (EBS) Container Storage Interface (CSI) driver enables Kubernetes clusters on Amazon EKS to dynamically provision and manage persistent block storage backed by Amazon EBS volumes. This guide will help you:
Enable OIDC provider for IAM roles in EKS
Create IAM roles with KMS permissions for encrypted EBS volumes
Install and configure the Amazon EBS CSI driver
Create encrypted StorageClass with a custom KMS key
Deploy a PersistentVolumeClaim (PVC) and a Pod using the encrypted EBS volume
Understand Pod and PVC lifecycle impacts on data and volumes
Prerequisites
An existing Amazon EKS cluster (Kubernetes 1.15+)
AWS CLI and kubectl installed and configured
eksctl installed (optional but recommended)
An AWS KMS key created for EBS encryption
Step 1: Enable OIDC Provider for Your EKS Cluster
Amazon EKS uses IAM Roles for Service Accounts (IRSA) to provide fine-grained permissions to pods. First, enable OIDC identity provider for your cluster:
eksctl utils associate-iam-oidc-provider \
--region <your-region> \
--cluster <your-cluster-name> \
--approve
Retrieve your OIDC provider URL for creating IAM trust relationships:
aws eks describe-cluster \
--name <your-cluster-name> \
--query "cluster.identity.oidc.issuer" \
--output text
Step 2: Create IAM Role for EBS CSI Driver with KMS Permissions
2.1 Create Trust Policy (replace placeholders)
Create a file trust-policy.json
:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<oidc-id>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<oidc-id>:aud": "sts.amazonaws.com",
"oidc.eks.<region>.amazonaws.com/id/<oidc-id>:sub": "system:serviceaccount:kube-system:ebs-csi-controller-sa"
}
}
}
]
}
2.2 Create the role
aws iam create-role \
--role-name AmazonEKS_EBS_CSI_DriverRole \
--assume-role-policy-document file://trust-policy.json
2.3 Attach managed policy
aws iam attach-role-policy \
--role-name AmazonEKS_EBS_CSI_DriverRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
2.4 Create custom KMS policy for encryption
Create kms-policy.json
(replace with your KMS ARN):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": ["arn:aws:kms:<region>:<account-id>:key/<key-id>"],
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
},
{
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": ["arn:aws:kms:<region>:<account-id>:key/<key-id>"]
}
]
}
Create and attach policy:
aws iam create-policy \
--policy-name KMS_EBS_Encryption_Policy \
--policy-document file://kms-policy.json
aws iam attach-role-policy \
--role-name AmazonEKS_EBS_CSI_DriverRole \
--policy-arn arn:aws:iam::<account-id>:policy/KMS_EBS_Encryption_Policy
Step 3: Install Amazon EBS CSI Driver Add-on on EKS
Install using AWS EKS add-ons for simplicity and automatic updates:
aws eks create-addon \
--cluster-name <your-cluster-name> \
--addon-name aws-ebs-csi-driver \
--service-account-role-arn arn:aws:iam::<account-id>:role/AmazonEKS_EBS_CSI_DriverRole \
--region <your-region>
Step 4: Create Encrypted StorageClass with KMS Key
Create a file storageclass.yaml
:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-csi-encrypted
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
parameters:
type: gp3
fstype: ext4
encrypted: "true"
kmsKeyId: arn:aws:kms:<region>:<account-id>:key/<key-id>
WaitForFirstConsumer
delays volume creation until pod scheduling to ensure AZ affinity.reclaimPolicy: Delete
means volume is deleted when PVC is deleted (change toRetain
to keep volume).kmsKeyId
uses your custom KMS key for encryption.
Apply it:
kubectl apply -f storageclass.yaml
Step 5: Create PersistentVolumeClaim
Create pvc.yaml
:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-csi-encrypted
resources:
requests:
storage: 2Gi
Apply:
kubectl apply -f pvc.yaml
Step 6: Deploy Sample Pod Using PVC
Create pod.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: ebs-app
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: ebs-storage
mountPath: /usr/share/nginx/html
volumes:
- name: ebs-storage
persistentVolumeClaim:
claimName: ebs-claim
Apply:
kubectl apply -f pod.yaml
Step 7: Verify Setup
- Check pod status:
kubectl get pods ebs-app
kubectl describe pod ebs-app
- Verify PVC bound to a PV:
kubectl get pvc ebs-claim
kubectl describe pvc ebs-claim
- Check PV and confirm encryption and KMS key from AWS Console or CLI:
aws ec2 describe-volumes --volume-ids <volume-id-from-pv>
What Happens When You Delete a Pod?
Pod terminates; volume is detached but PVC and EBS volume remain intact.
Data remains persistent on the encrypted EBS volume.
You can recreate a pod using the same PVC and access your data.
What Happens When You Delete a PVC?
Since
reclaimPolicy
isDelete
, the EBS volume is deleted, and all data is lost.Pod using this PVC will go into an error state due to missing volume.
If you want to keep data, set reclaimPolicy to
Retain
, then manually manage the volume.
Conclusion
This guide walked you through securely provisioning encrypted EBS volumes in EKS with OIDC and IAM Roles for Service Accounts. Using custom KMS keys ensures data-at-rest encryption under your control. Pods can dynamically consume encrypted storage with data persistence across restarts, and you control lifecycle behavior with StorageClass reclaim policies.
Subscribe to my newsletter
Read articles from Navya A directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Navya A
Navya A
๐ Welcome to my Hashnode profile! I'm a passionate technologist with expertise in AWS, DevOps, Kubernetes, Terraform, Datree, and various cloud technologies. Here's a glimpse into what I bring to the table: ๐ Cloud Aficionado: I thrive in the world of cloud technologies, particularly AWS. From architecting scalable infrastructure to optimizing cost efficiency, I love diving deep into the AWS ecosystem and crafting robust solutions. ๐ DevOps Champion: As a DevOps enthusiast, I embrace the culture of collaboration and continuous improvement. I specialize in streamlining development workflows, implementing CI/CD pipelines, and automating infrastructure deployment using modern tools like Kubernetes. โต Kubernetes Navigator: Navigating the seas of containerization is my forte. With a solid grasp on Kubernetes, I orchestrate containerized applications, manage deployments, and ensure seamless scalability while maximizing resource utilization. ๐๏ธ Terraform Magician: Building infrastructure as code is where I excel. With Terraform, I conjure up infrastructure blueprints, define infrastructure-as-code, and provision resources across multiple cloud platforms, ensuring consistent and reproducible deployments. ๐ณ Datree Guardian: In my quest for secure and compliant code, I leverage Datree to enforce best practices and prevent misconfigurations. I'm passionate about maintaining code quality, security, and reliability in every project I undertake. ๐ Cloud Explorer: The ever-evolving cloud landscape fascinates me, and I'm constantly exploring new technologies and trends. From serverless architectures to big data analytics, I'm eager to stay ahead of the curve and help you harness the full potential of the cloud. Whether you need assistance in designing scalable architectures, optimizing your infrastructure, or enhancing your DevOps practices, I'm here to collaborate and share my knowledge. Let's embark on a journey together, where we leverage cutting-edge technologies to build robust and efficient solutions in the cloud! ๐๐ป