mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-05-09 09:45:35 -04:00
disk-mapper: systemd cryptsetup unit for state disk
This commit is contained in:
parent
0892525915
commit
da41cb6962
6 changed files with 311 additions and 87 deletions
113
state/internal/systemd/systemd.go
Normal file
113
state/internal/systemd/systemd.go
Normal file
|
@ -0,0 +1,113 @@
|
|||
package systemd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
const (
|
||||
systemdRuntimeUnitPath = "/run/systemd/system"
|
||||
systemdUnitName = "systemd-cryptsetup@state.service"
|
||||
systemdDeviceRequires = "dev-mapper-state.device.requires"
|
||||
systemdCryptsetupTargetRequires = "cryptsetup.target.requires"
|
||||
)
|
||||
|
||||
// CryptsetupUnitGenerator generates systemd-cryptsetup@.service unit files.
|
||||
type CryptsetupUnitGenerator struct {
|
||||
fs afero.Afero
|
||||
}
|
||||
|
||||
// New returns a new CryptsetupUnitGenerator.
|
||||
func New(fs afero.Afero) CryptsetupUnitGenerator {
|
||||
return CryptsetupUnitGenerator{fs: fs}
|
||||
}
|
||||
|
||||
// Generate generates a systemd-cryptsetup@.service unit file and its dependencies.
|
||||
func (g CryptsetupUnitGenerator) Generate(volumeName, encryptedDevice, keyFile, options string) error {
|
||||
unitContents, err := g.configureUnit(volumeName, encryptedDevice, keyFile, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return g.writeUnits(unitContents)
|
||||
}
|
||||
|
||||
// configureUnit generates the systemd-cryptsetup@.service unit file contents.
|
||||
func (g CryptsetupUnitGenerator) configureUnit(volumeName, encryptedDevice, keyFile, options string) (string, error) {
|
||||
deviceUnit := strings.ReplaceAll(encryptedDevice, "/", "-") + ".device"
|
||||
deviceUnit = strings.TrimPrefix(deviceUnit, "-")
|
||||
templ, err := template.New("").Parse(`[Unit]
|
||||
Description=Cryptography Setup for %I
|
||||
Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)
|
||||
DefaultDependencies=no
|
||||
IgnoreOnIsolate=true
|
||||
After=cryptsetup-pre.target systemd-udevd-kernel.socket
|
||||
Before=blockdev@dev-mapper-%i.target
|
||||
Wants=blockdev@dev-mapper-%i.target
|
||||
Conflicts=umount.target
|
||||
Before=cryptsetup.target
|
||||
RequiresMountsFor={{.keyFile}}
|
||||
BindsTo={{.deviceUnit}}
|
||||
After={{.deviceUnit}}
|
||||
Before=umount.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
TimeoutSec=0
|
||||
KeyringMode=shared
|
||||
OOMScoreAdjust=500
|
||||
ExecStart=/usr/lib/systemd/systemd-cryptsetup attach '{{.volumeName}}' '{{.encryptedDevice}}' '{{.keyFile}}' '{{.options}}'
|
||||
ExecStop=/usr/lib/systemd/systemd-cryptsetup detach '{{.volumeName}}'
|
||||
`)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = templ.Execute(&buf, map[string]string{
|
||||
"volumeName": volumeName,
|
||||
"encryptedDevice": encryptedDevice,
|
||||
"deviceUnit": deviceUnit,
|
||||
"keyFile": keyFile,
|
||||
"options": options,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// writeUnits writes the unit file and its dependencies to the filesystem.
|
||||
func (g CryptsetupUnitGenerator) writeUnits(unitContents string) error {
|
||||
if err := g.fs.MkdirAll(systemdRuntimeUnitPath, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.fs.Mkdir(filepath.Join(systemdRuntimeUnitPath, systemdDeviceRequires), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.fs.Mkdir(filepath.Join(systemdRuntimeUnitPath, systemdCryptsetupTargetRequires), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
unitPath := filepath.Join(systemdRuntimeUnitPath, systemdUnitName)
|
||||
if err := g.fs.WriteFile(unitPath, []byte(unitContents), 0o444); err != nil {
|
||||
return err
|
||||
}
|
||||
if symlinker, ok := g.fs.Fs.(afero.Symlinker); ok {
|
||||
if err := symlinker.SymlinkIfPossible(unitPath, filepath.Join(systemdRuntimeUnitPath, systemdDeviceRequires, systemdUnitName)); err != nil {
|
||||
return fmt.Errorf("creating device symlink: %w", err)
|
||||
}
|
||||
if err := symlinker.SymlinkIfPossible(unitPath, filepath.Join(systemdRuntimeUnitPath, systemdCryptsetupTargetRequires, systemdUnitName)); err != nil {
|
||||
return fmt.Errorf("creating cryptsetup target symlink: %w", err)
|
||||
}
|
||||
} else {
|
||||
return errors.New("fs does not support symlinks")
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue