Skip to content

Commit a5af5a1

Browse files
iPraveenPariharnixpanic
authored andcommitted
rbd: add additional space for encrypted volumes
issue: when a block-mode pvc is created with encryption enabled there is some space reserved for the encryption metadata. Which doesn't allows users to write extact amount of data that they have requested for. solution: create pvc with extra space needed for the encryption metadata. The extra space is added during the CreateVolume and ExpandVolume operations. And while returning the response remove the extra space so the client/user gets the requested size reported. Signed-off-by: Praveen M <m.praveen@ibm.com>
1 parent 71cbf3d commit a5af5a1

5 files changed

Lines changed: 92 additions & 4 deletions

File tree

PendingReleaseNotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
- deploy: radosNamespaceCephFS can be configured for ceph-csi-cephfs chart in [PR](https://github.com/ceph/ceph-csi/pull/4652)
1313
- build: update ceph release to squid in [PR](https://github.com/ceph/ceph-csi/pull/4735)
1414
- build: CentOS Stream 9 is used as OS in the container-images [PR](https://github.com/ceph/ceph-csi/pull/4735)
15+
- rbd: add additional space for encrypted volumes for Luks2 header in [PR] (https://github.com/ceph/ceph-csi/pull/4582)
1516

1617
## NOTE

internal/rbd/controllerserver.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,17 @@ func (cs *ControllerServer) CreateSnapshot(
12351235
return nil, status.Error(codes.Internal, err.Error())
12361236
}
12371237

1238+
err = vol.Connect(cr)
1239+
if err != nil {
1240+
return nil, status.Error(codes.Internal, err.Error())
1241+
}
1242+
defer vol.Destroy(ctx)
1243+
1244+
err = vol.getImageInfo()
1245+
if err != nil {
1246+
return nil, status.Error(codes.Internal, err.Error())
1247+
}
1248+
12381249
csiSnap, err := vol.toSnapshot().ToCSI(ctx)
12391250
if err != nil {
12401251
return nil, status.Error(codes.Internal, err.Error())
@@ -1294,6 +1305,17 @@ func cloneFromSnapshot(
12941305
}
12951306
}
12961307

1308+
err = rbdSnap.Connect(cr)
1309+
if err != nil {
1310+
return nil, status.Error(codes.Internal, err.Error())
1311+
}
1312+
defer rbdSnap.Destroy(ctx)
1313+
1314+
err = rbdSnap.getImageInfo()
1315+
if err != nil {
1316+
return nil, status.Error(codes.Internal, err.Error())
1317+
}
1318+
12971319
csiSnap, err := rbdSnap.ToCSI(ctx)
12981320
if err != nil {
12991321
return nil, status.Error(codes.Internal, err.Error())

internal/rbd/encryption.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ const (
5959
metadataDEK = "rbd.csi.ceph.com/dek"
6060
oldMetadataDEK = ".rbd.csi.ceph.com/dek"
6161

62+
// luks2 header size metadata key.
63+
luks2HeaderSizeKey = "rbd.csi.ceph.com/luks2HeaderSize"
64+
6265
encryptionPassphraseSize = 20
6366

6467
// rbdDefaultEncryptionType is the default to use when the
@@ -130,6 +133,11 @@ func (ri *rbdImage) setupBlockEncryption(ctx context.Context) error {
130133
return err
131134
}
132135

136+
err = ri.SetMetadata(luks2HeaderSizeKey, strconv.FormatUint(util.Luks2HeaderSize, 10))
137+
if err != nil {
138+
return fmt.Errorf("failed to save %s metadata on image: %w", luks2HeaderSizeKey, err)
139+
}
140+
133141
err = ri.ensureEncryptionMetadataSet(rbdImageEncryptionPrepared)
134142
if err != nil {
135143
log.ErrorLog(ctx, "failed to save encryption status, deleting "+

internal/rbd/rbd_util.go

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,16 @@ func createImage(ctx context.Context, pOpts *rbdVolume, cr *util.Credentials) er
449449
return fmt.Errorf("failed to get IOContext: %w", err)
450450
}
451451

452-
err = librbd.CreateImage(pOpts.ioctx, pOpts.RbdImageName,
453-
uint64(util.RoundOffVolSize(pOpts.VolSize)*helpers.MiB), options)
452+
size := uint64(util.RoundOffVolSize(pOpts.VolSize) * helpers.MiB)
453+
if pOpts.isBlockEncrypted() {
454+
// When a block-mode PVC is created with encryption enabled,
455+
// some space is reserved for the LUKS2 header.
456+
// Add the LUKS2 header size to the image size so that the user has at least
457+
// the requested size.
458+
size += util.Luks2HeaderSize
459+
}
460+
461+
err = librbd.CreateImage(pOpts.ioctx, pOpts.RbdImageName, size, options)
454462
if err != nil {
455463
return fmt.Errorf("failed to create rbd image: %w", err)
456464
}
@@ -1604,6 +1612,26 @@ func (ri *rbdImage) GetCreationTime(ctx context.Context) (*time.Time, error) {
16041612
return ri.CreatedAt, nil
16051613
}
16061614

1615+
// getLuks2HeaderSizeSet returns the value of the LUKS2 header size
1616+
// set in the image metadata (size returned in MiB).
1617+
func (ri *rbdImage) getLuks2HeaderSizeSet() (uint64, error) {
1618+
value, err := ri.GetMetadata(luks2HeaderSizeKey)
1619+
if err != nil {
1620+
if !errors.Is(err, librbd.ErrNotFound) {
1621+
return 0, err
1622+
}
1623+
1624+
return 0, nil
1625+
}
1626+
1627+
headerSize, parseErr := strconv.ParseUint(value, 10, 64)
1628+
if parseErr != nil {
1629+
return 0, parseErr
1630+
}
1631+
1632+
return headerSize, nil
1633+
}
1634+
16071635
// getImageInfo queries rbd about the given image and returns its metadata, and returns
16081636
// ErrImageNotFound if provided image is not found.
16091637
func (ri *rbdImage) getImageInfo() error {
@@ -1620,6 +1648,14 @@ func (ri *rbdImage) getImageInfo() error {
16201648
// TODO: can rv.VolSize not be a uint64? Or initialize it to -1?
16211649
ri.VolSize = int64(imageInfo.Size)
16221650

1651+
// If the luks2HeaderSizeKey metadata is set
1652+
// reduce the extra size of the LUKS header from the image size.
1653+
headerSize, err := ri.getLuks2HeaderSizeSet()
1654+
if err != nil {
1655+
return err
1656+
}
1657+
ri.VolSize -= int64(headerSize)
1658+
16231659
features, err := image.GetFeatures()
16241660
if err != nil {
16251661
return err
@@ -1869,7 +1905,17 @@ func (ri *rbdImage) resize(newSize int64) error {
18691905
}
18701906
defer image.Close()
18711907

1872-
err = image.Resize(uint64(util.RoundOffVolSize(newSize) * helpers.MiB))
1908+
size := uint64(util.RoundOffVolSize(newSize) * helpers.MiB)
1909+
1910+
// If the luks2HeaderSizeKey metadata is set
1911+
// add the extra size of the LUKS header to the image size.
1912+
headerSize, err := ri.getLuks2HeaderSizeSet()
1913+
if err != nil {
1914+
return err
1915+
}
1916+
size += headerSize
1917+
1918+
err = image.Resize(size)
18731919
if err != nil {
18741920
return err
18751921
}

internal/util/cryptsetup.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,17 @@ import (
2626

2727
"github.com/ceph/ceph-csi/internal/util/file"
2828
"github.com/ceph/ceph-csi/internal/util/log"
29+
30+
"k8s.io/cloud-provider/volume/helpers"
2931
)
3032

3133
// Limit memory used by Argon2i PBKDF to 32 MiB.
32-
const cryptsetupPBKDFMemoryLimit = 32 << 10 // 32768 KiB
34+
const (
35+
cryptsetupPBKDFMemoryLimit = 32 << 10 // 32768 KiB
36+
luks2MetadataSize = 32 << 7 // 4096 KiB
37+
luks2KeySlotsSize = 32 << 8 // 8192 KiB
38+
Luks2HeaderSize = uint64((((2 * luks2MetadataSize) + luks2KeySlotsSize) * helpers.KiB))
39+
)
3340

3441
// LuksFormat sets up volume as an encrypted LUKS partition.
3542
func LuksFormat(devicePath, passphrase string) (string, string, error) {
@@ -41,6 +48,10 @@ func LuksFormat(devicePath, passphrase string) (string, string, error) {
4148
"luks2",
4249
"--hash",
4350
"sha256",
51+
"--luks2-metadata-size",
52+
strconv.Itoa(luks2MetadataSize)+"k",
53+
"--luks2-keyslots-size",
54+
strconv.Itoa(luks2KeySlotsSize)+"k",
4455
"--pbkdf-memory",
4556
strconv.Itoa(cryptsetupPBKDFMemoryLimit),
4657
devicePath,

0 commit comments

Comments
 (0)