Trident Linux Unified Key Setup (LUKS)
Linux Unified Key Setup (LUKS) is a disk-encryption specification. Trident uses LUKS to provide per-volume, host-side encryption for ONTAP SAN and ONTAP SAN ECONOMY volumes, with support for passphrase rotation and volume expansion.
In Trident, LUKS-encrypted volumes use the aes-xts-plain64 cypher and mode, as recommended by NIST.
|
|
LUKS encryption is not supported for ASA r2 systems. For information about ASA r2 systems, see Learn about ASA r2 storage systems. |
-
Worker nodes must have cryptsetup 2.1 or higher (but lower than 3.0) installed. For more information, visit Gitlab: cryptsetup.
-
For performance reasons, NetApp recommends that worker nodes support Advanced Encryption Standard New Instructions (AES-NI). To verify AES-NI support, run the following command:
grep "aes" /proc/cpuinfo
If nothing is returned, your processor does not support AES-NI. For more information on AES-NI, visit: Intel: Advanced Encryption Standard Instructions (AES-NI).
Enable LUKS encryption
You can enable per-volume, host-side encryption using Linux Unified Key Setup (LUKS) for ONTAP SAN and ONTAP SAN ECONOMY volumes.
-
Define LUKS encryption attributes in the backend configuration. For more information on backend configuration options for ONTAP SAN, refer to ONTAP SAN configuration options.
{ "storage": [ { "labels": { "luks": "true" }, "zone": "us_east_1a", "defaults": { "luksEncryption": "true" } }, { "labels": { "luks": "false" }, "zone": "us_east_1a", "defaults": { "luksEncryption": "false" } } ] } -
Use
parameters.selectorto define the storage pools using LUKS encryption. For example:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: luks provisioner: csi.trident.netapp.io parameters: selector: "luks=true" csi.storage.k8s.io/node-stage-secret-name: luks-${pvc.name} csi.storage.k8s.io/node-stage-secret-namespace: ${pvc.namespace} -
Create a secret that contains the LUKS passphrase. For example:
kubectl -n trident create -f luks-pvc1.yaml apiVersion: v1 kind: Secret metadata: name: luks-pvc1 stringData: luks-passphrase-name: A luks-passphrase: secretA
Use LUKS with RWX raw block volumes
Beginning with Trident 26.10, you can use LUKS encryption with iSCSI-backed raw block volumes that are attached to multiple Kubernetes nodes using the ReadWriteMany (RWX) access mode. This is useful for workloads such as KubeVirt virtual machines that need to attach the same encrypted volume on a destination node while it is still attached on the source node during live migration.
RWX LUKS support is limited to raw block volumes. Filesystem-mode RWX LUKS volumes are not supported. The application is responsible for coordinating concurrent access to the decrypted data; Trident coordinates LUKS operations only.
Configure LUKS on the backend, StorageClass, and passphrase Secret as described in Enable LUKS encryption. Then create a PVC with volumeMode: Block and ReadWriteMany:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-rwx-pvc
namespace: my-app
spec:
accessModes:
- ReadWriteMany
volumeMode: Block
storageClassName: san-luks-rwx
resources:
requests:
storage: 10Gi
Pods on multiple nodes can attach this PVC as a raw block device. Trident formats the device with LUKS2 on its first attachment and opens the existing encrypted volume on subsequent nodes. Existing LUKS operations, including passphrase rotation and volume expansion, are supported.
Why Trident serializes LUKS operations
LUKS2 stores redundant copies of its encryption header at the start of the block device. cryptsetup can repair a header when it detects that the copies differ, including during commands that appear to be read-only. Its locking is local to a node and cannot coordinate operations on other nodes. If one node is updating the header while another runs cryptsetup, the second node could trigger header repair and interrupt the update, potentially corrupting the header.
To prevent concurrent header access, Trident uses a Kubernetes Lease for each RWX LUKS volume. Before a node runs any cryptsetup command for the volume, it must hold the Lease. Trident releases the Lease after a successful operation. If another node requests an operation while the Lease is held, Trident returns a retryable error and Kubernetes retries later. Operations on different volumes are independent.
If a cryptsetup operation fails, Trident intentionally retains the Lease so only the same node can retry. A warning event with reason LeaseRetained records the failure. Leases do not expire automatically; an administrator should remove a Lease only after confirming that no cryptsetup operation is running on its holder node. For recovery steps, see Remediate a stuck Lease for RWX Linux Unified Key Setup (LUKS) volumes.
Because nodes take turns opening the volume, starting workloads on many different nodes can take longer than with an unencrypted volume. Kubernetes retries transient lock errors after the current operation finishes. Pods may remain in ContainerCreating longer during large scale-outs; workloads on the same node can share a single open device mapping.
Limitations
LUKS-encrypted volumes cannot take advantage of ONTAP deduplication and compression.
Backend configuration for importing LUKS volumes
To import a LUKS volume, you must set luksEncryption to true on the backend. The luksEncryption option tells Trident if the volume is LUKS-compliant (true) or not LUKS-compliant (false) as shown in the following example.
version: 1
storageDriverName: ontap-san
managementLIF: 10.0.0.1
dataLIF: 10.0.0.2
svm: trident_svm
username: admin
password: password
defaults:
luksEncryption: 'true'
spaceAllocation: 'false'
snapshotPolicy: default
snapshotReserve: '10'
PVC configuration for importing LUKS volumes
To import LUKS volumes dynamically, set the annotation trident.netapp.io/luksEncryption to true and include a LUKS-enabled storage class in the PVC as shown in this example.
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: luks-pvc
namespace: trident
annotations:
trident.netapp.io/luksEncryption: "true"
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: luks-sc
Rotate a LUKS passphrase
You can rotate the LUKS passphrase and confirm rotation.
|
|
Do not forget a passphrase until you have verified it is no longer referenced by any volume, snapshot, or secret. If a referenced passphrase is lost, you might be unable to mount the volume and the data will remain encrypted and inaccessible. |
LUKS passphrase rotation occurs when a pod that mounts the volume is created after a new LUKS passphrase is specified. When a new pod is created, Trident compares the LUKS passphrase on the volume to the active passphrase in the secret.
-
If the passphrase on the volume does not match the active passphrase in the secret, rotation occurs.
-
If the passphrase on the volume matches the active passphrase in the secret, the
previous-luks-passphraseparameter is ignored.
-
Add the
node-publish-secret-nameandnode-publish-secret-namespaceStorageClass parameters. For example:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: csi-san provisioner: csi.trident.netapp.io parameters: trident.netapp.io/backendType: "ontap-san" csi.storage.k8s.io/node-stage-secret-name: luks csi.storage.k8s.io/node-stage-secret-namespace: ${pvc.namespace} csi.storage.k8s.io/node-publish-secret-name: luks csi.storage.k8s.io/node-publish-secret-namespace: ${pvc.namespace} -
Identify existing passphrases on the volume or snapshot.
Volumetridentctl -d get volume luks-pvc1 GET http://127.0.0.1:8000/trident/v1/volume/<volumeID> ...luksPassphraseNames:["A"]
Snapshottridentctl -d get snapshot luks-pvc1 GET http://127.0.0.1:8000/trident/v1/volume/<volumeID>/<snapshotID> ...luksPassphraseNames:["A"]
-
Update the LUKS secret for the volume to specify the new and previous passphrases. Ensure
previous-luke-passphrase-nameandprevious-luks-passphrasematch the previous passphrase.apiVersion: v1 kind: Secret metadata: name: luks-pvc1 stringData: luks-passphrase-name: B luks-passphrase: secretB previous-luks-passphrase-name: A previous-luks-passphrase: secretA -
Create a new pod mounting the volume. This is required to initiate the rotation.
-
Verify the the passphrase was rotated.
Volumetridentctl -d get volume luks-pvc1 GET http://127.0.0.1:8000/trident/v1/volume/<volumeID> ...luksPassphraseNames:["B"]
Snapshottridentctl -d get snapshot luks-pvc1 GET http://127.0.0.1:8000/trident/v1/volume/<volumeID>/<snapshotID> ...luksPassphraseNames:["B"]
The passphrase was rotated when only the new passphrase is returned on the volume and snapshot.
|
|
If two passphrases are returned, for example luksPassphraseNames: ["B", "A"], the rotation is incomplete. You can trigger a new pod to attempt to complete the rotation.
|
Enable volume expansion
You can enable volume expansion on a LUKS-encrypted volume.
-
Enable the
CSINodeExpandSecretfeature gate (beta 1.25+). Refer to Kubernetes 1.25: Use Secrets for Node-Driven Expansion of CSI Volumes for details. -
Add the
node-expand-secret-nameandnode-expand-secret-namespaceStorageClass parameters. For example:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: luks provisioner: csi.trident.netapp.io parameters: selector: "luks=true" csi.storage.k8s.io/node-stage-secret-name: luks-${pvc.name} csi.storage.k8s.io/node-stage-secret-namespace: ${pvc.namespace} csi.storage.k8s.io/node-expand-secret-name: luks-${pvc.name} csi.storage.k8s.io/node-expand-secret-namespace: ${pvc.namespace} allowVolumeExpansion: true
When you initiate online storage expansion, the kubelet passes the appropriate credentials to the driver.