nixos/tang: create module for tang server (#247037)
This commit adds a module for the tang server and the related nixos test.
This commit is contained in:
parent
301949dcf0
commit
fb3723fe52
5 changed files with 187 additions and 4 deletions
|
@ -1164,6 +1164,7 @@
|
|||
./services/security/sshguard.nix
|
||||
./services/security/sslmate-agent.nix
|
||||
./services/security/step-ca.nix
|
||||
./services/security/tang.nix
|
||||
./services/security/tor.nix
|
||||
./services/security/torify.nix
|
||||
./services/security/torsocks.nix
|
||||
|
|
95
nixos/modules/services/security/tang.nix
Normal file
95
nixos/modules/services/security/tang.nix
Normal file
|
@ -0,0 +1,95 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.tang;
|
||||
in
|
||||
{
|
||||
options.services.tang = {
|
||||
enable = mkEnableOption "tang";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.tang;
|
||||
defaultText = literalExpression "pkgs.tang";
|
||||
description = mdDoc "The tang package to use.";
|
||||
};
|
||||
|
||||
listenStream = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ "7654" ];
|
||||
example = [ "198.168.100.1:7654" "[2001:db8::1]:7654" "7654" ];
|
||||
description = mdDoc ''
|
||||
Addresses and/or ports on which tang should listen.
|
||||
For detailed syntax see ListenStream in {manpage}`systemd.socket(5)`.
|
||||
'';
|
||||
};
|
||||
|
||||
ipAddressAllow = mkOption {
|
||||
example = [ "192.168.1.0/24" ];
|
||||
type = types.listOf types.str;
|
||||
description = ''
|
||||
Whitelist a list of address prefixes.
|
||||
Preferably, internal addresses should be used.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
systemd.services."tangd@" = {
|
||||
description = "Tang server";
|
||||
path = [ cfg.package ];
|
||||
serviceConfig = {
|
||||
StandardInput = "socket";
|
||||
StandardOutput = "socket";
|
||||
StandardError = "journal";
|
||||
DynamicUser = true;
|
||||
StateDirectory = "tang";
|
||||
RuntimeDirectory = "tang";
|
||||
StateDirectoryMode = "700";
|
||||
UMask = "0077";
|
||||
CapabilityBoundingSet = [ "" ];
|
||||
ExecStart = "${cfg.package}/libexec/tangd %S/tang";
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
NoNewPrivileges = true;
|
||||
DeviceAllow = [ "/dev/stdin" ];
|
||||
RestrictAddressFamilies = [ "AF_UNIX" ];
|
||||
DevicePolicy = "strict";
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProcSubset = "pid";
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
|
||||
IPAddressDeny = "any";
|
||||
IPAddressAllow = cfg.ipAddressAllow;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.sockets.tangd = {
|
||||
description = "Tang server";
|
||||
wantedBy = [ "sockets.target" ];
|
||||
socketConfig = {
|
||||
ListenStream = cfg.listenStream;
|
||||
Accept = "yes";
|
||||
IPAddressDeny = "any";
|
||||
IPAddressAllow = cfg.ipAddressAllow;
|
||||
};
|
||||
};
|
||||
};
|
||||
meta.maintainers = with lib.maintainers; [ jfroche julienmalka ];
|
||||
}
|
|
@ -807,6 +807,7 @@ in {
|
|||
systemd-userdbd = handleTest ./systemd-userdbd.nix {};
|
||||
systemd-homed = handleTest ./systemd-homed.nix {};
|
||||
tandoor-recipes = handleTest ./tandoor-recipes.nix {};
|
||||
tang = handleTest ./tang.nix {};
|
||||
taskserver = handleTest ./taskserver.nix {};
|
||||
tayga = handleTest ./tayga.nix {};
|
||||
teeworlds = handleTest ./teeworlds.nix {};
|
||||
|
|
81
nixos/tests/tang.nix
Normal file
81
nixos/tests/tang.nix
Normal file
|
@ -0,0 +1,81 @@
|
|||
import ./make-test-python.nix ({ pkgs, ... }: {
|
||||
name = "tang";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ jfroche ];
|
||||
};
|
||||
|
||||
nodes.server =
|
||||
{ config
|
||||
, pkgs
|
||||
, modulesPath
|
||||
, ...
|
||||
}: {
|
||||
imports = [
|
||||
"${modulesPath}/../tests/common/auto-format-root-device.nix"
|
||||
];
|
||||
virtualisation = {
|
||||
emptyDiskImages = [ 512 ];
|
||||
useBootLoader = true;
|
||||
useEFIBoot = true;
|
||||
# This requires to have access
|
||||
# to a host Nix store as
|
||||
# the new root device is /dev/vdb
|
||||
# an empty 512MiB drive, containing no Nix store.
|
||||
mountHostNixStore = true;
|
||||
};
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
|
||||
networking.interfaces.eth1.ipv4.addresses = [
|
||||
{ address = "192.168.0.1"; prefixLength = 24; }
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [ clevis tang cryptsetup ];
|
||||
services.tang = {
|
||||
enable = true;
|
||||
ipAddressAllow = [ "127.0.0.1/32" ];
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.wait_for_unit("sockets.target")
|
||||
|
||||
with subtest("Check keys are generated"):
|
||||
machine.wait_until_succeeds("curl -v http://127.0.0.1:7654/adv")
|
||||
key = machine.wait_until_succeeds("tang-show-keys 7654")
|
||||
|
||||
with subtest("Check systemd access list"):
|
||||
machine.succeed("ping -c 3 192.168.0.1")
|
||||
machine.fail("curl -v --connect-timeout 3 http://192.168.0.1:7654/adv")
|
||||
|
||||
with subtest("Check basic encrypt and decrypt message"):
|
||||
machine.wait_until_succeeds(f"""echo 'Hello World' | clevis encrypt tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}"}}' > /tmp/encrypted""")
|
||||
decrypted = machine.wait_until_succeeds("clevis decrypt < /tmp/encrypted")
|
||||
assert decrypted.strip() == "Hello World"
|
||||
machine.wait_until_succeeds("tang-show-keys 7654")
|
||||
|
||||
with subtest("Check encrypt and decrypt disk"):
|
||||
machine.succeed("cryptsetup luksFormat --force-password --batch-mode /dev/vdb <<<'password'")
|
||||
machine.succeed(f"""clevis luks bind -s1 -y -f -d /dev/vdb tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}" }}' <<< 'password' """)
|
||||
clevis_luks = machine.succeed("clevis luks list -d /dev/vdb")
|
||||
assert clevis_luks.strip() == """1: tang '{"url":"http://127.0.0.1:7654"}'"""
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
# without tang available, unlock should fail
|
||||
machine.succeed("systemctl stop tangd.socket")
|
||||
machine.fail("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("systemctl start tangd.socket")
|
||||
|
||||
with subtest("Rotate server keys"):
|
||||
machine.succeed("${pkgs.tang}/libexec/tangd-rotate-keys -d /var/lib/tang")
|
||||
machine.succeed("clevis luks unlock -d /dev/vdb")
|
||||
machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
|
||||
|
||||
with subtest("Test systemd service security"):
|
||||
output = machine.succeed("systemd-analyze security tangd@.service")
|
||||
machine.log(output)
|
||||
assert output[-9:-1] == "SAFE :-}"
|
||||
'';
|
||||
})
|
|
@ -13,6 +13,7 @@
|
|||
, testers
|
||||
, tang
|
||||
, gitUpdater
|
||||
, nixosTests
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
|
@ -53,10 +54,13 @@ stdenv.mkDerivation rec {
|
|||
'';
|
||||
|
||||
passthru = {
|
||||
tests.version = testers.testVersion {
|
||||
package = tang;
|
||||
command = "${tang}/libexec/tangd --version";
|
||||
version = "tangd ${version}";
|
||||
tests = {
|
||||
inherit (nixosTests) tang;
|
||||
version = testers.testVersion {
|
||||
package = tang;
|
||||
command = "${tang}/libexec/tangd --version";
|
||||
version = "tangd ${version}";
|
||||
};
|
||||
};
|
||||
updateScript = gitUpdater { };
|
||||
};
|
||||
|
@ -67,5 +71,6 @@ stdenv.mkDerivation rec {
|
|||
changelog = "https://github.com/latchset/tang/releases/tag/v${version}";
|
||||
maintainers = with lib.maintainers; [ fpletz ];
|
||||
license = lib.licenses.gpl3Plus;
|
||||
mainProgram = "tangd";
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue