Files
site/content/blog/amazon-ebs-csi-driver-terraform/index.md
2024-07-27 07:43:08 -04:00

3.4 KiB

title, date, draft, comments, toc, author, tags
title date draft comments toc author tags
Amazon EBS CSI driver with terraform 2024-04-07T15:20:23-04:00 false true false Dave Gallant
aws
eks
ebs
aws-ebs-csi-driver
oidc
efs
aws-efs-csi-driver

I recently configured the Amazon EBS CSI driver and found the setup with terraform to be more effort than expected. I wanted to avoid third-party modules and keep it as simple as possible, while remaining least privilege.

UPDATE: This approach can also be used for the aws-efs-csi-driver

The Amazon EBS CSI driver docs mention that the following are needed:

  • an existing EKS cluster
  • IAM role (that allows communication to the EC2 API)
  • EKS add-on (aws-ebs-csi-driver)
  • OIDC provider

This sounded simple enough but I was unable to find a "grab-and-go" terraform example that followed the recommendations in the docs. I saw some suggestions about attaching an AmazonEBSCSIDriverPolicy policy to the node groups but did not think this was the best idea since this would allow many pods to potentially have access to the EC2 API.

After a few minutes of LLM prompting, I was unimpressed with the results. I began to piece together the config myself, and after some trial and error, this is the terraform that I came up with:


# TLS needed for the thumbprint
provider "tls" {}

data "tls_certificate" "oidc" {
  url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

# EKS addon
resource "aws_eks_addon" "ebs_csi_driver" {
  cluster_name             = aws_eks_cluster.main.name
  addon_name               = "aws-ebs-csi-driver"
  addon_version            = "v1.29.1-eksbuild.1"
  service_account_role_arn = aws_iam_role.ebs_csi_driver.arn
}

# AWS Identity and Access Management (IAM) OpenID Connect (OIDC) provider

resource "aws_iam_openid_connect_provider" "eks" {
  url             = aws_eks_cluster.main.identity.0.oidc.0.issuer
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.oidc.certificates[0].sha1_fingerprint]
}

# IAM
resource "aws_iam_role" "ebs_csi_driver" {
  name               = "ebs-csi-driver"
  assume_role_policy = data.aws_iam_policy_document.ebs_csi_driver_assume_role.json
}

data "aws_iam_policy_document" "ebs_csi_driver_assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.eks.arn]
    }

    actions = [
      "sts:AssumeRoleWithWebIdentity",
    ]

    condition {
      test     = "StringEquals"
      variable = "${aws_iam_openid_connect_provider.eks.url}:aud"
      values   = ["sts.amazonaws.com"]
    }

    condition {
      test     = "StringEquals"
      variable = "${aws_iam_openid_connect_provider.eks.url}:sub"
      values   = ["system:serviceaccount:kube-system:ebs-csi-controller-sa"]
    }

  }
}

resource "aws_iam_role_policy_attachment" "AmazonEBSCSIDriverPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
  role       = aws_iam_role.ebs_csi_driver.name
}

The above configuration follows the docs, binding an IAM role to the service account kube-system/ebs-csi-controller-sa using an OpenID connect provider.

After applying the changes above, I deployed the sample application and noticed that the persistent volume claims were bound to EBS volumes.