mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-27 16:50:23 +00:00
144 lines
5.0 KiB
Go
144 lines
5.0 KiB
Go
|
/*
|
||
|
Copyright 2019 The Ceph-CSI Authors.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package util
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"path"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
|
||
|
"k8s.io/klog"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
mapperFilePrefix = "luks-rbd-"
|
||
|
mapperFilePathPrefix = "/dev/mapper"
|
||
|
|
||
|
// image metadata key for encryption
|
||
|
encryptionMetaKey = ".rbd.csi.ceph.com/encrypted"
|
||
|
|
||
|
// Encryption passphrase location in K8s secrets
|
||
|
encryptionPassphraseKey = "encryptionPassphrase"
|
||
|
)
|
||
|
|
||
|
// VolumeMapper returns file name and it's path to where encrypted device should be open
|
||
|
func VolumeMapper(volumeID string) (mapperFile, mapperFilePath string) {
|
||
|
mapperFile = mapperFilePrefix + volumeID
|
||
|
mapperFilePath = path.Join(mapperFilePathPrefix, mapperFile)
|
||
|
return mapperFile, mapperFilePath
|
||
|
}
|
||
|
|
||
|
// GetCryptoPassphrase Retrieves passphrase to encrypt volume
|
||
|
func GetCryptoPassphrase(secrets map[string]string) (string, error) {
|
||
|
val, ok := secrets[encryptionPassphraseKey]
|
||
|
if !ok {
|
||
|
return "", errors.New("missing encryption passphrase in secrets")
|
||
|
}
|
||
|
return val, nil
|
||
|
}
|
||
|
|
||
|
// EncryptVolume encrypts provided device with LUKS
|
||
|
func EncryptVolume(ctx context.Context, devicePath, passphrase string) error {
|
||
|
klog.V(4).Infof(Log(ctx, "Encrypting device %s with LUKS"), devicePath)
|
||
|
if _, _, err := LuksFormat(devicePath, passphrase); err != nil {
|
||
|
return errors.Wrapf(err, "failed to encrypt device %s with LUKS", devicePath)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// OpenEncryptedVolume opens volume so that it can be used by the client
|
||
|
func OpenEncryptedVolume(ctx context.Context, devicePath, mapperFile, passphrase string) error {
|
||
|
klog.V(4).Infof(Log(ctx, "Opening device %s with LUKS on %s"), devicePath, mapperFile)
|
||
|
_, _, err := LuksOpen(devicePath, mapperFile, passphrase)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// CloseEncryptedVolume closes encrypted volume so it can be detached
|
||
|
func CloseEncryptedVolume(ctx context.Context, mapperFile string) error {
|
||
|
klog.V(4).Infof(Log(ctx, "Closing LUKS device %s"), mapperFile)
|
||
|
_, _, err := LuksClose(mapperFile)
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// IsDeviceOpen determines if encrypted device is already open
|
||
|
func IsDeviceOpen(ctx context.Context, device string) (bool, error) {
|
||
|
_, mappedFile, err := DeviceEncryptionStatus(ctx, device)
|
||
|
return (mappedFile != ""), err
|
||
|
}
|
||
|
|
||
|
// DeviceEncryptionStatus looks to identify if the passed device is a LUKS mapping
|
||
|
// and if so what the device is and the mapper name as used by LUKS.
|
||
|
// If not, just returns the original device and an empty string.
|
||
|
func DeviceEncryptionStatus(ctx context.Context, devicePath string) (mappedDevice, mapper string, err error) {
|
||
|
if !strings.HasPrefix(devicePath, mapperFilePathPrefix) {
|
||
|
return devicePath, "", nil
|
||
|
}
|
||
|
mapPath := strings.TrimPrefix(devicePath, mapperFilePathPrefix+"/")
|
||
|
stdout, _, err := LuksStatus(mapPath)
|
||
|
if err != nil {
|
||
|
klog.V(4).Infof(Log(ctx, "device %s is not an active LUKS device: %v"), devicePath, err)
|
||
|
return devicePath, "", nil
|
||
|
}
|
||
|
lines := strings.Split(string(stdout), "\n")
|
||
|
if len(lines) < 1 {
|
||
|
return "", "", fmt.Errorf("device encryption status returned no stdout for %s", devicePath)
|
||
|
}
|
||
|
if !strings.HasSuffix(lines[0], " is active.") {
|
||
|
// Implies this is not a LUKS device
|
||
|
return devicePath, "", nil
|
||
|
}
|
||
|
for i := 1; i < len(lines); i++ {
|
||
|
kv := strings.SplitN(strings.TrimSpace(lines[i]), ":", 2)
|
||
|
if len(kv) < 1 {
|
||
|
return "", "", fmt.Errorf("device encryption status output for %s is badly formatted: %s",
|
||
|
devicePath, lines[i])
|
||
|
}
|
||
|
if strings.Compare(kv[0], "device") == 0 {
|
||
|
return strings.TrimSpace(kv[1]), mapPath, nil
|
||
|
}
|
||
|
}
|
||
|
// Identified as LUKS, but failed to identify a mapped device
|
||
|
return "", "", fmt.Errorf("mapped device not found in path %s", devicePath)
|
||
|
}
|
||
|
|
||
|
// CheckRbdImageEncrypted verifies if rbd image was encrypted when created
|
||
|
func CheckRbdImageEncrypted(ctx context.Context, cr *Credentials, monitors, imageSpec string) (string, error) {
|
||
|
value, err := GetImageMeta(ctx, cr, monitors, imageSpec, encryptionMetaKey)
|
||
|
if err != nil {
|
||
|
klog.Errorf(Log(ctx, "checking image %s encrypted state metadata failed: %s"), imageSpec, err)
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
encrypted := strings.TrimSpace(value)
|
||
|
klog.V(4).Infof(Log(ctx, "image %s encrypted state metadata reports %q"), imageSpec, encrypted)
|
||
|
return encrypted, nil
|
||
|
}
|
||
|
|
||
|
// SaveRbdImageEncryptionStatus sets image metadata for encryption status
|
||
|
func SaveRbdImageEncryptionStatus(ctx context.Context, cr *Credentials, monitors, imageSpec, status string) error {
|
||
|
err := SetImageMeta(ctx, cr, monitors, imageSpec, encryptionMetaKey, status)
|
||
|
if err != nil {
|
||
|
err = fmt.Errorf("failed to save image metadata encryption status for %s: %v", imageSpec, err.Error())
|
||
|
klog.Errorf(Log(ctx, err.Error()))
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|