1 { lib, pkgs, config, options, ... }:
4 cfg = config.services.nifi;
5 opt = options.services.nifi;
8 NIFI_OVERRIDE_NIFIENV = "true";
9 NIFI_HOME = "/var/lib/nifi";
10 NIFI_PID_DIR = "/run/nifi";
11 NIFI_LOG_DIR = "/var/log/nifi";
14 envFile = pkgs.writeText "nifi.env" (lib.concatMapStrings (s: s + "\n") (
15 (lib.concatLists (lib.mapAttrsToList (name: value:
16 lib.optional (value != null) ''${name}="${toString value}"''
19 nifiEnv = pkgs.writeShellScriptBin "nifi-env" ''
28 enable = lib.mkEnableOption "Apache NiFi";
30 package = lib.mkOption {
31 type = lib.types.package;
33 defaultText = lib.literalExpression "pkgs.nifi";
34 description = "Apache NiFi package to use.";
40 description = "User account where Apache NiFi runs.";
43 group = lib.mkOption {
46 description = "Group account where Apache NiFi runs.";
49 enableHTTPS = lib.mkOption {
50 type = lib.types.bool;
52 description = "Enable HTTPS protocol. Don`t use in production.";
55 listenHost = lib.mkOption {
57 default = if cfg.enableHTTPS then "0.0.0.0" else "127.0.0.1";
58 defaultText = lib.literalExpression ''
59 if config.${opt.enableHTTPS}
63 description = "Bind to an ip for Apache NiFi web-ui.";
66 listenPort = lib.mkOption {
68 default = if cfg.enableHTTPS then 8443 else 8080;
69 defaultText = lib.literalExpression ''
70 if config.${opt.enableHTTPS}
74 description = "Bind to a port for Apache NiFi web-ui.";
77 proxyHost = lib.mkOption {
78 type = lib.types.nullOr lib.types.str;
79 default = if cfg.enableHTTPS then "0.0.0.0" else null;
80 defaultText = lib.literalExpression ''
81 if config.${opt.enableHTTPS}
85 description = "Allow requests from a specific host.";
88 proxyPort = lib.mkOption {
89 type = lib.types.nullOr lib.types.int;
90 default = if cfg.enableHTTPS then 8443 else null;
91 defaultText = lib.literalExpression ''
92 if config.${opt.enableHTTPS}
96 description = "Allow requests from a specific port.";
99 initUser = lib.mkOption {
100 type = lib.types.nullOr lib.types.str;
102 description = "Initial user account for Apache NiFi. Username must be at least 4 characters.";
105 initPasswordFile = lib.mkOption {
106 type = lib.types.nullOr lib.types.path;
108 example = "/run/keys/nifi/password-nifi";
109 description = "nitial password for Apache NiFi. Password must be at least 12 characters.";
112 initJavaHeapSize = lib.mkOption {
113 type = lib.types.nullOr lib.types.int;
116 description = "Set the initial heap size for the JVM in MB.";
119 maxJavaHeapSize = lib.mkOption {
120 type = lib.types.nullOr lib.types.int;
123 description = "Set the initial heap size for the JVM in MB.";
128 config = lib.mkIf cfg.enable {
130 { assertion = cfg.initUser!=null || cfg.initPasswordFile==null;
132 <option>services.nifi.initUser</option> needs to be set if <option>services.nifi.initPasswordFile</option> enabled.
135 { assertion = cfg.initUser==null || cfg.initPasswordFile!=null;
137 <option>services.nifi.initPasswordFile</option> needs to be set if <option>services.nifi.initUser</option> enabled.
140 { assertion = cfg.proxyHost==null || cfg.proxyPort!=null;
142 <option>services.nifi.proxyPort</option> needs to be set if <option>services.nifi.proxyHost</option> value specified.
145 { assertion = cfg.proxyHost!=null || cfg.proxyPort==null;
147 <option>services.nifi.proxyHost</option> needs to be set if <option>services.nifi.proxyPort</option> value specified.
150 { assertion = cfg.initJavaHeapSize==null || cfg.maxJavaHeapSize!=null;
152 <option>services.nifi.maxJavaHeapSize</option> needs to be set if <option>services.nifi.initJavaHeapSize</option> value specified.
155 { assertion = cfg.initJavaHeapSize!=null || cfg.maxJavaHeapSize==null;
157 <option>services.nifi.initJavaHeapSize</option> needs to be set if <option>services.nifi.maxJavaHeapSize</option> value specified.
162 warnings = lib.optional (cfg.enableHTTPS==false) ''
163 Please do not disable HTTPS mode in production. In this mode, access to the nifi is opened without authentication.
166 systemd.tmpfiles.settings."10-nifi" = {
167 "/var/lib/nifi/conf".d = {
168 inherit (cfg) user group;
171 "/var/lib/nifi/lib"."L+" = {
172 argument = "${cfg.package}/lib";
177 systemd.services.nifi = {
178 description = "Apache NiFi";
179 after = [ "network.target" ];
180 wantedBy = [ "multi-user.target" ];
183 path = [ pkgs.gawk ];
187 PIDFile = "/run/nifi/nifi.pid";
188 ExecStartPre = pkgs.writeScript "nifi-pre-start.sh" ''
191 test -f '/var/lib/nifi/conf/authorizers.xml' || (cp '${cfg.package}/share/nifi/conf/authorizers.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/authorizers.xml')
192 test -f '/var/lib/nifi/conf/bootstrap.conf' || (cp '${cfg.package}/share/nifi/conf/bootstrap.conf' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/bootstrap.conf')
193 test -f '/var/lib/nifi/conf/bootstrap-hashicorp-vault.conf' || (cp '${cfg.package}/share/nifi/conf/bootstrap-hashicorp-vault.conf' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/bootstrap-hashicorp-vault.conf')
194 test -f '/var/lib/nifi/conf/bootstrap-notification-services.xml' || (cp '${cfg.package}/share/nifi/conf/bootstrap-notification-services.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/bootstrap-notification-services.xml')
195 test -f '/var/lib/nifi/conf/logback.xml' || (cp '${cfg.package}/share/nifi/conf/logback.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/logback.xml')
196 test -f '/var/lib/nifi/conf/login-identity-providers.xml' || (cp '${cfg.package}/share/nifi/conf/login-identity-providers.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/login-identity-providers.xml')
197 test -f '/var/lib/nifi/conf/nifi.properties' || (cp '${cfg.package}/share/nifi/conf/nifi.properties' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/nifi.properties')
198 test -f '/var/lib/nifi/conf/stateless-logback.xml' || (cp '${cfg.package}/share/nifi/conf/stateless-logback.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/stateless-logback.xml')
199 test -f '/var/lib/nifi/conf/stateless.properties' || (cp '${cfg.package}/share/nifi/conf/stateless.properties' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/stateless.properties')
200 test -f '/var/lib/nifi/conf/state-management.xml' || (cp '${cfg.package}/share/nifi/conf/state-management.xml' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/state-management.xml')
201 test -f '/var/lib/nifi/conf/zookeeper.properties' || (cp '${cfg.package}/share/nifi/conf/zookeeper.properties' '/var/lib/nifi/conf/' && chmod 0640 '/var/lib/nifi/conf/zookeeper.properties')
202 test -d '/var/lib/nifi/docs/html' || (mkdir -p /var/lib/nifi/docs && cp -r '${cfg.package}/share/nifi/docs/html' '/var/lib/nifi/docs/html')
203 ${lib.optionalString ((cfg.initUser != null) && (cfg.initPasswordFile != null)) ''
204 awk -F'[<|>]' '/property name="Username"/ {if ($3!="") f=1} END{exit !f}' /var/lib/nifi/conf/login-identity-providers.xml || ${cfg.package}/bin/nifi.sh set-single-user-credentials ${cfg.initUser} $(cat ${cfg.initPasswordFile})
206 ${lib.optionalString (cfg.enableHTTPS == false) ''
207 sed -i /var/lib/nifi/conf/nifi.properties \
208 -e 's|nifi.remote.input.secure=.*|nifi.remote.input.secure=false|g' \
209 -e 's|nifi.web.http.host=.*|nifi.web.http.host=${cfg.listenHost}|g' \
210 -e 's|nifi.web.http.port=.*|nifi.web.http.port=${(toString cfg.listenPort)}|g' \
211 -e 's|nifi.web.https.host=.*|nifi.web.https.host=|g' \
212 -e 's|nifi.web.https.port=.*|nifi.web.https.port=|g' \
213 -e 's|nifi.security.keystore=.*|nifi.security.keystore=|g' \
214 -e 's|nifi.security.keystoreType=.*|nifi.security.keystoreType=|g' \
215 -e 's|nifi.security.truststore=.*|nifi.security.truststore=|g' \
216 -e 's|nifi.security.truststoreType=.*|nifi.security.truststoreType=|g' \
217 -e '/nifi.security.keystorePasswd/s|^|#|' \
218 -e '/nifi.security.keyPasswd/s|^|#|' \
219 -e '/nifi.security.truststorePasswd/s|^|#|'
221 ${lib.optionalString (cfg.enableHTTPS == true) ''
222 sed -i /var/lib/nifi/conf/nifi.properties \
223 -e 's|nifi.remote.input.secure=.*|nifi.remote.input.secure=true|g' \
224 -e 's|nifi.web.http.host=.*|nifi.web.http.host=|g' \
225 -e 's|nifi.web.http.port=.*|nifi.web.http.port=|g' \
226 -e 's|nifi.web.https.host=.*|nifi.web.https.host=${cfg.listenHost}|g' \
227 -e 's|nifi.web.https.port=.*|nifi.web.https.port=${(toString cfg.listenPort)}|g' \
228 -e 's|nifi.security.keystore=.*|nifi.security.keystore=./conf/keystore.p12|g' \
229 -e 's|nifi.security.keystoreType=.*|nifi.security.keystoreType=PKCS12|g' \
230 -e 's|nifi.security.truststore=.*|nifi.security.truststore=./conf/truststore.p12|g' \
231 -e 's|nifi.security.truststoreType=.*|nifi.security.truststoreType=PKCS12|g' \
232 -e '/nifi.security.keystorePasswd/s|^#\+||' \
233 -e '/nifi.security.keyPasswd/s|^#\+||' \
234 -e '/nifi.security.truststorePasswd/s|^#\+||'
236 ${lib.optionalString ((cfg.enableHTTPS == true) && (cfg.proxyHost != null) && (cfg.proxyPort != null)) ''
237 sed -i /var/lib/nifi/conf/nifi.properties \
238 -e 's|nifi.web.proxy.host=.*|nifi.web.proxy.host=${cfg.proxyHost}:${(toString cfg.proxyPort)}|g'
240 ${lib.optionalString ((cfg.enableHTTPS == false) || (cfg.proxyHost == null) && (cfg.proxyPort == null)) ''
241 sed -i /var/lib/nifi/conf/nifi.properties \
242 -e 's|nifi.web.proxy.host=.*|nifi.web.proxy.host=|g'
244 ${lib.optionalString ((cfg.initJavaHeapSize != null) && (cfg.maxJavaHeapSize != null))''
245 sed -i /var/lib/nifi/conf/bootstrap.conf \
246 -e 's|java.arg.2=.*|java.arg.2=-Xms${(toString cfg.initJavaHeapSize)}m|g' \
247 -e 's|java.arg.3=.*|java.arg.3=-Xmx${(toString cfg.maxJavaHeapSize)}m|g'
249 ${lib.optionalString ((cfg.initJavaHeapSize == null) && (cfg.maxJavaHeapSize == null))''
250 sed -i /var/lib/nifi/conf/bootstrap.conf \
251 -e 's|java.arg.2=.*|java.arg.2=-Xms512m|g' \
252 -e 's|java.arg.3=.*|java.arg.3=-Xmx512m|g'
255 ExecStart = "${cfg.package}/bin/nifi.sh start";
256 ExecStop = "${cfg.package}/bin/nifi.sh stop";
260 # Runtime directory and mode
261 RuntimeDirectory = "nifi";
262 RuntimeDirectoryMode = "0750";
263 # State directory and mode
264 StateDirectory = "nifi";
265 StateDirectoryMode = "0750";
266 # Logs directory and mode
267 LogsDirectory = "nifi";
268 LogsDirectoryMode = "0750";
271 ProtectProc = "invisible";
272 # Access write directories
273 ReadWritePaths = [ cfg.initPasswordFile ];
276 CapabilityBoundingSet = "";
278 NoNewPrivileges = true;
280 ProtectSystem = "strict";
283 PrivateDevices = true;
286 ProtectHostname = true;
288 ProtectKernelTunables = true;
289 ProtectKernelModules = true;
290 ProtectKernelLogs = true;
291 ProtectControlGroups = true;
292 RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
293 RestrictNamespaces = true;
294 LockPersonality = true;
295 MemoryDenyWriteExecute = false;
296 RestrictRealtime = true;
297 RestrictSUIDSGID = true;
299 PrivateMounts = true;
300 # System Call Filtering
301 SystemCallArchitectures = "native";
302 SystemCallFilter = [ "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @resources @privileged @setuid" "@chown" ];
306 users.users = lib.mkMerge [
307 (lib.mkIf (cfg.user == "nifi") {
314 (lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ cfg.package nifiEnv ])
317 users.groups = lib.optionalAttrs (cfg.group == "nifi") {