summary refs log tree commit diff
path: root/nixos/tests/podman-tls-ghostunnel.nix
blob: b5836c436497bf13b25b06be8fc2fe64482782b0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
  This test runs podman as a backend for the Docker CLI.
 */
import ./make-test-python.nix (
  { pkgs, lib, ... }:

  let gen-ca = pkgs.writeScript "gen-ca" ''
    # Create CA
    PATH="${pkgs.openssl}/bin:$PATH"
    openssl genrsa -out ca-key.pem 4096
    openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -subj '/C=NL/ST=Zuid-Holland/L=The Hague/O=Stevige Balken en Planken B.V./OU=OpSec/CN=Certificate Authority' -out ca.pem

    # Create service
    openssl genrsa -out podman-key.pem 4096
    openssl req -subj '/CN=podman' -sha256 -new -key podman-key.pem -out service.csr
    echo subjectAltName = DNS:podman,IP:127.0.0.1 >> extfile.cnf
    echo extendedKeyUsage = serverAuth >> extfile.cnf
    openssl x509 -req -days 365 -sha256 -in service.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out podman-cert.pem -extfile extfile.cnf

    # Create client
    openssl genrsa -out client-key.pem 4096
    openssl req -subj '/CN=client' -new -key client-key.pem -out client.csr
    echo extendedKeyUsage = clientAuth > extfile-client.cnf
    openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile extfile-client.cnf

    # Create CA 2
    PATH="${pkgs.openssl}/bin:$PATH"
    openssl genrsa -out ca-2-key.pem 4096
    openssl req -new -x509 -days 365 -key ca-2-key.pem -sha256 -subj '/C=NL/ST=Zuid-Holland/L=The Hague/O=Stevige Balken en Planken B.V./OU=OpSec/CN=Certificate Authority' -out ca-2.pem

    # Create client signed by CA 2
    openssl genrsa -out client-2-key.pem 4096
    openssl req -subj '/CN=client' -new -key client-2-key.pem -out client-2.csr
    echo extendedKeyUsage = clientAuth > extfile-client.cnf
    openssl x509 -req -days 365 -sha256 -in client-2.csr -CA ca-2.pem -CAkey ca-2-key.pem -CAcreateserial -out client-2-cert.pem -extfile extfile-client.cnf

    '';
  in
  {
    name = "podman-tls-ghostunnel";
    meta = {
      maintainers = lib.teams.podman.members ++ [ lib.maintainers.roberth ];
    };

    nodes = {
      podman =
        { pkgs, ... }:
        {
          virtualisation.podman.enable = true;
          virtualisation.podman.dockerSocket.enable = true;
          virtualisation.podman.networkSocket = {
            enable = true;
            openFirewall = true;
            server = "ghostunnel";
            tls.cert = "/root/podman-cert.pem";
            tls.key = "/root/podman-key.pem";
            tls.cacert = "/root/ca.pem";
          };

          environment.systemPackages = [
            pkgs.docker-client
          ];

          users.users.alice = {
            isNormalUser = true;
            home = "/home/alice";
            description = "Alice Foobar";
            extraGroups = ["podman"];
          };

        };

      client = { ... }: {
        environment.systemPackages = [
          # Installs the docker _client_ only
          # Normally, you'd want `virtualisation.docker.enable = true;`.
          pkgs.docker-client
        ];
        environment.variables.DOCKER_HOST = "podman:2376";
        environment.variables.DOCKER_TLS_VERIFY = "1";
      };
    };

    testScript = ''
      import shlex


      def su_cmd(user, cmd):
          cmd = shlex.quote(cmd)
          return f"su {user} -l -c {cmd}"

      def cmd(command):
        print(f"+{command}")
        r = os.system(command)
        if r != 0:
          raise Exception(f"Command {command} failed with exit code {r}")

      start_all()
      cmd("${gen-ca}")

      podman.copy_from_host("ca.pem", "/root/ca.pem")
      podman.copy_from_host("podman-cert.pem", "/root/podman-cert.pem")
      podman.copy_from_host("podman-key.pem", "/root/podman-key.pem")

      client.copy_from_host("ca.pem", "/root/.docker/ca.pem")
      # client.copy_from_host("podman-cert.pem", "/root/podman-cert.pem")
      client.copy_from_host("client-cert.pem", "/root/.docker/cert.pem")
      client.copy_from_host("client-key.pem", "/root/.docker/key.pem")

      # TODO (ghostunnel): add file watchers so the restart isn't necessary
      podman.succeed("systemctl reset-failed && systemctl restart ghostunnel-server-podman-socket.service")

      podman.wait_for_unit("sockets.target")
      podman.wait_for_unit("ghostunnel-server-podman-socket.service")

      with subtest("Create default network"):
          podman.succeed("docker network create default")

      with subtest("Root docker cli also works"):
          podman.succeed("docker version")

      with subtest("A podman member can also still use the docker cli"):
          podman.succeed(su_cmd("alice", "docker version"))

      with subtest("Run container remotely via docker cli"):
          client.succeed("docker version")

          # via socket would be nicer
          podman.succeed("tar cvf scratchimg.tar --files-from /dev/null && podman import scratchimg.tar scratchimg")

          client.succeed(
            "docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
          )
          client.succeed("docker ps | grep sleeping")
          podman.succeed("docker ps | grep sleeping")
          client.succeed("docker stop sleeping")
          client.succeed("docker rm sleeping")

      with subtest("Clients without cert will be denied"):
          client.succeed("rm /root/.docker/{cert,key}.pem")
          client.fail("docker version")

      with subtest("Clients with wrong cert will be denied"):
          client.copy_from_host("client-2-cert.pem", "/root/.docker/cert.pem")
          client.copy_from_host("client-2-key.pem", "/root/.docker/key.pem")
          client.fail("docker version")

    '';
  }
)