at 24.11-pre 25 kB view raw
1{ config, lib, pkgs, ... }: 2 3 4# TODO: test configuration when building nixexpr (use -t parameter) 5# TODO: support sqlite3 (it's deprecate?) and mysql 6 7 8let 9 inherit (lib) 10 concatStringsSep 11 literalExpression 12 mapAttrsToList 13 mkIf 14 mkOption 15 optional 16 optionalString 17 types 18 ; 19 libDir = "/var/lib/bacula"; 20 21 yes_no = bool: if bool then "yes" else "no"; 22 tls_conf = tls_cfg: optionalString tls_cfg.enable ( 23 concatStringsSep 24 "\n" 25 ( 26 ["TLS Enable = yes;"] 27 ++ optional (tls_cfg.require != null) "TLS Require = ${yes_no tls_cfg.require};" 28 ++ optional (tls_cfg.certificate != null) ''TLS Certificate = "${tls_cfg.certificate}";'' 29 ++ [''TLS Key = "${tls_cfg.key}";''] 30 ++ optional (tls_cfg.verifyPeer != null) "TLS Verify Peer = ${yes_no tls_cfg.verifyPeer};" 31 ++ optional (tls_cfg.allowedCN != [ ]) "TLS Allowed CN = ${concatStringsSep " " (tls_cfg.allowedCN)};" 32 ++ optional (tls_cfg.caCertificateFile != null) ''TLS CA Certificate File = "${tls_cfg.caCertificateFile}";'' 33 ) 34 ); 35 36 fd_cfg = config.services.bacula-fd; 37 fd_conf = pkgs.writeText "bacula-fd.conf" 38 '' 39 Client { 40 Name = "${fd_cfg.name}"; 41 FDPort = ${toString fd_cfg.port}; 42 WorkingDirectory = ${libDir}; 43 Pid Directory = /run; 44 ${fd_cfg.extraClientConfig} 45 ${tls_conf fd_cfg.tls} 46 } 47 48 ${concatStringsSep "\n" (mapAttrsToList (name: value: '' 49 Director { 50 Name = "${name}"; 51 Password = ${value.password}; 52 Monitor = ${value.monitor}; 53 ${tls_conf value.tls} 54 } 55 '') fd_cfg.director)} 56 57 Messages { 58 Name = Standard; 59 syslog = all, !skipped, !restored 60 ${fd_cfg.extraMessagesConfig} 61 } 62 ''; 63 64 sd_cfg = config.services.bacula-sd; 65 sd_conf = pkgs.writeText "bacula-sd.conf" 66 '' 67 Storage { 68 Name = "${sd_cfg.name}"; 69 SDPort = ${toString sd_cfg.port}; 70 WorkingDirectory = ${libDir}; 71 Pid Directory = /run; 72 ${sd_cfg.extraStorageConfig} 73 ${tls_conf sd_cfg.tls} 74 } 75 76 ${concatStringsSep "\n" (mapAttrsToList (name: value: '' 77 Autochanger { 78 Name = "${name}"; 79 Device = ${concatStringsSep ", " (map (a: "\"${a}\"") value.devices)}; 80 Changer Device = ${value.changerDevice}; 81 Changer Command = ${value.changerCommand}; 82 ${value.extraAutochangerConfig} 83 } 84 '') sd_cfg.autochanger)} 85 86 ${concatStringsSep "\n" (mapAttrsToList (name: value: '' 87 Device { 88 Name = "${name}"; 89 Archive Device = ${value.archiveDevice}; 90 Media Type = ${value.mediaType}; 91 ${value.extraDeviceConfig} 92 } 93 '') sd_cfg.device)} 94 95 ${concatStringsSep "\n" (mapAttrsToList (name: value: '' 96 Director { 97 Name = "${name}"; 98 Password = ${value.password}; 99 Monitor = ${value.monitor}; 100 ${tls_conf value.tls} 101 } 102 '') sd_cfg.director)} 103 104 Messages { 105 Name = Standard; 106 syslog = all, !skipped, !restored 107 ${sd_cfg.extraMessagesConfig} 108 } 109 ''; 110 111 dir_cfg = config.services.bacula-dir; 112 dir_conf = pkgs.writeText "bacula-dir.conf" 113 '' 114 Director { 115 Name = "${dir_cfg.name}"; 116 Password = ${dir_cfg.password}; 117 DirPort = ${toString dir_cfg.port}; 118 Working Directory = ${libDir}; 119 Pid Directory = /run/; 120 QueryFile = ${pkgs.bacula}/etc/query.sql; 121 ${tls_conf dir_cfg.tls} 122 ${dir_cfg.extraDirectorConfig} 123 } 124 125 Catalog { 126 Name = PostgreSQL; 127 dbname = bacula; 128 user = bacula; 129 } 130 131 Messages { 132 Name = Standard; 133 syslog = all, !skipped, !restored 134 ${dir_cfg.extraMessagesConfig} 135 } 136 137 ${dir_cfg.extraConfig} 138 ''; 139 140 linkOption = name: destination: "[${name}](#opt-${builtins.replaceStrings [ "<" ">"] ["_" "_"] destination})"; 141 tlsLink = destination: submodulePath: linkOption "${submodulePath}.${destination}" "${submodulePath}.${destination}"; 142 143 tlsOptions = submodulePath: {...}: 144 { 145 options = { 146 enable = mkOption { 147 type = types.bool; 148 default = false; 149 description = '' 150 Specifies if TLS should be enabled. 151 If this set to `false` TLS will be completely disabled, even if ${tlsLink "tls.require" submodulePath} is true. 152 ''; 153 }; 154 require = mkOption { 155 type = types.nullOr types.bool; 156 default = null; 157 description = '' 158 Require TLS or TLS-PSK encryption. 159 This directive is ignored unless one of ${tlsLink "tls.enable" submodulePath} is true or TLS PSK Enable is set to `yes`. 160 If TLS is not required while TLS or TLS-PSK are enabled, then the Bacula component 161 will connect with other components either with or without TLS or TLS-PSK 162 163 If ${tlsLink "tls.enable" submodulePath} or TLS-PSK is enabled and TLS is required, then the Bacula 164 component will refuse any connection request that does not use TLS. 165 ''; 166 }; 167 certificate = mkOption { 168 type = types.nullOr types.path; 169 default = null; 170 description = '' 171 The full path to the PEM encoded TLS certificate. 172 It will be used as either a client or server certificate, 173 depending on the connection direction. 174 This directive is required in a server context, but it may 175 not be specified in a client context if ${tlsLink "tls.verifyPeer" submodulePath} is 176 `false` in the corresponding server context. 177 ''; 178 }; 179 key = mkOption { 180 type = types.path; 181 description = '' 182 The path of a PEM encoded TLS private key. 183 It must correspond to the TLS certificate. 184 ''; 185 }; 186 verifyPeer = mkOption { 187 type = types.nullOr types.bool; 188 default = null; 189 description = '' 190 Verify peer certificate. 191 Instructs server to request and verify the client's X.509 certificate. 192 Any client certificate signed by a known-CA will be accepted. 193 Additionally, the client's X509 certificate Common Name must meet the value of the Address directive. 194 If ${tlsLink "tls.allowedCN" submodulePath} is used, 195 the client's x509 certificate Common Name must also correspond to 196 one of the CN specified in the ${tlsLink "tls.allowedCN" submodulePath} directive. 197 This directive is valid only for a server and not in client context. 198 199 Standard from Bacula is `true`. 200 ''; 201 }; 202 allowedCN = mkOption { 203 type = types.listOf types.str; 204 default = [ ]; 205 description = '' 206 Common name attribute of allowed peer certificates. 207 This directive is valid for a server and in a client context. 208 If this directive is specified, the peer certificate will be verified against this list. 209 In the case this directive is configured on a server side, the allowed 210 CN list will not be checked if ${tlsLink "tls.verifyPeer" submodulePath} is false. 211 ''; 212 }; 213 caCertificateFile = mkOption { 214 type = types.nullOr types.path; 215 default = null; 216 description = '' 217 The path specifying a PEM encoded TLS CA certificate(s). 218 Multiple certificates are permitted in the file. 219 One of TLS CA Certificate File or TLS CA Certificate Dir are required in a server context, unless 220 ${tlsLink "tls.verifyPeer" submodulePath} is false, and are always required in a client context. 221 ''; 222 }; 223 }; 224 }; 225 226 directorOptions = submodulePath:{...}: 227 { 228 options = { 229 password = mkOption { 230 type = types.str; 231 # TODO: required? 232 description = '' 233 Specifies the password that must be supplied for the default Bacula 234 Console to be authorized. The same password must appear in the 235 Director resource of the Console configuration file. For added 236 security, the password is never passed across the network but instead 237 a challenge response hash code created with the password. This 238 directive is required. If you have either /dev/random or bc on your 239 machine, Bacula will generate a random password during the 240 configuration process, otherwise it will be left blank and you must 241 manually supply it. 242 243 The password is plain text. It is not generated through any special 244 process but as noted above, it is better to use random text for 245 security reasons. 246 ''; 247 }; 248 249 monitor = mkOption { 250 type = types.enum [ "no" "yes" ]; 251 default = "no"; 252 example = "yes"; 253 description = '' 254 If Monitor is set to `no`, this director will have 255 full access to this Storage daemon. If Monitor is set to 256 `yes`, this director will only be able to fetch the 257 current status of this Storage daemon. 258 259 Please note that if this director is being used by a Monitor, we 260 highly recommend to set this directive to yes to avoid serious 261 security problems. 262 ''; 263 }; 264 265 tls = mkOption { 266 type = types.submodule (tlsOptions "${submodulePath}.director.<name>"); 267 description = '' 268 TLS Options for the Director in this Configuration. 269 ''; 270 }; 271 }; 272 }; 273 274 autochangerOptions = {...}: 275 { 276 options = { 277 changerDevice = mkOption { 278 type = types.str; 279 description = '' 280 The specified name-string must be the generic SCSI device name of the 281 autochanger that corresponds to the normal read/write Archive Device 282 specified in the Device resource. This generic SCSI device name 283 should be specified if you have an autochanger or if you have a 284 standard tape drive and want to use the Alert Command (see below). 285 For example, on Linux systems, for an Archive Device name of 286 `/dev/nst0`, you would specify 287 `/dev/sg0` for the Changer Device name. Depending 288 on your exact configuration, and the number of autochangers or the 289 type of autochanger, what you specify here can vary. This directive 290 is optional. See the Using AutochangersAutochangersChapter chapter of 291 this manual for more details of using this and the following 292 autochanger directives. 293 ''; 294 }; 295 296 changerCommand = mkOption { 297 type = types.str; 298 description = '' 299 The name-string specifies an external program to be called that will 300 automatically change volumes as required by Bacula. Normally, this 301 directive will be specified only in the AutoChanger resource, which 302 is then used for all devices. However, you may also specify the 303 different Changer Command in each Device resource. Most frequently, 304 you will specify the Bacula supplied mtx-changer script as follows: 305 306 `"/path/mtx-changer %c %o %S %a %d"` 307 308 and you will install the mtx on your system (found in the depkgs 309 release). An example of this command is in the default bacula-sd.conf 310 file. For more details on the substitution characters that may be 311 specified to configure your autochanger please see the 312 AutochangersAutochangersChapter chapter of this manual. For FreeBSD 313 users, you might want to see one of the several chio scripts in 314 examples/autochangers. 315 ''; 316 default = "/etc/bacula/mtx-changer %c %o %S %a %d"; 317 }; 318 319 devices = mkOption { 320 description = ""; 321 type = types.listOf types.str; 322 }; 323 324 extraAutochangerConfig = mkOption { 325 default = ""; 326 type = types.lines; 327 description = '' 328 Extra configuration to be passed in Autochanger directive. 329 ''; 330 example = '' 331 332 ''; 333 }; 334 }; 335 }; 336 337 338 deviceOptions = {...}: 339 { 340 options = { 341 archiveDevice = mkOption { 342 # TODO: required? 343 type = types.str; 344 description = '' 345 The specified name-string gives the system file name of the storage 346 device managed by this storage daemon. This will usually be the 347 device file name of a removable storage device (tape drive), for 348 example `/dev/nst0` or 349 `/dev/rmt/0mbn`. For a DVD-writer, it will be for 350 example `/dev/hdc`. It may also be a directory name 351 if you are archiving to disk storage. In this case, you must supply 352 the full absolute path to the directory. When specifying a tape 353 device, it is preferable that the "non-rewind" variant of the device 354 file name be given. 355 ''; 356 }; 357 358 mediaType = mkOption { 359 # TODO: required? 360 type = types.str; 361 description = '' 362 The specified name-string names the type of media supported by this 363 device, for example, `DLT7000`. Media type names are 364 arbitrary in that you set them to anything you want, but they must be 365 known to the volume database to keep track of which storage daemons 366 can read which volumes. In general, each different storage type 367 should have a unique Media Type associated with it. The same 368 name-string must appear in the appropriate Storage resource 369 definition in the Director's configuration file. 370 371 Even though the names you assign are arbitrary (i.e. you choose the 372 name you want), you should take care in specifying them because the 373 Media Type is used to determine which storage device Bacula will 374 select during restore. Thus you should probably use the same Media 375 Type specification for all drives where the Media can be freely 376 interchanged. This is not generally an issue if you have a single 377 Storage daemon, but it is with multiple Storage daemons, especially 378 if they have incompatible media. 379 380 For example, if you specify a Media Type of `DDS-4` 381 then during the restore, Bacula will be able to choose any Storage 382 Daemon that handles `DDS-4`. If you have an 383 autochanger, you might want to name the Media Type in a way that is 384 unique to the autochanger, unless you wish to possibly use the 385 Volumes in other drives. You should also ensure to have unique Media 386 Type names if the Media is not compatible between drives. This 387 specification is required for all devices. 388 389 In addition, if you are using disk storage, each Device resource will 390 generally have a different mount point or directory. In order for 391 Bacula to select the correct Device resource, each one must have a 392 unique Media Type. 393 ''; 394 }; 395 396 extraDeviceConfig = mkOption { 397 default = ""; 398 type = types.lines; 399 description = '' 400 Extra configuration to be passed in Device directive. 401 ''; 402 example = '' 403 LabelMedia = yes 404 Random Access = no 405 AutomaticMount = no 406 RemovableMedia = no 407 MaximumOpenWait = 60 408 AlwaysOpen = no 409 ''; 410 }; 411 }; 412 }; 413 414in { 415 options = { 416 services.bacula-fd = { 417 enable = mkOption { 418 type = types.bool; 419 default = false; 420 description = '' 421 Whether to enable the Bacula File Daemon. 422 ''; 423 }; 424 425 name = mkOption { 426 default = "${config.networking.hostName}-fd"; 427 defaultText = literalExpression ''"''${config.networking.hostName}-fd"''; 428 type = types.str; 429 description = '' 430 The client name that must be used by the Director when connecting. 431 Generally, it is a good idea to use a name related to the machine so 432 that error messages can be easily identified if you have multiple 433 Clients. This directive is required. 434 ''; 435 }; 436 437 port = mkOption { 438 default = 9102; 439 type = types.port; 440 description = '' 441 This specifies the port number on which the Client listens for 442 Director connections. It must agree with the FDPort specified in 443 the Client resource of the Director's configuration file. 444 ''; 445 }; 446 447 director = mkOption { 448 default = {}; 449 description = '' 450 This option defines director resources in Bacula File Daemon. 451 ''; 452 type = types.attrsOf (types.submodule (directorOptions "services.bacula-fd")); 453 }; 454 455 456 tls = mkOption { 457 type = types.submodule (tlsOptions "services.bacula-fd"); 458 default = { }; 459 description = '' 460 TLS Options for the File Daemon. 461 Important notice: The backup won't be encrypted. 462 ''; 463 }; 464 465 extraClientConfig = mkOption { 466 default = ""; 467 type = types.lines; 468 description = '' 469 Extra configuration to be passed in Client directive. 470 ''; 471 example = '' 472 Maximum Concurrent Jobs = 20; 473 Heartbeat Interval = 30; 474 ''; 475 }; 476 477 extraMessagesConfig = mkOption { 478 default = ""; 479 type = types.lines; 480 description = '' 481 Extra configuration to be passed in Messages directive. 482 ''; 483 example = '' 484 console = all 485 ''; 486 }; 487 }; 488 489 services.bacula-sd = { 490 enable = mkOption { 491 type = types.bool; 492 default = false; 493 description = '' 494 Whether to enable Bacula Storage Daemon. 495 ''; 496 }; 497 498 name = mkOption { 499 default = "${config.networking.hostName}-sd"; 500 defaultText = literalExpression ''"''${config.networking.hostName}-sd"''; 501 type = types.str; 502 description = '' 503 Specifies the Name of the Storage daemon. 504 ''; 505 }; 506 507 port = mkOption { 508 default = 9103; 509 type = types.port; 510 description = '' 511 Specifies port number on which the Storage daemon listens for 512 Director connections. 513 ''; 514 }; 515 516 director = mkOption { 517 default = {}; 518 description = '' 519 This option defines Director resources in Bacula Storage Daemon. 520 ''; 521 type = types.attrsOf (types.submodule (directorOptions "services.bacula-sd")); 522 }; 523 524 device = mkOption { 525 default = {}; 526 description = '' 527 This option defines Device resources in Bacula Storage Daemon. 528 ''; 529 type = types.attrsOf (types.submodule deviceOptions); 530 }; 531 532 autochanger = mkOption { 533 default = {}; 534 description = '' 535 This option defines Autochanger resources in Bacula Storage Daemon. 536 ''; 537 type = types.attrsOf (types.submodule autochangerOptions); 538 }; 539 540 extraStorageConfig = mkOption { 541 default = ""; 542 type = types.lines; 543 description = '' 544 Extra configuration to be passed in Storage directive. 545 ''; 546 example = '' 547 Maximum Concurrent Jobs = 20; 548 Heartbeat Interval = 30; 549 ''; 550 }; 551 552 extraMessagesConfig = mkOption { 553 default = ""; 554 type = types.lines; 555 description = '' 556 Extra configuration to be passed in Messages directive. 557 ''; 558 example = '' 559 console = all 560 ''; 561 }; 562 tls = mkOption { 563 type = types.submodule (tlsOptions "services.bacula-sd"); 564 default = { }; 565 description = '' 566 TLS Options for the Storage Daemon. 567 Important notice: The backup won't be encrypted. 568 ''; 569 }; 570 571 }; 572 573 services.bacula-dir = { 574 enable = mkOption { 575 type = types.bool; 576 default = false; 577 description = '' 578 Whether to enable Bacula Director Daemon. 579 ''; 580 }; 581 582 name = mkOption { 583 default = "${config.networking.hostName}-dir"; 584 defaultText = literalExpression ''"''${config.networking.hostName}-dir"''; 585 type = types.str; 586 description = '' 587 The director name used by the system administrator. This directive is 588 required. 589 ''; 590 }; 591 592 port = mkOption { 593 default = 9101; 594 type = types.port; 595 description = '' 596 Specify the port (a positive integer) on which the Director daemon 597 will listen for Bacula Console connections. This same port number 598 must be specified in the Director resource of the Console 599 configuration file. The default is 9101, so normally this directive 600 need not be specified. This directive should not be used if you 601 specify DirAddresses (N.B plural) directive. 602 ''; 603 }; 604 605 password = mkOption { 606 # TODO: required? 607 type = types.str; 608 description = '' 609 Specifies the password that must be supplied for a Director. 610 ''; 611 }; 612 613 extraMessagesConfig = mkOption { 614 default = ""; 615 type = types.lines; 616 description = '' 617 Extra configuration to be passed in Messages directive. 618 ''; 619 example = '' 620 console = all 621 ''; 622 }; 623 624 extraDirectorConfig = mkOption { 625 default = ""; 626 type = types.lines; 627 description = '' 628 Extra configuration to be passed in Director directive. 629 ''; 630 example = '' 631 Maximum Concurrent Jobs = 20; 632 Heartbeat Interval = 30; 633 ''; 634 }; 635 636 extraConfig = mkOption { 637 default = ""; 638 type = types.lines; 639 description = '' 640 Extra configuration for Bacula Director Daemon. 641 ''; 642 example = '' 643 TODO 644 ''; 645 }; 646 647 tls = mkOption { 648 type = types.submodule (tlsOptions "services.bacula-dir"); 649 default = { }; 650 description = '' 651 TLS Options for the Director. 652 Important notice: The backup won't be encrypted. 653 ''; 654 }; 655 }; 656 }; 657 658 config = mkIf (fd_cfg.enable || sd_cfg.enable || dir_cfg.enable) { 659 systemd.services.bacula-fd = mkIf fd_cfg.enable { 660 after = [ "network.target" ]; 661 description = "Bacula File Daemon"; 662 wantedBy = [ "multi-user.target" ]; 663 path = [ pkgs.bacula ]; 664 serviceConfig = { 665 ExecStart = "${pkgs.bacula}/sbin/bacula-fd -f -u root -g bacula -c ${fd_conf}"; 666 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 667 LogsDirectory = "bacula"; 668 StateDirectory = "bacula"; 669 }; 670 }; 671 672 systemd.services.bacula-sd = mkIf sd_cfg.enable { 673 after = [ "network.target" ]; 674 description = "Bacula Storage Daemon"; 675 wantedBy = [ "multi-user.target" ]; 676 path = [ pkgs.bacula ]; 677 serviceConfig = { 678 ExecStart = "${pkgs.bacula}/sbin/bacula-sd -f -u bacula -g bacula -c ${sd_conf}"; 679 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 680 LogsDirectory = "bacula"; 681 StateDirectory = "bacula"; 682 }; 683 }; 684 685 services.postgresql.enable = lib.mkIf dir_cfg.enable true; 686 687 systemd.services.bacula-dir = mkIf dir_cfg.enable { 688 after = [ "network.target" "postgresql.service" ]; 689 description = "Bacula Director Daemon"; 690 wantedBy = [ "multi-user.target" ]; 691 path = [ pkgs.bacula ]; 692 serviceConfig = { 693 ExecStart = "${pkgs.bacula}/sbin/bacula-dir -f -u bacula -g bacula -c ${dir_conf}"; 694 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 695 LogsDirectory = "bacula"; 696 StateDirectory = "bacula"; 697 }; 698 preStart = '' 699 if ! test -e "${libDir}/db-created"; then 700 ${pkgs.postgresql}/bin/createuser --no-superuser --no-createdb --no-createrole bacula 701 #${pkgs.postgresql}/bin/createdb --owner bacula bacula 702 703 # populate DB 704 ${pkgs.bacula}/etc/create_bacula_database postgresql 705 ${pkgs.bacula}/etc/make_bacula_tables postgresql 706 ${pkgs.bacula}/etc/grant_bacula_privileges postgresql 707 touch "${libDir}/db-created" 708 else 709 ${pkgs.bacula}/etc/update_bacula_tables postgresql || true 710 fi 711 ''; 712 }; 713 714 environment.systemPackages = [ pkgs.bacula ]; 715 716 users.users.bacula = { 717 group = "bacula"; 718 uid = config.ids.uids.bacula; 719 home = "${libDir}"; 720 createHome = true; 721 description = "Bacula Daemons user"; 722 shell = "${pkgs.bash}/bin/bash"; 723 }; 724 725 users.groups.bacula.gid = config.ids.gids.bacula; 726 }; 727}