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