at 25.11-pre 27 kB view raw
1{ 2 config, 3 options, 4 lib, 5 pkgs, 6 ... 7}: 8let 9 cfg = config.services.neo4j; 10 opt = options.services.neo4j; 11 certDirOpt = options.services.neo4j.directories.certificates; 12 isDefaultPathOption = 13 opt: lib.isOption opt && opt.type == lib.types.path && opt.highestPrio >= 1500; 14 15 sslPolicies = lib.mapAttrsToList (name: conf: '' 16 dbms.ssl.policy.${name}.allow_key_generation=${lib.boolToString conf.allowKeyGeneration} 17 dbms.ssl.policy.${name}.base_directory=${conf.baseDirectory} 18 ${lib.optionalString (conf.ciphers != null) '' 19 dbms.ssl.policy.${name}.ciphers=${lib.concatStringsSep "," conf.ciphers} 20 ''} 21 dbms.ssl.policy.${name}.client_auth=${conf.clientAuth} 22 ${ 23 if lib.length (lib.splitString "/" conf.privateKey) > 1 then 24 "dbms.ssl.policy.${name}.private_key=${conf.privateKey}" 25 else 26 "dbms.ssl.policy.${name}.private_key=${conf.baseDirectory}/${conf.privateKey}" 27 } 28 ${ 29 if lib.length (lib.splitString "/" conf.privateKey) > 1 then 30 "dbms.ssl.policy.${name}.public_certificate=${conf.publicCertificate}" 31 else 32 "dbms.ssl.policy.${name}.public_certificate=${conf.baseDirectory}/${conf.publicCertificate}" 33 } 34 dbms.ssl.policy.${name}.revoked_dir=${conf.revokedDir} 35 dbms.ssl.policy.${name}.tls_versions=${lib.concatStringsSep "," conf.tlsVersions} 36 dbms.ssl.policy.${name}.trust_all=${lib.boolToString conf.trustAll} 37 dbms.ssl.policy.${name}.trusted_dir=${conf.trustedDir} 38 '') cfg.ssl.policies; 39 40 serverConfig = pkgs.writeText "neo4j.conf" '' 41 # General 42 server.default_listen_address=${cfg.defaultListenAddress} 43 server.databases.default_to_read_only=${lib.boolToString cfg.readOnly} 44 ${lib.optionalString (cfg.workerCount > 0) '' 45 dbms.threads.worker_count=${toString cfg.workerCount} 46 ''} 47 48 # Directories (readonly) 49 # dbms.directories.certificates=${cfg.directories.certificates} 50 server.directories.plugins=${cfg.directories.plugins} 51 server.directories.lib=${cfg.package}/share/neo4j/lib 52 ${lib.optionalString (cfg.constrainLoadCsv) '' 53 server.directories.import=${cfg.directories.imports} 54 ''} 55 56 # Directories (read and write) 57 server.directories.data=${cfg.directories.data} 58 server.directories.logs=${cfg.directories.home}/logs 59 server.directories.run=${cfg.directories.home}/run 60 61 # HTTP Connector 62 server.http.enabled=${lib.boolToString cfg.http.enable} 63 server.http.listen_address=${cfg.http.listenAddress} 64 server.http.advertised_address=${cfg.http.advertisedAddress} 65 66 # HTTPS Connector 67 server.https.enabled=${lib.boolToString cfg.https.enable} 68 server.https.listen_address=${cfg.https.listenAddress} 69 server.https.advertised_address=${cfg.https.advertisedAddress} 70 71 # BOLT Connector 72 server.bolt.enabled=${lib.boolToString cfg.bolt.enable} 73 server.bolt.listen_address=${cfg.bolt.listenAddress} 74 server.bolt.advertised_address=${cfg.bolt.advertisedAddress} 75 server.bolt.tls_level=${cfg.bolt.tlsLevel} 76 77 # SSL Policies 78 ${lib.concatStringsSep "\n" sslPolicies} 79 80 # Default retention policy from neo4j.conf 81 db.tx_log.rotation.retention_policy=1 days 82 83 # Default JVM parameters from neo4j.conf 84 server.jvm.additional=-XX:+UseG1GC 85 server.jvm.additional=-XX:-OmitStackTraceInFastThrow 86 server.jvm.additional=-XX:+AlwaysPreTouch 87 server.jvm.additional=-XX:+UnlockExperimentalVMOptions 88 server.jvm.additional=-XX:+TrustFinalNonStaticFields 89 server.jvm.additional=-XX:+DisableExplicitGC 90 server.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048 91 server.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true 92 server.jvm.additional=-Dunsupported.dbms.udc.source=tarball 93 94 #server.memory.off_heap.transaction_max_size=12000m 95 #server.memory.heap.max_size=12000m 96 #server.memory.pagecache.size=4g 97 #server.tx_state.max_off_heap_memory=8000m 98 99 # Extra Configuration 100 ${cfg.extraServerConfig} 101 ''; 102in 103{ 104 imports = [ 105 (lib.mkRenamedOptionModule 106 [ "services" "neo4j" "host" ] 107 [ "services" "neo4j" "defaultListenAddress" ] 108 ) 109 (lib.mkRenamedOptionModule 110 [ "services" "neo4j" "listenAddress" ] 111 [ "services" "neo4j" "defaultListenAddress" ] 112 ) 113 (lib.mkRenamedOptionModule 114 [ "services" "neo4j" "enableBolt" ] 115 [ "services" "neo4j" "bolt" "enable" ] 116 ) 117 (lib.mkRenamedOptionModule 118 [ "services" "neo4j" "enableHttps" ] 119 [ "services" "neo4j" "https" "enable" ] 120 ) 121 (lib.mkRenamedOptionModule 122 [ "services" "neo4j" "certDir" ] 123 [ "services" "neo4j" "directories" "certificates" ] 124 ) 125 (lib.mkRenamedOptionModule 126 [ "services" "neo4j" "dataDir" ] 127 [ "services" "neo4j" "directories" "home" ] 128 ) 129 (lib.mkRemovedOptionModule [ 130 "services" 131 "neo4j" 132 "port" 133 ] "Use services.neo4j.http.listenAddress instead.") 134 (lib.mkRemovedOptionModule [ 135 "services" 136 "neo4j" 137 "boltPort" 138 ] "Use services.neo4j.bolt.listenAddress instead.") 139 (lib.mkRemovedOptionModule [ 140 "services" 141 "neo4j" 142 "httpsPort" 143 ] "Use services.neo4j.https.listenAddress instead.") 144 (lib.mkRemovedOptionModule [ 145 "services" 146 "neo4j" 147 "shell" 148 "enabled" 149 ] "shell.enabled was removed upstream") 150 (lib.mkRemovedOptionModule [ 151 "services" 152 "neo4j" 153 "udc" 154 "enabled" 155 ] "udc.enabled was removed upstream") 156 ]; 157 158 ###### interface 159 160 options.services.neo4j = { 161 enable = lib.mkOption { 162 type = lib.types.bool; 163 default = false; 164 description = '' 165 Whether to enable Neo4j Community Edition. 166 ''; 167 }; 168 169 constrainLoadCsv = lib.mkOption { 170 type = lib.types.bool; 171 default = true; 172 description = '' 173 Sets the root directory for file URLs used with the Cypher 174 `LOAD CSV` clause to be that defined by 175 {option}`directories.imports`. It restricts 176 access to only those files within that directory and its 177 subdirectories. 178 179 Setting this option to `false` introduces 180 possible security problems. 181 ''; 182 }; 183 184 defaultListenAddress = lib.mkOption { 185 type = lib.types.str; 186 default = "127.0.0.1"; 187 description = '' 188 Default network interface to listen for incoming connections. To 189 listen for connections on all interfaces, use "0.0.0.0". 190 191 Specifies the default IP address and address part of connector 192 specific {option}`listenAddress` options. To bind specific 193 connectors to a specific network interfaces, specify the entire 194 {option}`listenAddress` option for that connector. 195 ''; 196 }; 197 198 extraServerConfig = lib.mkOption { 199 type = lib.types.lines; 200 default = ""; 201 description = '' 202 Extra configuration for Neo4j Community server. Refer to the 203 [complete reference](https://neo4j.com/docs/operations-manual/current/reference/configuration-settings/) 204 of Neo4j configuration settings. 205 ''; 206 }; 207 208 package = lib.mkPackageOption pkgs "neo4j" { }; 209 210 readOnly = lib.mkOption { 211 type = lib.types.bool; 212 default = false; 213 description = '' 214 Only allow read operations from this Neo4j instance. 215 ''; 216 }; 217 218 workerCount = lib.mkOption { 219 type = lib.types.ints.between 0 44738; 220 default = 0; 221 description = '' 222 Number of Neo4j worker threads, where the default of 223 `0` indicates a worker count equal to the number of 224 available processors. 225 ''; 226 }; 227 228 bolt = { 229 enable = lib.mkOption { 230 type = lib.types.bool; 231 default = true; 232 description = '' 233 Enable the BOLT connector for Neo4j. Setting this option to 234 `false` will stop Neo4j from listening for incoming 235 connections on the BOLT port (7687 by default). 236 ''; 237 }; 238 239 listenAddress = lib.mkOption { 240 type = lib.types.str; 241 default = ":7687"; 242 description = '' 243 Neo4j listen address for BOLT traffic. The listen address is 244 expressed in the format `<ip-address>:<port-number>`. 245 ''; 246 }; 247 248 advertisedAddress = lib.mkOption { 249 type = lib.types.str; 250 default = cfg.bolt.listenAddress; 251 defaultText = lib.literalExpression "config.${opt.bolt.listenAddress}"; 252 description = '' 253 Neo4j advertised address for BOLT traffic. The advertised address is 254 expressed in the format `<ip-address>:<port-number>`. 255 ''; 256 }; 257 258 sslPolicy = lib.mkOption { 259 type = lib.types.str; 260 default = "legacy"; 261 description = '' 262 Neo4j SSL policy for BOLT traffic. 263 264 The legacy policy is a special policy which is not defined in 265 the policy configuration section, but rather derives from 266 {option}`directories.certificates` and 267 associated files (by default: {file}`neo4j.key` and 268 {file}`neo4j.cert`). Its use will be deprecated. 269 270 Note: This connector must be configured to support/require 271 SSL/TLS for the legacy policy to actually be utilized. See 272 {option}`bolt.tlsLevel`. 273 ''; 274 }; 275 276 tlsLevel = lib.mkOption { 277 type = lib.types.enum [ 278 "REQUIRED" 279 "OPTIONAL" 280 "DISABLED" 281 ]; 282 default = "OPTIONAL"; 283 description = '' 284 SSL/TSL requirement level for BOLT traffic. 285 ''; 286 }; 287 }; 288 289 directories = { 290 certificates = lib.mkOption { 291 type = lib.types.path; 292 default = "${cfg.directories.home}/certificates"; 293 defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/certificates"''; 294 description = '' 295 Directory for storing certificates to be used by Neo4j for 296 TLS connections. 297 298 When setting this directory to something other than its default, 299 ensure the directory's existence, and that read/write permissions are 300 given to the Neo4j daemon user `neo4j`. 301 302 Note that changing this directory from its default will prevent 303 the directory structure required for each SSL policy from being 304 automatically generated. A policy's directory structure as defined by 305 its {option}`baseDirectory`,{option}`revokedDir` and 306 {option}`trustedDir` must then be setup manually. The 307 existence of these directories is mandatory, as well as the presence 308 of the certificate file and the private key. Ensure the correct 309 permissions are set on these directories and files. 310 ''; 311 }; 312 313 data = lib.mkOption { 314 type = lib.types.path; 315 default = "${cfg.directories.home}/data"; 316 defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/data"''; 317 description = '' 318 Path of the data directory. You must not configure more than one 319 Neo4j installation to use the same data directory. 320 321 When setting this directory to something other than its default, 322 ensure the directory's existence, and that read/write permissions are 323 given to the Neo4j daemon user `neo4j`. 324 ''; 325 }; 326 327 home = lib.mkOption { 328 type = lib.types.path; 329 default = "/var/lib/neo4j"; 330 description = '' 331 Path of the Neo4j home directory. Other default directories are 332 subdirectories of this path. This directory will be created if 333 non-existent, and its ownership will be {command}`chown` to 334 the Neo4j daemon user `neo4j`. 335 ''; 336 }; 337 338 imports = lib.mkOption { 339 type = lib.types.path; 340 default = "${cfg.directories.home}/import"; 341 defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/import"''; 342 description = '' 343 The root directory for file URLs used with the Cypher 344 `LOAD CSV` clause. Only meaningful when 345 {option}`constrainLoadCvs` is set to 346 `true`. 347 348 When setting this directory to something other than its default, 349 ensure the directory's existence, and that read permission is 350 given to the Neo4j daemon user `neo4j`. 351 ''; 352 }; 353 354 plugins = lib.mkOption { 355 type = lib.types.path; 356 default = "${cfg.directories.home}/plugins"; 357 defaultText = lib.literalExpression ''"''${config.${opt.directories.home}}/plugins"''; 358 description = '' 359 Path of the database plugin directory. Compiled Java JAR files that 360 contain database procedures will be loaded if they are placed in 361 this directory. 362 363 When setting this directory to something other than its default, 364 ensure the directory's existence, and that read permission is 365 given to the Neo4j daemon user `neo4j`. 366 ''; 367 }; 368 }; 369 370 http = { 371 enable = lib.mkOption { 372 type = lib.types.bool; 373 default = true; 374 description = '' 375 Enable the HTTP connector for Neo4j. Setting this option to 376 `false` will stop Neo4j from listening for incoming 377 connections on the HTTPS port (7474 by default). 378 ''; 379 }; 380 381 listenAddress = lib.mkOption { 382 type = lib.types.str; 383 default = ":7474"; 384 description = '' 385 Neo4j listen address for HTTP traffic. The listen address is 386 expressed in the format `<ip-address>:<port-number>`. 387 ''; 388 }; 389 390 advertisedAddress = lib.mkOption { 391 type = lib.types.str; 392 default = cfg.http.listenAddress; 393 defaultText = lib.literalExpression "config.${opt.http.listenAddress}"; 394 description = '' 395 Neo4j advertised address for HTTP traffic. The advertised address is 396 expressed in the format `<ip-address>:<port-number>`. 397 ''; 398 }; 399 }; 400 401 https = { 402 enable = lib.mkOption { 403 type = lib.types.bool; 404 default = true; 405 description = '' 406 Enable the HTTPS connector for Neo4j. Setting this option to 407 `false` will stop Neo4j from listening for incoming 408 connections on the HTTPS port (7473 by default). 409 ''; 410 }; 411 412 listenAddress = lib.mkOption { 413 type = lib.types.str; 414 default = ":7473"; 415 description = '' 416 Neo4j listen address for HTTPS traffic. The listen address is 417 expressed in the format `<ip-address>:<port-number>`. 418 ''; 419 }; 420 421 advertisedAddress = lib.mkOption { 422 type = lib.types.str; 423 default = cfg.https.listenAddress; 424 defaultText = lib.literalExpression "config.${opt.https.listenAddress}"; 425 description = '' 426 Neo4j advertised address for HTTPS traffic. The advertised address is 427 expressed in the format `<ip-address>:<port-number>`. 428 ''; 429 }; 430 431 sslPolicy = lib.mkOption { 432 type = lib.types.str; 433 default = "legacy"; 434 description = '' 435 Neo4j SSL policy for HTTPS traffic. 436 437 The legacy policy is a special policy which is not defined in the 438 policy configuration section, but rather derives from 439 {option}`directories.certificates` and 440 associated files (by default: {file}`neo4j.key` and 441 {file}`neo4j.cert`). Its use will be deprecated. 442 ''; 443 }; 444 }; 445 446 shell = { 447 enable = lib.mkOption { 448 type = lib.types.bool; 449 default = false; 450 description = '' 451 Enable a remote shell server which Neo4j Shell clients can log in to. 452 Only applicable to {command}`neo4j-shell`. 453 ''; 454 }; 455 }; 456 457 ssl.policies = lib.mkOption { 458 type = 459 with lib.types; 460 attrsOf ( 461 submodule ( 462 { 463 name, 464 config, 465 options, 466 ... 467 }: 468 { 469 options = { 470 allowKeyGeneration = lib.mkOption { 471 type = lib.types.bool; 472 default = false; 473 description = '' 474 Allows the generation of a private key and associated self-signed 475 certificate. Only performed when both objects cannot be found for 476 this policy. It is recommended to turn this off again after keys 477 have been generated. 478 479 The public certificate is required to be duplicated to the 480 directory holding trusted certificates as defined by the 481 {option}`trustedDir` option. 482 483 Keys should in general be generated and distributed offline by a 484 trusted certificate authority and not by utilizing this mode. 485 ''; 486 }; 487 488 baseDirectory = lib.mkOption { 489 type = lib.types.path; 490 default = "${cfg.directories.certificates}/${name}"; 491 defaultText = lib.literalExpression ''"''${config.${opt.directories.certificates}}/''${name}"''; 492 description = '' 493 The mandatory base directory for cryptographic objects of this 494 policy. This path is only automatically generated when this 495 option as well as {option}`directories.certificates` are 496 left at their default. Ensure read/write permissions are given 497 to the Neo4j daemon user `neo4j`. 498 499 It is also possible to override each individual 500 configuration with absolute paths. See the 501 {option}`privateKey` and {option}`publicCertificate` 502 policy options. 503 ''; 504 }; 505 506 ciphers = lib.mkOption { 507 type = lib.types.nullOr (lib.types.listOf lib.types.str); 508 default = null; 509 description = '' 510 Restrict the allowed ciphers of this policy to those defined 511 here. The default ciphers are those of the JVM platform. 512 ''; 513 }; 514 515 clientAuth = lib.mkOption { 516 type = lib.types.enum [ 517 "NONE" 518 "OPTIONAL" 519 "REQUIRE" 520 ]; 521 default = "REQUIRE"; 522 description = '' 523 The client authentication stance for this policy. 524 ''; 525 }; 526 527 privateKey = lib.mkOption { 528 type = lib.types.str; 529 default = "private.key"; 530 description = '' 531 The name of private PKCS #8 key file for this policy to be found 532 in the {option}`baseDirectory`, or the absolute path to 533 the key file. It is mandatory that a key can be found or generated. 534 ''; 535 }; 536 537 publicCertificate = lib.mkOption { 538 type = lib.types.str; 539 default = "public.crt"; 540 description = '' 541 The name of public X.509 certificate (chain) file in PEM format 542 for this policy to be found in the {option}`baseDirectory`, 543 or the absolute path to the certificate file. It is mandatory 544 that a certificate can be found or generated. 545 546 The public certificate is required to be duplicated to the 547 directory holding trusted certificates as defined by the 548 {option}`trustedDir` option. 549 ''; 550 }; 551 552 revokedDir = lib.mkOption { 553 type = lib.types.path; 554 default = "${config.baseDirectory}/revoked"; 555 defaultText = lib.literalExpression ''"''${config.${options.baseDirectory}}/revoked"''; 556 description = '' 557 Path to directory of CRLs (Certificate Revocation Lists) in 558 PEM format. Must be an absolute path. The existence of this 559 directory is mandatory and will need to be created manually when: 560 setting this option to something other than its default; setting 561 either this policy's {option}`baseDirectory` or 562 {option}`directories.certificates` to something other than 563 their default. Ensure read/write permissions are given to the 564 Neo4j daemon user `neo4j`. 565 ''; 566 }; 567 568 tlsVersions = lib.mkOption { 569 type = lib.types.listOf lib.types.str; 570 default = [ "TLSv1.2" ]; 571 description = '' 572 Restrict the TLS protocol versions of this policy to those 573 defined here. 574 ''; 575 }; 576 577 trustAll = lib.mkOption { 578 type = lib.types.bool; 579 default = false; 580 description = '' 581 Makes this policy trust all remote parties. Enabling this is not 582 recommended and the policy's trusted directory will be ignored. 583 Use of this mode is discouraged. It would offer encryption but 584 no security. 585 ''; 586 }; 587 588 trustedDir = lib.mkOption { 589 type = lib.types.path; 590 default = "${config.baseDirectory}/trusted"; 591 defaultText = lib.literalExpression ''"''${config.${options.baseDirectory}}/trusted"''; 592 description = '' 593 Path to directory of X.509 certificates in PEM format for 594 trusted parties. Must be an absolute path. The existence of this 595 directory is mandatory and will need to be created manually when: 596 setting this option to something other than its default; setting 597 either this policy's {option}`baseDirectory` or 598 {option}`directories.certificates` to something other than 599 their default. Ensure read/write permissions are given to the 600 Neo4j daemon user `neo4j`. 601 602 The public certificate as defined by 603 {option}`publicCertificate` is required to be duplicated 604 to this directory. 605 ''; 606 }; 607 608 directoriesToCreate = lib.mkOption { 609 type = lib.types.listOf lib.types.path; 610 internal = true; 611 readOnly = true; 612 description = '' 613 Directories of this policy that will be created automatically 614 when the certificates directory is left at its default value. 615 This includes all options of type path that are left at their 616 default value. 617 ''; 618 }; 619 }; 620 621 config.directoriesToCreate = lib.optionals ( 622 certDirOpt.highestPrio >= 1500 && options.baseDirectory.highestPrio >= 1500 623 ) (map (opt: opt.value) (lib.filter isDefaultPathOption (lib.attrValues options))); 624 } 625 ) 626 ); 627 default = { }; 628 description = '' 629 Defines the SSL policies for use with Neo4j connectors. Each attribute 630 of this set defines a policy, with the attribute name defining the name 631 of the policy and its namespace. Refer to the operations manual section 632 on Neo4j's 633 [SSL Framework](https://neo4j.com/docs/operations-manual/current/security/ssl-framework/) 634 for further details. 635 ''; 636 }; 637 }; 638 639 ###### implementation 640 641 config = 642 let 643 # Assertion helpers 644 policyNameList = lib.attrNames cfg.ssl.policies; 645 validPolicyNameList = [ "legacy" ] ++ policyNameList; 646 validPolicyNameString = lib.concatStringsSep ", " validPolicyNameList; 647 648 # Capture various directories left at their default so they can be created. 649 defaultDirectoriesToCreate = map (opt: opt.value) ( 650 lib.filter isDefaultPathOption (lib.attrValues options.services.neo4j.directories) 651 ); 652 policyDirectoriesToCreate = lib.concatMap (pol: pol.directoriesToCreate) ( 653 lib.attrValues cfg.ssl.policies 654 ); 655 in 656 lib.mkIf cfg.enable { 657 assertions = [ 658 { 659 assertion = !lib.elem "legacy" policyNameList; 660 message = "The policy 'legacy' is special to Neo4j, and its name is reserved."; 661 } 662 { 663 assertion = lib.elem cfg.bolt.sslPolicy validPolicyNameList; 664 message = "Invalid policy assigned: `services.neo4j.bolt.sslPolicy = \"${cfg.bolt.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; 665 } 666 { 667 assertion = lib.elem cfg.https.sslPolicy validPolicyNameList; 668 message = "Invalid policy assigned: `services.neo4j.https.sslPolicy = \"${cfg.https.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; 669 } 670 ]; 671 672 systemd.services.neo4j = { 673 description = "Neo4j Daemon"; 674 wantedBy = [ "multi-user.target" ]; 675 after = [ "network.target" ]; 676 environment = { 677 NEO4J_HOME = "${cfg.directories.home}"; 678 NEO4J_CONF = "${cfg.directories.home}/conf"; 679 }; 680 serviceConfig = { 681 ExecStart = "${cfg.package}/bin/neo4j console"; 682 User = "neo4j"; 683 PermissionsStartOnly = true; 684 LimitNOFILE = 40000; 685 }; 686 687 preStart = '' 688 # Directories Setup 689 # Always ensure home exists with nested conf, logs directories. 690 mkdir -m 0700 -p ${cfg.directories.home}/{conf,logs} 691 692 # Create other sub-directories and policy directories that have been left at their default. 693 ${lib.concatMapStringsSep "\n" (dir: '' 694 mkdir -m 0700 -p ${dir} 695 '') (defaultDirectoriesToCreate ++ policyDirectoriesToCreate)} 696 697 # Place the configuration where Neo4j can find it. 698 ln -fs ${serverConfig} ${cfg.directories.home}/conf/neo4j.conf 699 700 # Ensure neo4j user ownership 701 chown -R neo4j ${cfg.directories.home} 702 ''; 703 }; 704 705 environment.systemPackages = [ cfg.package ]; 706 707 users.users.neo4j = { 708 isSystemUser = true; 709 group = "neo4j"; 710 description = "Neo4j daemon user"; 711 home = cfg.directories.home; 712 }; 713 users.groups.neo4j = { }; 714 }; 715 716 meta = { 717 maintainers = with lib.maintainers; [ patternspandemic ]; 718 }; 719}