Skip to content

Commit

Permalink
feat(crypto): v2 volume encryption support
Browse files Browse the repository at this point in the history
ref: longhorn/longhorn 7355

Signed-off-by: James Lu <jamesluhz@gmail.com>
  • Loading branch information
mantissahz committed Jan 10, 2025
1 parent 17e95bc commit be6d50f
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 23 deletions.
13 changes: 13 additions & 0 deletions app/cmd/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"fmt"
"net"
"os"
"os/signal"
Expand All @@ -16,6 +17,7 @@ import (

"github.com/longhorn/longhorn-share-manager/pkg/rpc"
"github.com/longhorn/longhorn-share-manager/pkg/server"
"github.com/longhorn/longhorn-share-manager/pkg/types"
"github.com/longhorn/longhorn-share-manager/pkg/util"
"github.com/longhorn/longhorn-share-manager/pkg/volume"
)
Expand All @@ -33,6 +35,11 @@ func ServerCmd() cli.Command {
Usage: "The volume to export via the nfs server",
Required: true,
},
cli.StringFlag{
Name: "dataEngine",
Usage: "The volume data engine",
Required: true,
},
cli.BoolFlag{
Name: "encrypted",
Usage: "signals that a volume is encrypted",
Expand Down Expand Up @@ -84,6 +91,7 @@ func ServerCmd() cli.Command {
Action: func(c *cli.Context) {
vol := volume.Volume{
Name: c.String("volume"),
DataEngine: c.String("dataEngine"),
Passphrase: c.String("passphrase"),
CryptoKeyCipher: c.String("crytpokeycipher"),
CryptoKeyHash: c.String("crytpokeyhash"),
Expand All @@ -106,6 +114,11 @@ func ServerCmd() cli.Command {

func start(vol volume.Volume) error {
logger := util.NewLogger()
if vol.DataEngine != types.DataEngineTypeV1 && vol.DataEngine != types.DataEngineTypeV2 {
logger.Warnf("Invalid data engine value: %s", vol.DataEngine)
return fmt.Errorf("invalid data engine value: %s", vol.DataEngine)
}

manager, err := server.NewShareManager(logger, vol)
if err != nil {
return err
Expand Down
29 changes: 16 additions & 13 deletions pkg/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ func EncryptVolume(devicePath, passphrase, keyCipher, keyHash, keySize, pbkdf st
}

// OpenVolume opens volume so that it can be used by the client.
func OpenVolume(volume, devicePath, passphrase string) error {
devPath := types.GetVolumeDevicePath(volume, true)
// devicePath is the path of the volume on the host that will be opened for instance '/dev/longhorn/volume1'
func OpenVolume(volume, dataEngine, devicePath, passphrase string) error {
devPath := types.GetVolumeDevicePath(volume, dataEngine, true)
if isOpen, _ := IsDeviceOpen(devPath); isOpen {
logrus.Debugf("Device %s is already opened at %s", devicePath, devPath)
return nil
Expand All @@ -42,33 +43,35 @@ func OpenVolume(volume, devicePath, passphrase string) error {
return err
}

logrus.Debugf("Opening device %s with LUKS on %s", devicePath, volume)
_, err = nsexec.LuksOpen(volume, devicePath, passphrase, lhtypes.LuksTimeout)
encryptedDevName := types.GetEncryptVolumeName(volume, dataEngine)
logrus.Debugf("Opening device %s with LUKS on %s", devicePath, encryptedDevName)
_, err = nsexec.LuksOpen(encryptedDevName, devicePath, passphrase, lhtypes.LuksTimeout)
if err != nil {
logrus.WithError(err).Warnf("Failed to open LUKS device %s", devicePath)
logrus.WithError(err).Warnf("Failed to open LUKS device %s to %s", devicePath, encryptedDevName)
}
return err
}

// CloseVolume closes encrypted volume so it can be detached.
func CloseVolume(volume string) error {
func CloseVolume(volume, dataEngine string) error {
encryptedDevPath := types.GetVolumeDevicePath(volume, dataEngine, true)
namespaces := []lhtypes.Namespace{lhtypes.NamespaceMnt, lhtypes.NamespaceIpc}
nsexec, err := lhns.NewNamespaceExecutor(lhtypes.ProcessNone, lhtypes.HostProcDirectory, namespaces)
if err != nil {
return err
}

logrus.Debugf("Closing LUKS device %s", volume)
_, err = nsexec.LuksClose(volume, lhtypes.LuksTimeout)
logrus.Debugf("Closing LUKS device %s", encryptedDevPath)
_, err = nsexec.LuksClose(encryptedDevPath, lhtypes.LuksTimeout)
return err
}

func ResizeEncryptoDevice(volume, passphrase string) error {
devPath := types.GetVolumeDevicePath(volume, true)
if isOpen, err := IsDeviceOpen(devPath); err != nil {
func ResizeEncryptoDevice(volume, dataEngine, passphrase string) error {
encryptedDevPath := types.GetVolumeDevicePath(volume, dataEngine, true)
if isOpen, err := IsDeviceOpen(encryptedDevPath); err != nil {
return err
} else if !isOpen {
return fmt.Errorf("volume %v encrypto device is closed for resizing", volume)
return fmt.Errorf("volume %v encrypto device %s is closed for resizing", volume, encryptedDevPath)
}

namespaces := []lhtypes.Namespace{lhtypes.NamespaceMnt, lhtypes.NamespaceIpc}
Expand All @@ -77,7 +80,7 @@ func ResizeEncryptoDevice(volume, passphrase string) error {
return err
}

_, err = nsexec.LuksResize(volume, passphrase, lhtypes.LuksTimeout)
_, err = nsexec.LuksResize(encryptedDevPath, passphrase, lhtypes.LuksTimeout)
return err
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/rpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (s *ShareManagerServer) FilesystemTrim(ctx context.Context, req *smrpc.File
}
}()

devicePath := types.GetVolumeDevicePath(vol.Name, req.EncryptedDevice)
devicePath := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, req.EncryptedDevice)
if !volume.CheckDeviceValid(devicePath) {
return &emptypb.Empty{}, grpcstatus.Errorf(grpccodes.FailedPrecondition, "volume %v is not valid", vol.Name)
}
Expand Down Expand Up @@ -134,7 +134,7 @@ func (s *ShareManagerServer) FilesystemResize(ctx context.Context, req *emptypb.
}
}()

devicePath := types.GetVolumeDevicePath(vol.Name, vol.IsEncrypted())
devicePath := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, vol.IsEncrypted())
if !volume.CheckDeviceValid(devicePath) {
return &emptypb.Empty{}, grpcstatus.Errorf(grpccodes.FailedPrecondition, "volume %v is not valid", vol.Name)
}
Expand All @@ -161,7 +161,7 @@ func (s *ShareManagerServer) FilesystemResize(ctx context.Context, req *emptypb.
return &emptypb.Empty{}, grpcstatus.Errorf(grpccodes.InvalidArgument, "unsupported disk encryption format %v", diskFormat)
}

if err = crypto.ResizeEncryptoDevice(vol.Name, vol.Passphrase); err != nil {
if err = crypto.ResizeEncryptoDevice(vol.Name, vol.DataEngine, vol.Passphrase); err != nil {
return &emptypb.Empty{}, grpcstatus.Errorf(grpccodes.Internal, "failed to resize crypto device %v for volume %v node expansion: %v", devicePath, vol.Name, err)
}
}
Expand Down Expand Up @@ -309,7 +309,7 @@ func (s *ShareManagerServer) Mount(ctx context.Context, req *emptypb.Empty) (res

log.Info("Mounting and exporting volume")

devicePath := types.GetVolumeDevicePath(vol.Name, false)
devicePath := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, false)
mountPath := types.GetMountPath(vol.Name)

defer func() {
Expand Down
10 changes: 5 additions & 5 deletions pkg/server/share_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func NewShareManager(logger logrus.FieldLogger, volume volume.Volume) (*ShareMan
func (m *ShareManager) Run() error {
vol := m.volume
mountPath := types.GetMountPath(vol.Name)
devicePath := types.GetVolumeDevicePath(vol.Name, false)
devicePath := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, false)

defer func() {
// if the server is exiting, try to unmount & teardown device before we terminate the container
Expand Down Expand Up @@ -201,9 +201,9 @@ func (m *ShareManager) setupDevice(vol volume.Volume, devicePath string) (string
}
}

cryptoDevice := types.GetVolumeDevicePath(vol.Name, true)
cryptoDevice := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, true)
m.logger.Infof("Volume %s requires crypto device %s", vol.Name, cryptoDevice)
if err := crypto.OpenVolume(vol.Name, devicePath, vol.Passphrase); err != nil {
if err := crypto.OpenVolume(vol.Name, vol.DataEngine, devicePath, vol.Passphrase); err != nil {
m.logger.WithError(err).Error("Failed to open encrypted volume")
return "", err
}
Expand All @@ -217,12 +217,12 @@ func (m *ShareManager) setupDevice(vol volume.Volume, devicePath string) (string

func (m *ShareManager) tearDownDevice(vol volume.Volume) error {
// close any matching crypto device for this volume
cryptoDevice := types.GetVolumeDevicePath(vol.Name, true)
cryptoDevice := types.GetVolumeDevicePath(vol.Name, vol.DataEngine, true)
if isOpen, err := crypto.IsDeviceOpen(cryptoDevice); err != nil {
return err
} else if isOpen {
m.logger.Infof("Volume %s has active crypto device %s", vol.Name, cryptoDevice)
if err := crypto.CloseVolume(vol.Name); err != nil {
if err := crypto.CloseVolume(vol.Name, vol.DataEngine); err != nil {
return err
}
m.logger.Infof("Volume %s closed active crypto device %s", vol.Name, cryptoDevice)
Expand Down
20 changes: 19 additions & 1 deletion pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,29 @@ const (
DevPath = "/dev"
MapperDevPath = "/dev/mapper"

// The suffix for dm device name of the encrypted v2 volume.
MapperV2VolumeSuffix = "-encrypted"

ExportPath = "/export"

DataEngineTypeV1 = "v1"
DataEngineTypeV2 = "v2"
)

func GetVolumeDevicePath(volumeName string, EncryptedDevice bool) string {
func GetEncryptVolumeName(volume, dataEngine string) string {
if dataEngine == DataEngineTypeV2 {
return volume + MapperV2VolumeSuffix
}
return volume
}

func GetVolumeDevicePath(volumeName, dataEngine string, EncryptedDevice bool) string {
if EncryptedDevice {
if dataEngine == DataEngineTypeV2 {
// v2 volume will use a dm device as default to control IO path when attaching. This dm device will be created with the same name as the volume name.
// The encrypted volume will be created with the volume name with "-encrypted" suffix to resolve the naming conflict.
return path.Join(MapperDevPath, GetEncryptVolumeName(volumeName, dataEngine))
}
return path.Join(MapperDevPath, volumeName)
}
return filepath.Join(DevPath, "longhorn", volumeName)
Expand Down
1 change: 1 addition & 0 deletions pkg/volume/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

type Volume struct {
Name string
DataEngine string
Passphrase string
CryptoKeyCipher string
CryptoKeyHash string
Expand Down

0 comments on commit be6d50f

Please sign in to comment.