Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add encryption support #514

Closed
wants to merge 5 commits into from
Closed
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,19 @@ $ kubectl exec -ti my-csi-app /bin/sh
hello-world
```

## Volume parameters

This plugin supports the following `StorageClass` parameters:

For LUKS encryption:

* `dobs.csi.digitalocean.com/luks-encrypted`: set to the string `"true"` if the volume should be encrypted
with LUKS
* `dobs.csi.digitalocean.com/luks-cipher`: cipher to use; must be supported by the kernel and luks. E.g. `aes-xts-plain64`
* `dobs.csi.digitalocean.com/luks-key-size`: key-size to use. E.g. `512`
* `csi.storage.k8s.io/node-stage-secret-name`: secret name that contains LUKS key. E.g. `${pvc.name}-luks-key`
* `csi.storage.k8s.io/node-stage-secret-namespace`: secret key namespace. E.g. `${pvc.namespace}`

## Upgrading

When upgrading to a new Kubernetes minor version, you should upgrade the CSI
Expand Down
1 change: 1 addition & 0 deletions cmd/do-csi-plugin/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ FROM amd64/alpine:3.16
# e2fsprogs-extra is required for resize2fs used for the resize operation
# blkid: block device identification tool from util-linux
RUN apk add --no-cache ca-certificates \
cryptsetup \
e2fsprogs \
findmnt \
xfsprogs \
Expand Down
6 changes: 6 additions & 0 deletions deploy/kubernetes/releases/csi-digitalocean-dev/driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ spec:
mountPropagation: "Bidirectional"
- name: device-dir
mountPath: /dev
- name: tmpfs
mountPath: /tmp
volumes:
- name: registration-dir
hostPath:
Expand All @@ -462,6 +464,10 @@ spec:
- name: udev-rules-dir
hostPath:
path: /etc/udev/rules.d/
# to make sure temporary stored luks keys never touch a disk
- name: tmpfs
emptyDir:
medium: Memory
---

apiVersion: v1
Expand Down
65 changes: 46 additions & 19 deletions driver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ const (
tiB
)

const (
// PublishInfoVolumeName is used to pass the volume name from
// `ControllerPublishVolume` to `NodeStageVolume or `NodePublishVolume`
PublishInfoVolumeName = DefaultDriverName + "/volume-name"
)

const (
// minimumVolumeSizeInBytes is used to validate that the user is not trying
// to create a volume that is smaller than what we support
Expand Down Expand Up @@ -115,12 +121,17 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
}

volumeName := req.Name
luksEncrypted := "false"
if req.Parameters[LuksEncryptedAttribute] == "true" {
luksEncrypted = "true"
}

log := d.log.WithFields(logrus.Fields{
"volume_name": volumeName,
"storage_size_giga_bytes": size / giB,
"method": "create_volume",
"volume_capabilities": req.VolumeCapabilities,
"luks_encrypted": luksEncrypted,
})
log.Info("create volume called")

Expand All @@ -133,6 +144,26 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
return nil, status.Error(codes.Internal, err.Error())
}

csiVolume := csi.Volume{
AccessibleTopology: []*csi.Topology{
{
Segments: map[string]string{
"region": d.region,
},
},
},
CapacityBytes: size,
VolumeContext: map[string]string{
LuksEncryptedAttribute: luksEncrypted,
PublishInfoVolumeName: volumeName,
},
}

if luksEncrypted == "true" {
csiVolume.VolumeContext[LuksCipherAttribute] = req.Parameters[LuksCipherAttribute]
csiVolume.VolumeContext[LuksKeySizeAttribute] = req.Parameters[LuksKeySizeAttribute]
}

// volume already exist, do nothing
if len(volumes) != 0 {
if len(volumes) > 1 {
Expand All @@ -145,12 +176,9 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
}

log.Info("volume already created")
return &csi.CreateVolumeResponse{
Volume: &csi.Volume{
VolumeId: vol.ID,
CapacityBytes: vol.SizeGigaBytes * giB,
},
}, nil
csiVolume.VolumeId = vol.ID
csiVolume.CapacityBytes = vol.SizeGigaBytes * giB
return &csi.CreateVolumeResponse{Volume: &csiVolume}, nil
}

volumeReq := &godo.VolumeCreateRequest{
Expand Down Expand Up @@ -220,19 +248,8 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
log.Info("resize completed")
}

resp := &csi.CreateVolumeResponse{
Volume: &csi.Volume{
VolumeId: vol.ID,
CapacityBytes: size,
AccessibleTopology: []*csi.Topology{
{
Segments: map[string]string{
"region": d.region,
},
},
},
},
}
csiVolume.VolumeId = vol.ID
resp := &csi.CreateVolumeResponse{Volume: &csiVolume}

// external-provisioner expects a content source to be returned if the PVC
// specified a data source, which corresponds to us having received a
Expand Down Expand Up @@ -349,6 +366,9 @@ func (d *Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controlle
return &csi.ControllerPublishVolumeResponse{
PublishContext: map[string]string{
d.publishInfoVolumeName: vol.Name,
LuksEncryptedAttribute: req.VolumeContext[LuksEncryptedAttribute],
LuksCipherAttribute: req.VolumeContext[LuksCipherAttribute],
LuksKeySizeAttribute: req.VolumeContext[LuksKeySizeAttribute],
},
}, nil
}
Expand All @@ -374,6 +394,9 @@ func (d *Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controlle
return &csi.ControllerPublishVolumeResponse{
PublishContext: map[string]string{
d.publishInfoVolumeName: vol.Name,
LuksEncryptedAttribute: req.VolumeContext[LuksEncryptedAttribute],
LuksCipherAttribute: req.VolumeContext[LuksCipherAttribute],
LuksKeySizeAttribute: req.VolumeContext[LuksKeySizeAttribute],
},
}, nil
}
Expand Down Expand Up @@ -406,6 +429,9 @@ func (d *Driver) ControllerPublishVolume(ctx context.Context, req *csi.Controlle
return &csi.ControllerPublishVolumeResponse{
PublishContext: map[string]string{
d.publishInfoVolumeName: vol.Name,
LuksEncryptedAttribute: req.VolumeContext[LuksEncryptedAttribute],
LuksCipherAttribute: req.VolumeContext[LuksCipherAttribute],
LuksKeySizeAttribute: req.VolumeContext[LuksKeySizeAttribute],
},
}, nil
}
Expand Down Expand Up @@ -838,6 +864,7 @@ func (d *Driver) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsReques

untypedSnapshots, nextToken, err := listResources(ctx, log, startingToken, req.MaxEntries, func(ctx context.Context, listOpts *godo.ListOptions) ([]interface{}, *godo.Response, error) {
snapshots, resp, err := d.snapshots.ListVolume(ctx, listOpts)

if err != nil {
return nil, resp, err
}
Expand Down
9 changes: 5 additions & 4 deletions driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,16 +523,16 @@ type fakeMounter struct {
mounted map[string]string
}

func (f *fakeMounter) Format(source string, fsType string) error {
func (f *fakeMounter) Format(source string, fsType string, context LuksContext) error {
return nil
}

func (f *fakeMounter) Mount(source string, target string, fsType string, options ...string) error {
func (f *fakeMounter) Mount(source string, target string, fsType string, context LuksContext, options ...string) error {
f.mounted[target] = source
return nil
}

func (f *fakeMounter) Unmount(target string) error {
func (f *fakeMounter) Unmount(target string, context LuksContext) error {
delete(f.mounted, target)
return nil
}
Expand All @@ -549,9 +549,10 @@ func (f *fakeMounter) IsAttached(source string) error {
return nil
}

func (f *fakeMounter) IsFormatted(source string) (bool, error) {
func (f *fakeMounter) IsFormatted(source string, context LuksContext) (bool, error) {
return true, nil
}

func (f *fakeMounter) IsMounted(target string) (bool, error) {
_, ok := f.mounted[target]
return ok, nil
Expand Down
Loading