1{
2 lib,
3 pkgs,
4 config,
5 ...
6}:
7let
8 inherit (lib)
9 getExe'
10 mkEnableOption
11 mkIf
12 mkOption
13 mkPackageOption
14 types
15 ;
16
17 cfg = config.services.firezone.gui-client;
18in
19{
20 options = {
21 services.firezone.gui-client = {
22 enable = mkEnableOption "the firezone gui client";
23 package = mkPackageOption pkgs "firezone-gui-client" { };
24
25 allowedUsers = mkOption {
26 type = types.listOf types.str;
27 default = [ ];
28 description = ''
29 All listed users will become part of the `firezone-client` group so
30 they can control the tunnel service. This is a convenience option.
31 '';
32 };
33
34 name = mkOption {
35 type = types.str;
36 description = "The name of this client as shown in firezone";
37 };
38
39 logLevel = mkOption {
40 type = types.str;
41 default = "info";
42 description = ''
43 The log level for the firezone application. See
44 [RUST_LOG](https://docs.rs/env_logger/latest/env_logger/#enabling-logging)
45 for the format.
46 '';
47 };
48 };
49 };
50
51 config = mkIf cfg.enable {
52 users.groups.firezone-client.members = cfg.allowedUsers;
53
54 # Required for deep-link mimetype registration
55 environment.systemPackages = [ cfg.package ];
56
57 # Required for the token store in the gui application
58 services.gnome.gnome-keyring.enable = true;
59
60 systemd.services.firezone-tunnel-service = {
61 description = "GUI tunnel service for the Firezone zero-trust access platform";
62 after = [ "network.target" ];
63 wantedBy = [ "multi-user.target" ];
64
65 path = [ pkgs.util-linux ];
66 script = ''
67 # If FIREZONE_ID is not given by the user, use a persisted (or newly generated) uuid.
68 if [[ -z "''${FIREZONE_ID:-}" ]]; then
69 if [[ ! -e client_id ]]; then
70 uuidgen -r > client_id
71 fi
72 export FIREZONE_ID=$(< client_id)
73 fi
74
75 exec ${getExe' cfg.package "firezone-client-tunnel"} run
76 '';
77
78 environment = {
79 FIREZONE_NAME = cfg.name;
80 LOG_DIR = "%L/dev.firezone.client";
81 RUST_LOG = cfg.logLevel;
82 };
83
84 serviceConfig = {
85 Type = "notify";
86
87 DeviceAllow = "/dev/net/tun";
88 AmbientCapabilities = [ "CAP_NET_ADMIN" ];
89 CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
90
91 # This block contains hardcoded values in the client, we cannot change these :(
92 Group = "firezone-client";
93 RuntimeDirectory = "dev.firezone.client";
94 StateDirectory = "dev.firezone.client";
95 WorkingDirectory = "/var/lib/dev.firezone.client";
96 LogsDirectory = "dev.firezone.client";
97
98 Restart = "on-failure";
99 RestartSec = 10;
100
101 LockPersonality = true;
102 MemoryDenyWriteExecute = true;
103 NoNewPrivileges = true;
104 PrivateMounts = true;
105 PrivateTmp = true;
106 PrivateUsers = false;
107 ProcSubset = "pid";
108 ProtectClock = true;
109 ProtectControlGroups = true;
110 ProtectHome = true;
111 ProtectHostname = true;
112 ProtectKernelLogs = true;
113 ProtectKernelModules = true;
114 ProtectKernelTunables = true;
115 ProtectProc = "invisible";
116 ProtectSystem = "strict";
117 RestrictAddressFamilies = [
118 "AF_INET"
119 "AF_INET6"
120 "AF_NETLINK"
121 "AF_UNIX"
122 ];
123 RestrictNamespaces = true;
124 RestrictRealtime = true;
125 RestrictSUIDSGID = true;
126 SystemCallArchitectures = "native";
127 SystemCallFilter = "@system-service";
128 UMask = "077";
129 };
130 };
131 };
132
133 meta.maintainers = with lib.maintainers; [
134 oddlama
135 patrickdag
136 ];
137}