mirror of
https://github.com/Mic92/sops-nix.git
synced 2025-03-16 05:28:15 +00:00
Re-add service restarts
We also have service reloads now, so add them as well
This commit is contained in:
parent
4e21493d34
commit
5e2f743edd
5 changed files with 135 additions and 90 deletions
14
README.md
14
README.md
|
@ -562,6 +562,20 @@ the service needs a token and a SSH private key to function.</summary>
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## Restarting/reloading systemd units on secret change
|
||||||
|
|
||||||
|
**With NixOS 22.05**, it is possible to restart or reload units when a secret changes or is newly initialized.
|
||||||
|
|
||||||
|
This behavior can be configured per-secret:
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
sops.secrets."home-assistant-secrets.yaml" = {
|
||||||
|
restartUnits = [ "home-assistant.service" ];
|
||||||
|
# there is also `reloadUnits` which acts like a `reloadTrigger` in a NixOS systemd service
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Symlinks to other directories
|
## Symlinks to other directories
|
||||||
|
|
||||||
Some services might expect files in certain locations.
|
Some services might expect files in certain locations.
|
||||||
|
|
|
@ -92,6 +92,15 @@ let
|
||||||
This works the same way as <xref linkend="opt-systemd.services._name_.restartTriggers" />.
|
This works the same way as <xref linkend="opt-systemd.services._name_.restartTriggers" />.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
reloadUnits = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "sshd.service" ];
|
||||||
|
description = ''
|
||||||
|
Names of units that should be reloaded when this secret changes.
|
||||||
|
This works the same way as <xref linkend="opt-systemd.services._name_.reloadTriggers" />.
|
||||||
|
'';
|
||||||
|
};
|
||||||
neededForUsers = mkOption {
|
neededForUsers = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
|
@ -36,6 +36,7 @@ type secret struct {
|
||||||
Format FormatType `json:"format"`
|
Format FormatType `json:"format"`
|
||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
RestartUnits []string `json:"restartUnits"`
|
RestartUnits []string `json:"restartUnits"`
|
||||||
|
ReloadUnits []string `json:"reloadUnits"`
|
||||||
value []byte
|
value []byte
|
||||||
mode os.FileMode
|
mode os.FileMode
|
||||||
owner int
|
owner int
|
||||||
|
@ -679,6 +680,7 @@ func symlinkWalk(filename string, linkDirname string, walkFn filepath.WalkFunc)
|
||||||
|
|
||||||
func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, secretDir string, secrets []secret) error {
|
func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, secretDir string, secrets []secret) error {
|
||||||
var restart []string
|
var restart []string
|
||||||
|
var reload []string
|
||||||
|
|
||||||
newSecrets := make(map[string]bool)
|
newSecrets := make(map[string]bool)
|
||||||
modifiedSecrets := make(map[string]bool)
|
modifiedSecrets := make(map[string]bool)
|
||||||
|
@ -702,6 +704,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
// File did not exist before
|
// File did not exist before
|
||||||
restart = append(restart, secret.RestartUnits...)
|
restart = append(restart, secret.RestartUnits...)
|
||||||
|
reload = append(reload, secret.ReloadUnits...)
|
||||||
newSecrets[secret.Name] = true
|
newSecrets[secret.Name] = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -716,6 +719,7 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
|
||||||
|
|
||||||
if !bytes.Equal(oldData, newData) {
|
if !bytes.Equal(oldData, newData) {
|
||||||
restart = append(restart, secret.RestartUnits...)
|
restart = append(restart, secret.RestartUnits...)
|
||||||
|
reload = append(reload, secret.ReloadUnits...)
|
||||||
modifiedSecrets[secret.Name] = true
|
modifiedSecrets[secret.Name] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,6 +748,9 @@ func handleModifications(isDry bool, logcfg loggingConfig, symlinkPath string, s
|
||||||
if err := writeLines(restart, dryPrefix+"-restart-list"); err != nil {
|
if err := writeLines(restart, dryPrefix+"-restart-list"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := writeLines(reload, dryPrefix+"-reload-list"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Do not output changes if not requested
|
// Do not output changes if not requested
|
||||||
if !logcfg.SecretChanges {
|
if !logcfg.SecretChanges {
|
||||||
|
|
|
@ -107,6 +107,7 @@ func testGPG(t *testing.T) {
|
||||||
Path: path.Join(testdir.path, "test-target"),
|
Path: path.Join(testdir.path, "test-target"),
|
||||||
Mode: "0400",
|
Mode: "0400",
|
||||||
RestartUnits: []string{"affected-service"},
|
RestartUnits: []string{"affected-service"},
|
||||||
|
ReloadUnits: []string{"affected-reload-service"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonSecret, binarySecret secret
|
var jsonSecret, binarySecret secret
|
||||||
|
@ -205,6 +206,7 @@ func testSSHKey(t *testing.T) {
|
||||||
Path: target,
|
Path: target,
|
||||||
Mode: "0400",
|
Mode: "0400",
|
||||||
RestartUnits: []string{"affected-service"},
|
RestartUnits: []string{"affected-service"},
|
||||||
|
ReloadUnits: []string{"affected-reload-service"},
|
||||||
}
|
}
|
||||||
|
|
||||||
m := manifest{
|
m := manifest{
|
||||||
|
@ -237,6 +239,7 @@ func TestAge(t *testing.T) {
|
||||||
Path: target,
|
Path: target,
|
||||||
Mode: "0400",
|
Mode: "0400",
|
||||||
RestartUnits: []string{"affected-service"},
|
RestartUnits: []string{"affected-service"},
|
||||||
|
ReloadUnits: []string{"affected-reload-service"},
|
||||||
}
|
}
|
||||||
|
|
||||||
m := manifest{
|
m := manifest{
|
||||||
|
@ -269,6 +272,7 @@ func TestAgeWithSSH(t *testing.T) {
|
||||||
Path: target,
|
Path: target,
|
||||||
Mode: "0400",
|
Mode: "0400",
|
||||||
RestartUnits: []string{"affected-service"},
|
RestartUnits: []string{"affected-service"},
|
||||||
|
ReloadUnits: []string{"affected-reload-service"},
|
||||||
}
|
}
|
||||||
|
|
||||||
m := manifest{
|
m := manifest{
|
||||||
|
@ -302,6 +306,7 @@ func TestValidateManifest(t *testing.T) {
|
||||||
Path: path.Join(testdir.path, "test-target"),
|
Path: path.Join(testdir.path, "test-target"),
|
||||||
Mode: "0400",
|
Mode: "0400",
|
||||||
RestartUnits: []string{},
|
RestartUnits: []string{},
|
||||||
|
ReloadUnits: []string{},
|
||||||
}
|
}
|
||||||
|
|
||||||
m := manifest{
|
m := manifest{
|
||||||
|
|
|
@ -204,109 +204,119 @@
|
||||||
inherit (pkgs) system;
|
inherit (pkgs) system;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // pkgs.lib.optionalAttrs (pkgs.lib.versionAtLeast (pkgs.lib.versions.majorMinor pkgs.lib.version) "21.11") {
|
} // pkgs.lib.optionalAttrs (pkgs.lib.versionAtLeast (pkgs.lib.versions.majorMinor pkgs.lib.version) "22.05") {
|
||||||
# This feature got reverted in nixpkgs...
|
restart-and-reload = makeTest {
|
||||||
#restart-and-reload = makeTest {
|
name = "sops-restart-and-reload";
|
||||||
# name = "sops-restart-and-reload";
|
machine = { pkgs, lib, config, ... }: {
|
||||||
# machine = { pkgs, lib, config, ... }: {
|
imports = [
|
||||||
# imports = [
|
../../modules/sops
|
||||||
# ../../modules/sops
|
];
|
||||||
# ];
|
|
||||||
|
|
||||||
# sops = {
|
sops = {
|
||||||
# age.keyFile = ./test-assets/age-keys.txt;
|
age.keyFile = ./test-assets/age-keys.txt;
|
||||||
# defaultSopsFile = ./test-assets/secrets.yaml;
|
defaultSopsFile = ./test-assets/secrets.yaml;
|
||||||
# secrets.test_key = {
|
secrets.test_key = {
|
||||||
# restartUnits = [ "restart-unit.service" "reload-unit.service" ];
|
restartUnits = [ "restart-unit.service" "reload-unit.service" ];
|
||||||
# };
|
reloadUnits = [ "reload-trigger.service" ];
|
||||||
# };
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# systemd.services."restart-unit" = {
|
systemd.services."restart-unit" = {
|
||||||
# description = "Restart unit";
|
description = "Restart unit";
|
||||||
# # not started on boot
|
# not started on boot
|
||||||
# serviceConfig = {
|
serviceConfig = {
|
||||||
# ExecStart = "/bin/sh -c 'echo ok > /restarted'";
|
ExecStart = "/bin/sh -c 'echo ok > /restarted'";
|
||||||
# };
|
};
|
||||||
# };
|
};
|
||||||
# systemd.services."reload-unit" = {
|
systemd.services."reload-unit" = {
|
||||||
# description = "Restart unit";
|
description = "Reload unit";
|
||||||
# wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
# reloadIfChanged = true;
|
reloadIfChanged = true;
|
||||||
# serviceConfig = {
|
serviceConfig = {
|
||||||
# Type = "oneshot";
|
Type = "oneshot";
|
||||||
# RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
# ExecStart = "/bin/sh -c true";
|
ExecStart = "/bin/sh -c true";
|
||||||
# ExecReload = "/bin/sh -c 'echo ok > /reloaded'";
|
ExecReload = "/bin/sh -c 'echo ok > /reloaded'";
|
||||||
# };
|
};
|
||||||
# };
|
};
|
||||||
# };
|
systemd.services."reload-trigger" = {
|
||||||
# testScript = ''
|
description = "Reload trigger unit";
|
||||||
# machine.wait_for_unit("multi-user.target")
|
wantedBy = [ "multi-user.target" ];
|
||||||
# machine.fail("test -f /restarted")
|
serviceConfig = {
|
||||||
# machine.fail("test -f /reloaded")
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = "/bin/sh -c true";
|
||||||
|
ExecReload = "/bin/sh -c 'echo ok > /reloaded'";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
machine.fail("test -f /restarted")
|
||||||
|
machine.fail("test -f /reloaded")
|
||||||
|
|
||||||
# # Nothing is to be restarted after boot
|
# Nothing is to be restarted after boot
|
||||||
# machine.fail("ls /run/nixos/*-list")
|
machine.fail("ls /run/nixos/*-list")
|
||||||
|
|
||||||
# # Nothing happens when the secret is not changed
|
# Nothing happens when the secret is not changed
|
||||||
# machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
# machine.fail("test -f /restarted")
|
machine.fail("test -f /restarted")
|
||||||
# machine.fail("test -f /reloaded")
|
machine.fail("test -f /reloaded")
|
||||||
|
|
||||||
# # Ensure the secret is changed
|
# Ensure the secret is changed
|
||||||
# machine.succeed(": > /run/secrets/test_key")
|
machine.succeed(": > /run/secrets/test_key")
|
||||||
|
|
||||||
# # The secret is changed, now something should happen
|
# The secret is changed, now something should happen
|
||||||
# machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
|
|
||||||
# # Ensure something happened
|
# Ensure something happened
|
||||||
# machine.succeed("test -f /restarted")
|
machine.succeed("test -f /restarted")
|
||||||
# machine.succeed("test -f /reloaded")
|
machine.succeed("test -f /reloaded")
|
||||||
|
|
||||||
# with subtest("change detection"):
|
with subtest("change detection"):
|
||||||
# machine.succeed("rm /run/secrets/test_key")
|
machine.succeed("rm /run/secrets/test_key")
|
||||||
# out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
# if "adding secret" not in out:
|
if "adding secret" not in out:
|
||||||
# raise Exception("Addition detection does not work")
|
raise Exception("Addition detection does not work")
|
||||||
|
|
||||||
# machine.succeed(": > /run/secrets/test_key")
|
machine.succeed(": > /run/secrets/test_key")
|
||||||
# out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
# if "modifying secret" not in out:
|
if "modifying secret" not in out:
|
||||||
# raise Exception("Modification detection does not work")
|
raise Exception("Modification detection does not work")
|
||||||
|
|
||||||
# machine.succeed(": > /run/secrets/another_key")
|
machine.succeed(": > /run/secrets/another_key")
|
||||||
# out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
out = machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
# if "removing secret" not in out:
|
if "removing secret" not in out:
|
||||||
# raise Exception("Removal detection does not work")
|
raise Exception("Removal detection does not work")
|
||||||
|
|
||||||
# with subtest("dry activation"):
|
with subtest("dry activation"):
|
||||||
# machine.succeed("rm /run/secrets/test_key")
|
machine.succeed("rm /run/secrets/test_key")
|
||||||
# machine.succeed(": > /run/secrets/another_key")
|
machine.succeed(": > /run/secrets/another_key")
|
||||||
# out = machine.succeed("/run/current-system/bin/switch-to-configuration dry-activate")
|
out = machine.succeed("/run/current-system/bin/switch-to-configuration dry-activate")
|
||||||
# if "would add secret" not in out:
|
if "would add secret" not in out:
|
||||||
# raise Exception("Dry addition detection does not work")
|
raise Exception("Dry addition detection does not work")
|
||||||
# if "would remove secret" not in out:
|
if "would remove secret" not in out:
|
||||||
# raise Exception("Dry removal detection does not work")
|
raise Exception("Dry removal detection does not work")
|
||||||
|
|
||||||
# machine.fail("test -f /run/secrets/test_key")
|
machine.fail("test -f /run/secrets/test_key")
|
||||||
# machine.succeed("test -f /run/secrets/another_key")
|
machine.succeed("test -f /run/secrets/another_key")
|
||||||
|
|
||||||
# machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
machine.succeed("/run/current-system/bin/switch-to-configuration test")
|
||||||
# machine.succeed("test -f /run/secrets/test_key")
|
machine.succeed("test -f /run/secrets/test_key")
|
||||||
# machine.succeed("rm /restarted /reloaded")
|
machine.succeed("rm /restarted /reloaded")
|
||||||
# machine.fail("test -f /run/secrets/another_key")
|
machine.fail("test -f /run/secrets/another_key")
|
||||||
|
|
||||||
# machine.succeed(": > /run/secrets/test_key")
|
machine.succeed(": > /run/secrets/test_key")
|
||||||
# out = machine.succeed("/run/current-system/bin/switch-to-configuration dry-activate")
|
out = machine.succeed("/run/current-system/bin/switch-to-configuration dry-activate")
|
||||||
# if "would modify secret" not in out:
|
if "would modify secret" not in out:
|
||||||
# raise Exception("Dry modification detection does not work")
|
raise Exception("Dry modification detection does not work")
|
||||||
# machine.succeed("[ $(cat /run/secrets/test_key | wc -c) = 0 ]")
|
machine.succeed("[ $(cat /run/secrets/test_key | wc -c) = 0 ]")
|
||||||
|
|
||||||
# machine.fail("test -f /restarted") # not done in dry mode
|
machine.fail("test -f /restarted") # not done in dry mode
|
||||||
# machine.fail("test -f /reloaded") # not done in dry mode
|
machine.fail("test -f /reloaded") # not done in dry mode
|
||||||
# '';
|
'';
|
||||||
#} {
|
} {
|
||||||
# inherit pkgs;
|
inherit pkgs;
|
||||||
# inherit (pkgs) system;
|
inherit (pkgs) system;
|
||||||
#};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue