Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,37 @@ Now you can use one of following storageClasses:
* `csi-driver-lvm-linear`
* `csi-driver-lvm-mirror`
* `csi-driver-lvm-striped`
* `csi-driver-lvm-linear-encrypted`
* `csi-driver-lvm-mirror-encrypted`
* `csi-driver-lvm-striped-encrypted`

To get the previous old and now deprecated `csi-lvm-sc-linear`, ... storageclasses, set helm-chart value `compat03x=true`.

## Encryption ##

csi-driver-lvm supports LUKS2 encryption for volumes at rest. When encryption is enabled, the LVM logical volume is formatted with LUKS2 and a dm-crypt mapper device is used transparently for all I/O.

### Setup ###

1. Create a Kubernetes Secret containing the LUKS passphrase:

```bash
kubectl create secret generic csi-lvm-encryption-secret \
--from-literal=passphrase='my-secret-passphrase'
```

2. Create PVCs using one of the encrypted StorageClasses. The encryption is handled transparently by the driver.

### How it works ###

- **NodeStageVolume**: LUKS-formats the LV (first use only), then opens it via `cryptsetup luksOpen`, creating a `/dev/mapper/csi-lvm-<volumeID>` device
- **NodePublishVolume**: Mounts the mapper device (instead of the raw LV) to the target path
- **NodeUnpublishVolume**: Unmounts as usual
- **NodeUnstageVolume**: Closes the LUKS device via `cryptsetup luksClose`
- **Volume expansion**: The LV is extended first, then the LUKS layer is resized, then the filesystem

Both filesystem and raw block access types are supported with encryption.

## Migration ##

