1{ pkgs, ... }:
2{
3 name = "tang";
4 meta = with pkgs.lib.maintainers; {
5 maintainers = [ jfroche ];
6 };
7
8 nodes.server =
9 {
10 config,
11 pkgs,
12 modulesPath,
13 ...
14 }:
15 {
16 imports = [
17 "${modulesPath}/../tests/common/auto-format-root-device.nix"
18 ];
19 virtualisation = {
20 emptyDiskImages = [ 512 ];
21 useBootLoader = true;
22 useEFIBoot = true;
23 # This requires to have access
24 # to a host Nix store as
25 # the new root device is /dev/vdb
26 # an empty 512MiB drive, containing no Nix store.
27 mountHostNixStore = true;
28 };
29
30 boot.loader.systemd-boot.enable = true;
31
32 networking.interfaces.eth1.ipv4.addresses = [
33 {
34 address = "192.168.0.1";
35 prefixLength = 24;
36 }
37 ];
38
39 environment.systemPackages = with pkgs; [
40 clevis
41 tang
42 cryptsetup
43 ];
44 services.tang = {
45 enable = true;
46 ipAddressAllow = [ "127.0.0.1/32" ];
47 };
48 };
49 testScript = ''
50 start_all()
51 machine.wait_for_unit("sockets.target")
52
53 with subtest("Check keys are generated"):
54 machine.wait_until_succeeds("curl -v http://127.0.0.1:7654/adv")
55 key = machine.wait_until_succeeds("tang-show-keys 7654")
56
57 with subtest("Check systemd access list"):
58 machine.succeed("ping -c 3 192.168.0.1")
59 machine.fail("curl -v --connect-timeout 3 http://192.168.0.1:7654/adv")
60
61 with subtest("Check basic encrypt and decrypt message"):
62 machine.wait_until_succeeds(f"""echo 'Hello World' | clevis encrypt tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}"}}' > /tmp/encrypted""")
63 decrypted = machine.wait_until_succeeds("clevis decrypt < /tmp/encrypted")
64 assert decrypted.strip() == "Hello World"
65 machine.wait_until_succeeds("tang-show-keys 7654")
66
67 with subtest("Check encrypt and decrypt disk"):
68 machine.succeed("cryptsetup luksFormat --force-password --batch-mode /dev/vdb <<<'password'")
69 machine.succeed(f"""clevis luks bind -s1 -y -f -d /dev/vdb tang '{{ "url": "http://127.0.0.1:7654", "thp":"{key}" }}' <<< 'password' """)
70 clevis_luks = machine.succeed("clevis luks list -d /dev/vdb")
71 assert clevis_luks.strip() == """1: tang '{"url":"http://127.0.0.1:7654"}'"""
72 machine.succeed("clevis luks unlock -d /dev/vdb")
73 machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
74 machine.succeed("clevis luks unlock -d /dev/vdb")
75 machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
76 # without tang available, unlock should fail
77 machine.succeed("systemctl stop tangd.socket")
78 machine.fail("clevis luks unlock -d /dev/vdb")
79 machine.succeed("systemctl start tangd.socket")
80
81 with subtest("Rotate server keys"):
82 machine.succeed("${pkgs.tang}/libexec/tangd-rotate-keys -d /var/lib/tang")
83 machine.succeed("clevis luks unlock -d /dev/vdb")
84 machine.succeed("find /dev/mapper -name 'luks*' -exec cryptsetup close {} +")
85
86 with subtest("Test systemd service security"):
87 output = machine.succeed("systemd-analyze security tangd@.service")
88 machine.log(output)
89 assert output[-9:-1] == "SAFE :-}"
90 '';
91}