Skip to content

Commit

Permalink
fixup! initializer/cryptsetup: add setupEncryptedMount
Browse files Browse the repository at this point in the history
  • Loading branch information
jmxnzo committed Jan 15, 2025
1 parent 80bc000 commit a715e67
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 75 deletions.
7 changes: 6 additions & 1 deletion initializer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import (
"github.com/edgelesssys/contrast/internal/meshapi"
)

const (
// workloadSecretPath is fixed path to the Contrast workload secret.
workloadSecretPath = "/contrast/secrets/workload-secret-seed"
)

func main() {
if err := run(); err != nil {
os.Exit(1)
Expand Down Expand Up @@ -127,7 +132,7 @@ func run() (retErr error) {
if err != nil {
return fmt.Errorf("writing coordinator-root-ca.pem: %w", err)
}
err = os.WriteFile("/contrast/secrets/workload-secret-seed", []byte(hex.EncodeToString(resp.WorkloadSecret)), 0o400)
err = os.WriteFile(workloadSecretPath, []byte(hex.EncodeToString(resp.WorkloadSecret)), 0o400)
if err != nil {
return fmt.Errorf("writing workload-secret-seed: %w", err)
}
Expand Down
127 changes: 53 additions & 74 deletions initializer/mount.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright 2024 Edgeless Systems GmbH
// SPDX-License-Identifier: AGPL-3.0-only

// TODO drop this again adding subcommand
//
//nolint:unused
package main

import (
Expand All @@ -10,71 +13,69 @@ import (
"log/slog"
"os"
"os/exec"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
)

const (
// TODO(jmxnzo) don't hardcode these, add struct EncryptedMount as parameter to setupEncryptedMount function
// TODO follow naming convention that /dev/mapper/{x} is remounted to /{x}
// csiDevicePath is the path to the block device to be encrypted.
csiDevicePath = "/dev/csi0"

mapperDeviceMountPoint = "state"
// workloadSecretPath is the path to the Contrast workload secret.
workloadSecretPath = "/contrast/secrets/workload-secret-seed"


// tmp_key_path is the path to a temporary key file.
tmpKeyPath = "/dev/shm/key"
// disk_encryption_key_path is the path to the disk encryption key.
diskEncryptionKeyPath = "/dev/shm/disk-key"
// tmpPassphrase is the path to a temporary passphrase file, used for initial formatting.
tmpPassphrase = "/dev/shm/key"
// encryptionPassphrase is the path to the disk encryption passphrase file.
encryptionPassphrase = "/dev/shm/disk-key"
)

type luksVolume struct {
devicePath string
mappingName string
volumeMountPath string
}

// TODO(jmxnzo) this should be a cobra command/ rework command
// SetupEncryptedMount sets up an encrypted LUKS volume mount using the specification of struct EncryptedMount handed in.
func setupEncryptedMount(ctx context.Context, logger *slog.Logger) error {
if !isLuks(ctx, logger, csiDevicePath) {
func setupEncryptedMount(ctx context.Context, logger *slog.Logger, luksVolume luksVolume) error {
if !isLuks(ctx, logger, luksVolume.devicePath) {
// TODO(jmxnzo) might just use stdin instead for the initial passphrase generation
if err := createInitPassphrase(tmpKeyPath); err != nil {
if err := createInitPassphrase(tmpPassphrase); err != nil {
return err
}
logger.Info("formatting csi device to LUKS with initial passphrase)")
if err := luksFormat(ctx, csiDevicePath, tmpKeyPath); err != nil {
return err
}

if err := setEncryptionPassphrase(ctx, csiDevicePath, workloadSecretPath, diskEncryptionKeyPath); err != nil {
// TODO(jmxnzo) check what happens if container is terminated in between formatting
if err := luksFormat(ctx, luksVolume.devicePath, tmpPassphrase); err != nil {
return err
}

if err := luksChangeKey(ctx, csiDevicePath, tmpKeyPath, diskEncryptionKeyPath); err != nil {
if err := createEncryptionPassphrase(ctx, luksVolume.devicePath, workloadSecretPath, encryptionPassphrase); err != nil {
return err
}

if err := openEncryptedDevice(ctx, csiDevicePath, diskEncryptionKeyPath, mapperDeviceMountPoint); err != nil {
if err := luksChangeKey(ctx, luksVolume.devicePath, tmpPassphrase, encryptionPassphrase); err != nil {
return err
}
} else {
if err := setEncryptionPassphrase(ctx, csiDevicePath, workloadSecretPath, diskEncryptionKeyPath); err != nil {
return err
}
if err := openEncryptedDevice(ctx, csiDevicePath, diskEncryptionKeyPath, mapperDeviceMountPoint); err != nil {
if err := createEncryptionPassphrase(ctx, luksVolume.devicePath, workloadSecretPath, encryptionPassphrase); err != nil {
return err
}
}
luksUUID(ctx, csiDevicePath)

if err := setupMount(ctx, logger, "/dev/mapper/"+mapperDeviceMountPoint, "/"+mapperDeviceMountPoint); err != nil {
if err := openEncryptedDevice(ctx, luksVolume.devicePath, encryptionPassphrase, luksVolume.mappingName); err != nil {
return err
}
file, err := os.Create("/done")
if err != nil {
if _, err := luksUUID(ctx, luksVolume.devicePath); err != nil {
return err
}
// The decrypted devices with <name> will always be mapped to /dev/mapper/<name> by default.
if err := setupMount(ctx, logger, "/dev/mapper/"+luksVolume.mappingName, luksVolume.volumeMountPath); err != nil {
return err
}

if err := os.WriteFile("/done", []byte(""), 0o644); err != nil {
return fmt.Errorf("Creating startup probe done directory:%w", err)
}
defer file.Close()
// Waits for SIGTERM signal and then properly release the resources.
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
<-signalChan

time.Sleep(10*time.Minute)
return nil
}

Expand Down Expand Up @@ -158,54 +159,38 @@ func mkfsExt4(ctx context.Context, devName string) error {
return nil
}


// createInitPassphrase creates a hardcoded string passphrase, to allow formatting the device to LUKS in order to get the UUID.
func createInitPassphrase(pathToPassphrase string) error {
file, err := os.Create(pathToPassphrase)
func createInitPassphrase(pathToPassphrase string) (err error) {
err = os.WriteFile(pathToPassphrase, []byte("init_passphrase"), 0o644)
if err != nil {
fmt.Println("Error creating file:", err)
return nil
}
defer file.Close()

_, err = file.WriteString("init_passphrase")
if err != nil {
fmt.Println("Error writing to file:", err)
return nil
return fmt.Errorf("Writing initial passphrase: %w", err)
}
return nil
}

// setEncryptionPassphrase writes the UUID of the device and the current workload secret to the diskEncryptionKeyPath used as passphrase.
func setEncryptionPassphrase(ctx context.Context, devName, workloadSecretPath, diskEncryptionKeyPath string) error {
// createEncryptionPassphrase writes the UUID of the device and the current workload secret to the pathToPassphrase.
func createEncryptionPassphrase(ctx context.Context, devName, workloadSecretPath, pathToPassphrase string) error {
blk, err := blkid(ctx, devName)
if err != nil {
return err
}
workloadSecretBytes, err := os.ReadFile(workloadSecretPath)
if err != nil {
return fmt.Errorf("Error reading file: %w", err)
return fmt.Errorf("reading workload secret: %w", err)
}
print(string(workloadSecretBytes))

diskEncryptionKey, err := os.Create(diskEncryptionKeyPath)
if err != nil {
return fmt.Errorf("creating file at %s: %w", diskEncryptionKeyPath, err)
}
defer diskEncryptionKey.Close()

_, err = diskEncryptionKey.WriteString(blk.UUID + string(workloadSecretBytes))
err = os.WriteFile(pathToPassphrase, []byte(blk.UUID+string(workloadSecretBytes)), 0o644)
if err != nil {
return fmt.Errorf("writing to %s: %w", diskEncryptionKeyPath, err)
return fmt.Errorf("writing encryption passphrase: %w", err)
}
return nil
}

// isLuks wraps the cryptsetup isLuks command and returns a bool reflecting if the device is formatted as LUKS.
func isLuks(ctx context.Context, logger *slog.Logger, devName string) bool {
cmd := exec.CommandContext(ctx, "cryptsetup", "isLuks", "--debug", devName)
out, err := cmd.CombinedOutput()
print(string(out))
_, err := cmd.CombinedOutput()
if err != nil {
logger.Info("cryptsetup isLuks failed", "error", err)
return false
Expand All @@ -215,47 +200,41 @@ func isLuks(ctx context.Context, logger *slog.Logger, devName string) bool {

// luksFormat wraps the luksFormat command.
func luksFormat(ctx context.Context, devName, pathToKey string) error {
cmd := exec.CommandContext(ctx, "cryptsetup", "luksFormat", "--pbkdf-memory=10240", devName, pathToKey, "</dev/null")
cmd := exec.CommandContext(ctx, "cryptsetup", "luksFormat", "--pbkdf-memory=10240", devName, pathToKey)
out, err := cmd.CombinedOutput()
print(string(out))
if err != nil {
return fmt.Errorf("cryptsetup luksFormat: %w, output: %q", err, out)
}
return nil
}

// openEncryptedDevice wraps the cryptsetup open command.
func openEncryptedDevice(ctx context.Context, devName, diskEncryptionKeyPath, mountPoint string) error {
cmd := exec.CommandContext(ctx, "cryptsetup", "open", devName, mountPoint, "-d", diskEncryptionKeyPath)
out, err := cmd.CombinedOutput()
func openEncryptedDevice(ctx context.Context, devName, diskEncryptionKeyPath, mappingName string) error {
cmd := exec.CommandContext(ctx, "cryptsetup", "open", devName, mappingName, "-d", diskEncryptionKeyPath)
_, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("cryptsetup open %s failed: %w", devName, err)
}

print(string(out))
return nil
}

// closeEncryptedDevice wraps the cryptsetup open command.
func closeEncryptedDevice(ctx context.Context, devName string) error {
cmd := exec.CommandContext(ctx, "cryptsetup", "close", devName)
out, err := cmd.CombinedOutput()
_, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("cryptsetup close %s failed: %w", devName, err)
}

print(string(out))
return nil
}

// luksChangeKey wraps the luksChangeKey command.
func luksChangeKey(ctx context.Context, devName, oldKeyPath, newKeyPath string) error {
cmd := exec.CommandContext(ctx, "cryptsetup", "luksChangeKey", "--pbkdf-memory=10240", devName, "--key-file", oldKeyPath, newKeyPath)
out, err := cmd.CombinedOutput()
_, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("cryptsetup luksChangeKey %s failed: %w", devName, err)
}
print(string(out))
return nil
}

Expand Down

0 comments on commit a715e67

Please sign in to comment.