grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-apps / powerdns-admin.nix
blobd64c468a9cb5561a5df221059db71acc457dfa52
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.powerdns-admin;
8   configText = ''
9     ${cfg.config}
10   ''
11   + optionalString (cfg.secretKeyFile != null) ''
12     with open('${cfg.secretKeyFile}') as file:
13       SECRET_KEY = file.read()
14   ''
15   + optionalString (cfg.saltFile != null) ''
16     with open('${cfg.saltFile}') as file:
17       SALT = file.read()
18   '';
21   options.services.powerdns-admin = {
22     enable = mkEnableOption "the PowerDNS web interface";
24     extraArgs = mkOption {
25       type = types.listOf types.str;
26       default = [ ];
27       example = literalExpression ''
28         [ "-b" "127.0.0.1:8000" ]
29       '';
30       description = ''
31         Extra arguments passed to powerdns-admin.
32       '';
33     };
35     config = mkOption {
36       type = types.str;
37       default = "";
38       example = ''
39         BIND_ADDRESS = '127.0.0.1'
40         PORT = 8000
41         SQLALCHEMY_DATABASE_URI = 'postgresql://powerdnsadmin@/powerdnsadmin?host=/run/postgresql'
42       '';
43       description = ''
44         Configuration python file.
45         See [the example configuration](https://github.com/ngoduykhanh/PowerDNS-Admin/blob/v${pkgs.powerdns-admin.version}/configs/development.py)
46         for options.
47       '';
48     };
50     secretKeyFile = mkOption {
51       type = types.nullOr types.path;
52       example = "/etc/powerdns-admin/secret";
53       description = ''
54         The secret used to create cookies.
55         This needs to be set, otherwise the default is used and everyone can forge valid login cookies.
56         Set this to null to ignore this setting and configure it through another way.
57       '';
58     };
60     saltFile = mkOption {
61       type = types.nullOr types.path;
62       example = "/etc/powerdns-admin/salt";
63       description = ''
64         The salt used for serialization.
65         This should be set, otherwise the default is used.
66         Set this to null to ignore this setting and configure it through another way.
67       '';
68     };
69   };
71   config = mkIf cfg.enable {
72     systemd.services.powerdns-admin = {
73       description = "PowerDNS web interface";
74       wantedBy = [ "multi-user.target" ];
75       after = [ "networking.target" ];
77       environment.FLASK_CONF = builtins.toFile "powerdns-admin-config.py" configText;
78       environment.PYTHONPATH = pkgs.powerdns-admin.pythonPath;
79       serviceConfig = {
80         ExecStart = "${pkgs.powerdns-admin}/bin/powerdns-admin --pid /run/powerdns-admin/pid ${escapeShellArgs cfg.extraArgs}";
81         # Set environment variables only for starting flask database upgrade
82         ExecStartPre = "${pkgs.coreutils}/bin/env FLASK_APP=${pkgs.powerdns-admin}/share/powerdnsadmin/__init__.py SESSION_TYPE= ${pkgs.python3Packages.flask}/bin/flask db upgrade -d ${pkgs.powerdns-admin}/share/migrations";
83         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
84         ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID";
85         PIDFile = "/run/powerdns-admin/pid";
86         RuntimeDirectory = "powerdns-admin";
87         User = "powerdnsadmin";
88         Group = "powerdnsadmin";
90         AmbientCapabilities = "CAP_NET_BIND_SERVICE";
91         BindReadOnlyPaths = [
92           "/nix/store"
93           "-/etc/resolv.conf"
94           "-/etc/nsswitch.conf"
95           "-/etc/hosts"
96           "-/etc/localtime"
97         ]
98         ++ (optional (cfg.secretKeyFile != null) cfg.secretKeyFile)
99         ++ (optional (cfg.saltFile != null) cfg.saltFile);
100         CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
101         # ProtectClock= adds DeviceAllow=char-rtc r
102         DeviceAllow = "";
103         # Implies ProtectSystem=strict, which re-mounts all paths
104         #DynamicUser = true;
105         LockPersonality = true;
106         MemoryDenyWriteExecute = true;
107         NoNewPrivileges = true;
108         PrivateDevices = true;
109         PrivateMounts = true;
110         # Needs to start a server
111         #PrivateNetwork = true;
112         PrivateTmp = true;
113         PrivateUsers = true;
114         ProcSubset = "pid";
115         ProtectClock = true;
116         ProtectHome = true;
117         ProtectHostname = true;
118         # Would re-mount paths ignored by temporary root
119         #ProtectSystem = "strict";
120         ProtectControlGroups = true;
121         ProtectKernelLogs = true;
122         ProtectKernelModules = true;
123         ProtectKernelTunables = true;
124         ProtectProc = "invisible";
125         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
126         RestrictNamespaces = true;
127         RestrictRealtime = true;
128         RestrictSUIDSGID = true;
129         SystemCallArchitectures = "native";
130         # gunicorn needs setuid
131         SystemCallFilter = [
132           "@system-service"
133           "~@privileged @resources @keyring"
134           # These got removed by the line above but are needed
135           "@setuid @chown"
136         ];
137         TemporaryFileSystem = "/:ro";
138         # Does not work well with the temporary root
139         #UMask = "0066";
140       };
141     };
143     users.groups.powerdnsadmin = { };
144     users.users.powerdnsadmin = {
145       description = "PowerDNS web interface user";
146       isSystemUser = true;
147       group = "powerdnsadmin";
148     };
149   };
151   # uses attributes of the linked package
152   meta.buildDocsInSandbox = false;