···
1
+
{ config, lib, pkgs, ... }:
4
+
cfg = config.services.gns3-server;
6
+
settingsFormat = pkgs.formats.ini { };
7
+
configFile = settingsFormat.generate "gns3-server.conf" cfg.settings;
11
+
doc = ./gns3-server.md;
12
+
maintainers = [ lib.maintainers.anthonyroussel ];
16
+
services.gns3-server = {
17
+
enable = lib.mkEnableOption (lib.mdDoc "GNS3 Server daemon");
19
+
package = lib.mkPackageOptionMD pkgs "gns3-server" { };
22
+
enable = lib.mkEnableOption (lib.mdDoc "password based HTTP authentication to access the GNS3 Server");
24
+
user = lib.mkOption {
25
+
type = lib.types.nullOr lib.types.str;
28
+
description = lib.mdDoc ''Username used to access the GNS3 Server.'';
31
+
passwordFile = lib.mkOption {
32
+
type = lib.types.nullOr lib.types.path;
34
+
example = "/run/secrets/gns3-server-password";
35
+
description = lib.mdDoc ''
36
+
A file containing the password to access the GNS3 Server.
39
+
This should be a string, not a nix path, since nix paths
40
+
are copied into the world-readable nix store.
46
+
settings = lib.mkOption {
47
+
type = lib.types.submodule { freeformType = settingsFormat.type; };
49
+
example = { host = "127.0.0.1"; port = 3080; };
50
+
description = lib.mdDoc ''
51
+
The global options in `config` file in ini format.
53
+
Refer to <https://docs.gns3.com/docs/using-gns3/administration/gns3-server-configuration-file/>
54
+
for all available options.
59
+
file = lib.mkOption {
60
+
type = lib.types.nullOr lib.types.path;
61
+
default = "/var/log/gns3/server.log";
62
+
description = lib.mdDoc ''Path of the file GNS3 Server should log to.'';
65
+
debug = lib.mkEnableOption (lib.mdDoc "debug logging");
69
+
enable = lib.mkEnableOption (lib.mdDoc "SSL encryption");
71
+
certFile = lib.mkOption {
72
+
type = lib.types.nullOr lib.types.path;
74
+
example = "/var/lib/gns3/ssl/server.pem";
75
+
description = lib.mdDoc ''
76
+
Path to the SSL certificate file. This certificate will
77
+
be offered to, and may be verified by, clients.
81
+
keyFile = lib.mkOption {
82
+
type = lib.types.nullOr lib.types.path;
84
+
example = "/var/lib/gns3/ssl/server.key";
85
+
description = lib.mdDoc "Private key file for the certificate.";
90
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable Dynamips support.'');
91
+
package = lib.mkPackageOptionMD pkgs "dynamips" { };
95
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable uBridge support.'');
96
+
package = lib.mkPackageOptionMD pkgs "ubridge" { };
100
+
enable = lib.mkEnableOption (lib.mdDoc ''Whether to enable VPCS support.'');
101
+
package = lib.mkPackageOptionMD pkgs "vpcs" { };
108
+
enableDocker = config.virtualisation.docker.enable;
109
+
enableLibvirtd = config.virtualisation.libvirtd.enable;
112
+
in lib.mkIf cfg.enable {
115
+
assertion = cfg.ssl.enable -> cfg.ssl.certFile != null;
116
+
message = "Please provide a certificate to use for SSL encryption.";
119
+
assertion = cfg.ssl.enable -> cfg.ssl.keyFile != null;
120
+
message = "Please provide a private key to use for SSL encryption.";
123
+
assertion = cfg.auth.enable -> cfg.auth.user != null;
124
+
message = "Please provide a username to use for HTTP authentication.";
127
+
assertion = cfg.auth.enable -> cfg.auth.passwordFile != null;
128
+
message = "Please provide a password file to use for HTTP authentication.";
132
+
users.groups.ubridge = lib.mkIf cfg.ubridge.enable { };
134
+
security.wrappers.ubridge = lib.mkIf cfg.ubridge.enable {
135
+
capabilities = "cap_net_raw,cap_net_admin=eip";
138
+
permissions = "u=rwx,g=rx,o=r";
139
+
source = lib.getExe cfg.ubridge.package;
142
+
services.gns3-server.settings = lib.mkMerge [
145
+
appliances_path = lib.mkDefault "/var/lib/gns3/appliances";
146
+
configs_path = lib.mkDefault "/var/lib/gns3/configs";
147
+
images_path = lib.mkDefault "/var/lib/gns3/images";
148
+
projects_path = lib.mkDefault "/var/lib/gns3/projects";
149
+
symbols_path = lib.mkDefault "/var/lib/gns3/symbols";
152
+
(lib.mkIf (cfg.ubridge.enable) {
153
+
Server.ubridge_path = lib.mkDefault (lib.getExe cfg.ubridge.package);
155
+
(lib.mkIf (cfg.auth.enable) {
157
+
auth = lib.mkDefault (lib.boolToString cfg.auth.enable);
158
+
user = lib.mkDefault cfg.auth.user;
159
+
password = lib.mkDefault "@AUTH_PASSWORD@";
162
+
(lib.mkIf (cfg.vpcs.enable) {
163
+
VPCS.vpcs_path = lib.mkDefault (lib.getExe cfg.vpcs.package);
165
+
(lib.mkIf (cfg.dynamips.enable) {
166
+
Dynamips.dynamips_path = lib.mkDefault (lib.getExe cfg.dynamips.package);
170
+
systemd.services.gns3-server = let
171
+
commandArgs = lib.cli.toGNUCommandLineShell { } {
172
+
config = "/etc/gns3/gns3_server.conf";
173
+
pid = "/run/gns3/server.pid";
174
+
log = cfg.log.file;
175
+
ssl = cfg.ssl.enable;
176
+
# These are implicitly not set if `null`
177
+
certfile = cfg.ssl.certFile;
178
+
certkey = cfg.ssl.keyFile;
182
+
description = "GNS3 Server";
184
+
after = [ "network.target" "network-online.target" ];
185
+
wantedBy = [ "multi-user.target" ];
186
+
wants = [ "network-online.target" ];
188
+
# configFile cannot be stored in RuntimeDirectory, because GNS3
189
+
# uses the `--config` base path to stores supplementary configuration files at runtime.
192
+
install -m660 ${configFile} /etc/gns3/gns3_server.conf
194
+
${lib.optionalString cfg.auth.enable ''
195
+
${pkgs.replace-secret}/bin/replace-secret \
196
+
'@AUTH_PASSWORD@' \
197
+
"''${CREDENTIALS_DIRECTORY}/AUTH_PASSWORD" \
198
+
/etc/gns3/gns3_server.conf
202
+
path = lib.optional flags.enableLibvirtd pkgs.qemu;
204
+
reloadTriggers = [ configFile ];
207
+
ConfigurationDirectory = "gns3";
208
+
ConfigurationDirectoryMode = "0750";
209
+
DynamicUser = true;
210
+
Environment = "HOME=%S/gns3";
211
+
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
212
+
ExecStart = "${lib.getExe cfg.package} ${commandArgs}";
214
+
LimitNOFILE = 16384;
215
+
LoadCredential = lib.mkIf cfg.auth.enable [ "AUTH_PASSWORD:${cfg.auth.passwordFile}" ];
216
+
LogsDirectory = "gns3";
217
+
LogsDirectoryMode = "0750";
218
+
PIDFile = "/run/gns3/server.pid";
219
+
Restart = "on-failure";
221
+
RuntimeDirectory = "gns3";
222
+
StateDirectory = "gns3";
223
+
StateDirectoryMode = "0750";
224
+
SupplementaryGroups = lib.optional flags.enableDocker "docker"
225
+
++ lib.optional flags.enableLibvirtd "libvirtd"
226
+
++ lib.optional cfg.ubridge.enable "ubridge";
228
+
WorkingDirectory = "%S/gns3";
231
+
DeviceAllow = lib.optional flags.enableLibvirtd "/dev/kvm";
232
+
DevicePolicy = "closed";
233
+
LockPersonality = true;
234
+
MemoryDenyWriteExecute = true;
235
+
NoNewPrivileges = true;
237
+
PrivateUsers = true;
238
+
# Don't restrict ProcSubset because python3Packages.psutil requires read access to /proc/stat
239
+
# ProcSubset = "pid";
240
+
ProtectClock = true;
241
+
ProtectControlGroups = true;
242
+
ProtectHome = true;
243
+
ProtectHostname = true;
244
+
ProtectKernelLogs = true;
245
+
ProtectKernelModules = true;
246
+
ProtectKernelTunables = true;
247
+
ProtectProc = "invisible";
248
+
ProtectSystem = "strict";
249
+
RestrictAddressFamilies = [
256
+
RestrictNamespaces = true;
257
+
RestrictRealtime = true;
258
+
RestrictSUIDSGID = true;