If you want to migrate your existing PVC to / from csi-driver-lvm, you can use [korb](https://github.com/BeryJu/korb).
Expand Down
5 changes: 5 additions & 0 deletions charts/csi-driver-lvm/templates/daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ spec:
- mountPath: /run/lock/lvm
name: lvmlock
mountPropagation: Bidirectional
- mountPath: /run/cryptsetup
name: cryptsetup-run
- name: liveness-probe
args:
- --csi-address=/csi/csi.sock
Expand Down Expand Up @@ -367,4 +369,7 @@ spec:
path: {{ .Values.lvm.hostWritePath }}/lock
type: DirectoryOrCreate
name: lvmlock
- emptyDir:
medium: Memory
name: cryptsetup-run
---
72 changes: 72 additions & 0 deletions charts/csi-driver-lvm/templates/storageclasses.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,75 @@ allowVolumeExpansion: true
parameters:
type: "striped"
{{ end }}
---
{{- $storageClass := .Values.storageClasses.linearEncrypted -}}
{{ if $storageClass.enabled }}
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: {{ .Values.lvm.storageClassStub }}-linear-encrypted
{{- if not (empty $storageClass.additionalAnnotations) }}
annotations:
{{- $storageClass.additionalAnnotations | toYaml | nindent 4 -}}
{{ end }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
provisioner: {{ .Values.lvm.driverName }}
reclaimPolicy: {{ $storageClass.reclaimPolicy }}
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "linear"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: {{ $storageClass.encryptionSecret.name }}
csi.storage.k8s.io/node-stage-secret-namespace: {{ $storageClass.encryptionSecret.namespace }}
{{ end }}
---
{{- $storageClass := .Values.storageClasses.mirrorEncrypted -}}
{{ if $storageClass.enabled }}
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: {{ .Values.lvm.storageClassStub }}-mirror-encrypted
{{- if not (empty $storageClass.additionalAnnotations) }}
annotations:
{{- $storageClass.additionalAnnotations | toYaml | nindent 4 -}}
{{ end }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
provisioner: {{ .Values.lvm.driverName }}
reclaimPolicy: {{ $storageClass.reclaimPolicy }}
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "mirror"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: {{ $storageClass.encryptionSecret.name }}
csi.storage.k8s.io/node-stage-secret-namespace: {{ $storageClass.encryptionSecret.namespace }}
{{ end }}
---
{{- $storageClass := .Values.storageClasses.stripedEncrypted -}}
{{ if $storageClass.enabled }}
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: {{ .Values.lvm.storageClassStub }}-striped-encrypted
{{- if not (empty $storageClass.additionalAnnotations) }}
annotations:
{{- $storageClass.additionalAnnotations | toYaml | nindent 4 -}}
{{ end }}
labels:
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
provisioner: {{ .Values.lvm.driverName }}
reclaimPolicy: {{ $storageClass.reclaimPolicy }}
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "striped"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: {{ $storageClass.encryptionSecret.name }}
csi.storage.k8s.io/node-stage-secret-namespace: {{ $storageClass.encryptionSecret.namespace }}
{{ end }}
21 changes: 21 additions & 0 deletions charts/csi-driver-lvm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@ storageClasses:
enabled: true
additionalAnnotations: []
reclaimPolicy: Delete
linearEncrypted:
enabled: true
additionalAnnotations: []
reclaimPolicy: Delete
encryptionSecret:
name: csi-lvm-encryption-secret
namespace: default
stripedEncrypted:
enabled: true
additionalAnnotations: []
reclaimPolicy: Delete
encryptionSecret:
name: csi-lvm-encryption-secret
namespace: default
mirrorEncrypted:
enabled: true
additionalAnnotations: []
reclaimPolicy: Delete
encryptionSecret:
name: csi-lvm-encryption-secret
namespace: default
Comment on lines +59 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably make these storageclasses/feature opt-in instead of default. Users first need to deploy the csi-lvm-encryption-secret.


nodeSelector:
# The plugin daemonset will run on all nodes if it has a toleration,
Expand Down
2 changes: 1 addition & 1 deletion cmd/lvmplugin/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM alpine:3.22
ARG TARGETPLATFORM
LABEL maintainer="metal-stack authors <info@metal-stack.io>"

RUN apk add lvm2 lvm2-extra e2fsprogs e2fsprogs-extra smartmontools nvme-cli util-linux device-mapper xfsprogs xfsprogs-extra
RUN apk add lvm2 lvm2-extra e2fsprogs e2fsprogs-extra smartmontools nvme-cli util-linux device-mapper xfsprogs xfsprogs-extra cryptsetup
COPY --chmod=755 bin/${TARGETPLATFORM}/lvmplugin /lvmplugin
USER root
ENTRYPOINT ["/lvmplugin"]
8 changes: 8 additions & 0 deletions examples/csi-encryption-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
kind: Secret
metadata:
name: csi-lvm-encryption-secret
namespace: default
type: Opaque
stringData:
passphrase: "my-secret-passphrase"
13 changes: 13 additions & 0 deletions examples/csi-storageclass-linear-encrypted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-lvm-sc-linear-encrypted
provisioner: lvm.csi.metal-stack.io
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "linear"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: csi-lvm-encryption-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
13 changes: 13 additions & 0 deletions examples/csi-storageclass-mirror-encrypted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-lvm-sc-mirror-encrypted
provisioner: lvm.csi.metal-stack.io
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "mirror"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: csi-lvm-encryption-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
13 changes: 13 additions & 0 deletions examples/csi-storageclass-striped-encrypted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-lvm-sc-striped-encrypted
provisioner: lvm.csi.metal-stack.io
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
type: "striped"
encryption: "true"
csi.storage.k8s.io/node-stage-secret-name: csi-lvm-encryption-secret
csi.storage.k8s.io/node-stage-secret-namespace: default
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
module github.com/metal-stack/csi-driver-lvm

go 1.25
go 1.25.0

require (
github.com/container-storage-interface/spec v1.11.0
github.com/docker/go-units v0.5.0
github.com/go-logr/logr v1.4.3
github.com/metal-stack/v v1.0.3
golang.org/x/net v0.43.0
golang.org/x/sys v0.35.0
golang.org/x/sys v0.38.0
google.golang.org/grpc v1.75.0
google.golang.org/protobuf v1.36.8
k8s.io/api v0.34.0
Expand Down Expand Up @@ -38,6 +38,7 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand Down Expand Up @@ -65,6 +66,7 @@ require (
k8s.io/apiextensions-apiserver v0.33.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
k8s.io/mount-utils v0.35.0 // indirect
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs=
github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down Expand Up @@ -98,6 +100,7 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand All @@ -106,6 +109,7 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -155,6 +159,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down Expand Up @@ -204,6 +210,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/mount-utils v0.35.0 h1:UDE8RDeqmQh1u/yRd+GZC2EpDibiyAfmMEsm43lKNQI=
k8s.io/mount-utils v0.35.0/go.mod h1:ppC4d+mUpfbAJr/V2E8vvxeCEckNM+S5b0kQBQjd3Pw=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
Expand Down
Loading