

 **Help improve this page** 

To contribute to this user guide, choose the **Edit this page on GitHub** link that is located in the right pane of every page.

# Create a storage class
<a name="create-storage-class"></a>

A `StorageClass` in Amazon EKS Auto Mode defines how Amazon EBS volumes are automatically provisioned when applications request persistent storage. This page explains how to create and configure a `StorageClass` that works with the Amazon EKS Auto Mode to provision EBS volumes.

By configuring a `StorageClass`, you can specify default settings for your EBS volumes including volume type, encryption, IOPS, and other storage parameters. You can also configure the `StorageClass` to use AWS KMS keys for encryption management.

EKS Auto Mode does not create a `StorageClass` for you. You must create a `StorageClass` referencing `ebs.csi.eks.amazonaws.com` to use the storage capability of EKS Auto Mode.

First, create a file named `storage-class.yaml`:

```
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: auto-ebs-sc
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
allowedTopologies:
- matchLabelExpressions:
  - key: eks.amazonaws.com/compute-type
    values:
    - auto
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  encrypted: "true"
```

Second, apply the storage class to your cluster.

```
kubectl apply -f storage-class.yaml
```

 **Key components:** 
+  `provisioner: ebs.csi.eks.amazonaws.com` - Uses EKS Auto Mode
+  `allowedTopologies` - Specifying `matchLabelExpressions` to match on `eks.amazonaws.com/compute-type:auto` will ensure that if your pods need a volume to be automatically provisioned using Auto Mode then the pods will not be scheduled on non-Auto nodes.
+  `volumeBindingMode: WaitForFirstConsumer` - Delays volume creation until a pod needs it
+  `type: gp3` - Specifies the EBS volume type
+  `encrypted: "true"` - EBS will encrypt any volumes created using the `StorageClass`. EBS will use the default `aws/ebs` key alias. For more information, see [How Amazon EBS encryption works](https://docs.aws.amazon.com/ebs/latest/userguide/how-ebs-encryption-works.html) in the Amazon EBS User Guide. This value is optional but suggested.
+  `storageclass.kubernetes.io/is-default-class: "true"` - Kubernetes will use this storage class by default, unless you specify a different volume class on a persistent volume claim. This value is optional. Use caution when setting this value if you are migrating from a different storage controller.

## Use self-managed KMS key to encrypt EBS volumes
<a name="_use_self_managed_kms_key_to_encrypt_ebs_volumes"></a>

To use a self-managed KMS key to encrypt EBS volumes automated by EKS Auto Mode, you need to:

1. Create a self-managed KMS key.
   + For more information, see [Create a symmetric encryption KMS key](https://docs.aws.amazon.com/kms/latest/developerguide/create-symmetric-cmk.html) or [How Amazon Elastic Block Store (Amazon EBS) uses KMS](https://docs.aws.amazon.com/kms/latest/developerguide/services-ebs.html) in the KMS User Guide.

1. Create a new policy that permits access to the KMS key.
   + Use the sample IAM policy below to create the policy. Insert the ARN of the new self-managed KMS key. For more information, see [Creating roles and attaching policies (console)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions_create-policies.html) in the AWS IAM User Guide.

1. Attach the policy to the EKS Cluster Role.
   + Use the AWS console to find the ARN of the EKS Cluster Role. The role information is visible in the **Overview** section. For more information, see [Amazon EKS cluster IAM role](cluster-iam-role.md).

1. Update the `StorageClass` to reference the KMS Key ID at the `parameters.kmsKeyId` field.

### Sample self-managed KMS IAM Policy
<a name="_sample_self_managed_kms_iam_policy"></a>

Update the following values in the policy below:
+  `<account-id>` – Your AWS account ID, such as `111122223333` 
+  `<aws-region>` – The AWS region of your cluster, such as `us-west-2` 

```
{
  "Version":"2012-10-17",		 	 	 
  "Id": "key-auto-policy-3",
  "Statement": [
      {
          "Sid": "Enable IAM User Permissions",
          "Effect": "Allow",
          "Principal": {
              "AWS": "arn:aws:iam::123456789012:root"
          },
          "Action": "kms:*",
          "Resource": "*"
      },
      {
        "Sid": "Allow access through EBS for all principals in the account that are authorized to use EBS",
        "Effect": "Allow",
        "Principal": {
            "AWS": "*"
        },
        "Action": [
            "kms:Encrypt",
            "kms:Decrypt",
            "kms:ReEncrypt*",
            "kms:GenerateDataKey*",
            "kms:CreateGrant",
            "kms:DescribeKey"
        ],
        "Resource": "*",
        "Condition": {
            "StringEquals": {
                "kms:CallerAccount": "123456789012",
                "kms:ViaService": "ec2.us-east-1.amazonaws.com"
            }
        }
    }
  ]
}
```

### Sample self-managed KMS `StorageClass`
<a name="_sample_self_managed_kms_storageclass"></a>

```
parameters:
  type: gp3
  encrypted: "true"
  kmsKeyId: <custom-key-arn>
```

## `StorageClass` Parameters Reference
<a name="_storageclass_parameters_reference"></a>

For general information on the Kubernetes `StorageClass` resources, see [Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) in the Kubernetes Documentation.

The `parameters` section of the `StorageClass` resource is specific to AWS. Use the following table to review available options.


| Parameters | Values | Default | Description | 
| --- | --- | --- | --- | 
| "csi.storage.k8s.io/fstype" | xfs, ext2, ext3, ext4 | ext4 | File system type that will be formatted during volume creation. This parameter is case sensitive\! | 
| "type" | io1, io2, gp2, gp3, sc1, st1, standard, sbp1, sbg1 | gp3 | EBS volume type. | 
| "iopsPerGB" |  |  | I/O operations per second per GiB. Can be specified for IO1, IO2, and GP3 volumes. | 
| "allowAutoIOPSPerGBIncrease" | true, false | false | When `"true"`, the CSI driver increases IOPS for a volume when `iopsPerGB * <volume size>` is too low to fit into IOPS range supported by AWS. This allows dynamic provisioning to always succeed, even when user specifies too small PVC capacity or `iopsPerGB` value. On the other hand, it may introduce additional costs, as such volumes have higher IOPS than requested in `iopsPerGB`. | 
| "iops" |  |  | I/O operations per second. Can be specified for IO1, IO2, and GP3 volumes. | 
| "throughput" |  | 125 | Throughput in MiB/s. Only effective when gp3 volume type is specified. | 
| "encrypted" | true, false | false | Whether the volume should be encrypted or not. Valid values are "true" or "false". | 
| "blockExpress" | true, false | false | Enables the creation of io2 Block Express volumes. | 
| "kmsKeyId" |  |  | The full ARN of the key to use when encrypting the volume. If not specified, AWS will use the default KMS key for the region the volume is in. This will be an auto-generated key called `/aws/ebs` if not changed. | 
| "blockSize" |  |  | The block size to use when formatting the underlying filesystem. Only supported on linux nodes and with fstype `ext2`, `ext3`, `ext4`, or `xfs`. | 
| "inodeSize" |  |  | The inode size to use when formatting the underlying filesystem. Only supported on linux nodes and with fstype `ext2`, `ext3`, `ext4`, or `xfs`. | 
| "bytesPerInode" |  |  | The `bytes-per-inode` to use when formatting the underlying filesystem. Only supported on linux nodes and with fstype `ext2`, `ext3`, `ext4`. | 
| "numberOfInodes" |  |  | The `number-of-inodes` to use when formatting the underlying filesystem. Only supported on linux nodes and with fstype `ext2`, `ext3`, `ext4`. | 
| "ext4BigAlloc" | true, false | false | Changes the `ext4` filesystem to use clustered block allocation by enabling the `bigalloc` formatting option. Warning: `bigalloc` may not be fully supported with your node’s Linux kernel. | 
| "ext4ClusterSize" |  |  | The cluster size to use when formatting an `ext4` filesystem when the `bigalloc` feature is enabled. Note: The `ext4BigAlloc` parameter must be set to true. | 

For more information, see the [AWS EBS CSI Driver](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/docs/parameters.md) on GitHub.

## Considerations
<a name="_considerations"></a>

**Note**  
You can only deploy workloads depending on EKS Auto Mode StorageClasses on EKS Auto Mode nodes. If you have a cluster with mixed types of nodes, you need to configure your workloads to run only on EKS Auto Mode nodes. For more information, see [Control if a workload is deployed on EKS Auto Mode nodes](associate-workload.md).

The block storage capability of EKS Auto Mode is different from the EBS CSI Driver.
+ Static Provisioning
  + If you want to use externally-created EBS volumes with EKS Auto Mode, you need to manually add an AWS tag with the key `eks:eks-cluster-name` and the value of the cluster name.
+ Node Startup Taint
  + You cannot use the node startup taint feature to prevent pod scheduling before storage capability readiness
+ Custom Tags on Dynamically Provisioned Volumes
  + You cannot use the extra-tag CLI flag to configure custom tags on dynamically provisioned EBS volumes
  + You can use `StorageClass` tagging to add custom tags. EKS Auto Mode will add tags to the associated AWS resources. You will need to update the Cluster IAM Role for custom tags. For more information, see [Custom AWS tags for EKS Auto resources](auto-cluster-iam-role.md#tag-prop).
+ EBS Detailed Performance Metrics
  + You cannot access Prometheus metrics for EBS detailed performance

**Annotation-based EBS volume modification is deprecated**  
The [`volume-modifier-for-k8s`](https://github.com/awslabs/volume-modifier-for-k8s) project has been deprecated in favor of the native Kubernetes [`VolumeAttributesClass`](https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/) API. This project was used to set annotations on a PersistentVolumeClaim to modify an EBS volume. After October 31, 2026, Amazon EKS Auto Mode no longer supports these annotations. To modify EBS volumes (for example, `type`, `iops`, or `throughput`) after that date, use the Kubernetes `VolumeAttributesClass` API instead. For more information, see [Volume Attributes Classes](https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/) in the Kubernetes documentation.

## Migrate from volume-modifier-for-k8s to VolumeAttributesClass
<a name="_migrate_from_volume_modifier_for_k8s_to_volumeattributesclass"></a>

For EKS Auto Mode clusters running Kubernetes 1.34 or later, use a `VolumeAttributesClass` (VAC) to change an EBS volume’s type, IOPS, or throughput.

Existing PVCs can be migrated in place by creating a VAC and setting `spec.volumeAttributesClassName` on the existing PVC. The PVC and PV are not recreated and there are no interruptions to your workloads during this process.

1. Define the volume settings in a VAC

   VMK annotations map to VAC parameters as follows:


<table>
<thead>
  <tr><th>Existing VMK annotation</th><th>VAC parameter</th></tr>
</thead>
<tbody>
  <tr><td> <code>ebs.csi.eks.amazonaws.com/volumeType</code> </td><td>type</td></tr>
  <tr><td> <code>ebs.csi.eks.amazonaws.com/iops</code> </td><td>iops</td></tr>
  <tr><td> <code>ebs.csi.eks.amazonaws.com/throughput</code> </td><td>throughput</td></tr>
</tbody>
</table>


   Use `type`, not `volumeType`, in the VAC. Values must be strings, and a VAC only needs the parameters relevant to the desired EBS configuration. Example:

   ```
   apiVersion: storage.k8s.io/v1
   kind: VolumeAttributesClass
   metadata:
     name: ebs-auto-gp3-6000-250
   driverName: ebs.csi.eks.amazonaws.com
   parameters:
     type: gp3
     iops: "6000"
     throughput: "250"
   ```

   VACs are cluster-scoped, so the manifest has no namespace. Apply it normally:

   ```
   kubectl apply -f vac.yaml
   ```

1. Assign the VAC to the PVC

   ```
   VAC_NAME=ebs-auto-gp3-6000-250
   
   kubectl patch pvc <pvc-name> -n <namespace> --type=merge \
     -p "{\"spec\":{\"volumeAttributesClassName\":\"${VAC_NAME}\"}}"
   ```

1. Confirm that the change completed

   ```
   kubectl get pvc <pvc-name> -n <namespace> \
     -o custom-columns='NAME:.metadata.name,REQUESTED:.spec.volumeAttributesClassName,CURRENT:.status.currentVolumeAttributesClassName,STATUS:.status.modifyVolumeStatus.status'
   ```

   The migration is complete when `REQUESTED` and `CURRENT` contain the same VAC name and `STATUS` is empty.

   If it does not complete, inspect the PVC events:

   ```
   kubectl describe pvc <pvc-name> -n <namespace>
   ```

    `Pending` usually means the referenced VAC is unavailable. `Infeasible` means the driver rejected the requested EBS parameters; create a valid VAC and assign that instead.

### Optional: Remove the VMK annotations
<a name="_optional_remove_the_vmk_annotations"></a>

Removing the old annotations is not required for VAC to work. Once a PVC or PV references a VAC, VMK refuses annotation-based modifications and VAC is the authoritative path.

The annotations may be removed later as configuration cleanup. If they are removed, also update any Helm, GitOps, or other automation that would add them back. VMK status annotations left on the PV are harmless and do not need to be removed.

### Changing or Reverting the Settings
<a name="_changing_or_reverting_the_settings"></a>

VAC parameters are immutable. To change the EBS configuration, create another VAC and assign its name to the PVC.

To cancel a change that has not completed, restore the previously assigned VAC. If the PVC did not previously use one, clear the field:

```
kubectl patch pvc <pvc-name> -n <namespace> --type=merge \
  -p '{"spec":{"volumeAttributesClassName":null}}'
```

Clearing the field does not undo an EBS modification that already completed. To restore previous volume settings, create a VAC containing those settings and assign it to the PVC. Normal EBS parameter constraints and modification cooldowns apply.

## Install CSI Snapshot Controller add-on
<a name="_install_csi_snapshot_controller_add_on"></a>

EKS Auto Mode is compatible with the CSI Snapshot Controller Amazon EKS add-on.

 AWS suggests you configure this add-on to run on the built-in `system` node pool.

For more information, see:
+  [Run critical add-ons on dedicated instances](critical-workload.md) 
+  [Enable or Disable Built-in NodePools](set-builtin-node-pools.md) 
+  [Enable snapshot functionality for CSI volumes](csi-snapshot-controller.md) 

### To install snapshot controller in system node pool
<a name="auto-install-snapshot-controller"></a>

1. Open your EKS cluster in the AWS console

1. From the **Add-ons** tab, select **Get more add-ons** 

1. Select the **CSI Snapshot Controller** and then **Next** 

1. On the **Configure selected add-ons settings** page, select **Optional configuration settings** to view the **Add-on configuration schema** 

   1. Insert the following yaml to associate the snapshot controller with the `system` node pool. The snapshot controller includes a toleration for the `CriticalAddonsOnly` taint.

      ```
      {
              "nodeSelector": {
                  "karpenter.sh/nodepool": "system"
              }
      }
      ```

   1. Select **Next** 

1. Review the add-on configuration and then select **Create** 