at 25.11-pre 5.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.certspotter; 10 11 configDir = pkgs.linkFarm "certspotter-config" ( 12 lib.toList { 13 name = "watchlist"; 14 path = pkgs.writeText "certspotter-watchlist" (builtins.concatStringsSep "\n" cfg.watchlist); 15 } 16 ++ lib.optional (cfg.emailRecipients != [ ]) { 17 name = "email_recipients"; 18 path = pkgs.writeText "certspotter-email_recipients" ( 19 builtins.concatStringsSep "\n" cfg.emailRecipients 20 ); 21 } 22 # always generate hooks dir when no emails are provided to allow running cert spotter with no hooks/emails 23 ++ lib.optional (cfg.emailRecipients == [ ] || cfg.hooks != [ ]) { 24 name = "hooks.d"; 25 path = pkgs.linkFarm "certspotter-hooks" ( 26 lib.imap1 (i: path: { 27 inherit path; 28 name = "hook${toString i}"; 29 }) cfg.hooks 30 ); 31 } 32 ); 33in 34{ 35 options.services.certspotter = { 36 enable = lib.mkEnableOption "Cert Spotter, a Certificate Transparency log monitor"; 37 38 package = lib.mkPackageOption pkgs "certspotter" { }; 39 40 startAtEnd = lib.mkOption { 41 type = lib.types.bool; 42 description = '' 43 Whether to skip certificates issued before the first launch of Cert Spotter. 44 Setting this to `false` will cause Cert Spotter to download tens of terabytes of data. 45 ''; 46 default = true; 47 }; 48 49 sendmailPath = lib.mkOption { 50 type = with lib.types; nullOr path; 51 description = '' 52 Path to the `sendmail` binary. By default, the local sendmail wrapper is used 53 (see {option}`services.mail.sendmailSetuidWrapper`}). 54 ''; 55 example = lib.literalExpression ''"''${pkgs.system-sendmail}/bin/sendmail"''; 56 }; 57 58 watchlist = lib.mkOption { 59 type = with lib.types; listOf str; 60 description = "Domain names to watch. To monitor a domain with all subdomains, prefix its name with `.` (e.g. `.example.org`)."; 61 default = [ ]; 62 example = [ 63 ".example.org" 64 "another.example.com" 65 ]; 66 }; 67 68 emailRecipients = lib.mkOption { 69 type = with lib.types; listOf str; 70 description = "A list of email addresses to send certificate updates to."; 71 default = [ ]; 72 }; 73 74 hooks = lib.mkOption { 75 type = with lib.types; listOf path; 76 description = '' 77 Scripts to run upon the detection of a new certificate. See `man 8 certspotter-script` or 78 [the GitHub page](https://github.com/SSLMate/certspotter/blob/${ 79 pkgs.certspotter.src.rev or "master" 80 }/man/certspotter-script.md) 81 for more info. 82 ''; 83 default = [ ]; 84 example = lib.literalExpression '' 85 [ 86 (pkgs.writeShellScript "certspotter-hook" ''' 87 echo "Event summary: $SUMMARY." 88 ''') 89 ] 90 ''; 91 }; 92 93 extraFlags = lib.mkOption { 94 type = with lib.types; listOf str; 95 description = "Extra command-line arguments to pass to Cert Spotter"; 96 example = [ "-no_save" ]; 97 default = [ ]; 98 }; 99 }; 100 101 config = lib.mkIf cfg.enable { 102 assertions = [ 103 { 104 assertion = (cfg.emailRecipients != [ ]) -> (cfg.sendmailPath != null); 105 message = '' 106 You must configure the sendmail setuid wrapper (services.mail.sendmailSetuidWrapper) 107 or services.certspotter.sendmailPath 108 ''; 109 } 110 ]; 111 112 services.certspotter.sendmailPath = 113 let 114 inherit (config.security) wrapperDir; 115 inherit (config.services.mail) sendmailSetuidWrapper; 116 in 117 lib.mkMerge [ 118 (lib.mkIf (sendmailSetuidWrapper != null) ( 119 lib.mkOptionDefault "${wrapperDir}/${sendmailSetuidWrapper.program}" 120 )) 121 (lib.mkIf (sendmailSetuidWrapper == null) (lib.mkOptionDefault null)) 122 ]; 123 124 users.users.certspotter = { 125 description = "Cert Spotter user"; 126 group = "certspotter"; 127 home = "/var/lib/certspotter"; 128 isSystemUser = true; 129 }; 130 users.groups.certspotter = { }; 131 132 systemd.services.certspotter = { 133 description = "Cert Spotter - Certificate Transparency Monitor"; 134 after = [ "network.target" ]; 135 wantedBy = [ "multi-user.target" ]; 136 environment.CERTSPOTTER_CONFIG_DIR = configDir; 137 environment.SENDMAIL_PATH = 138 if cfg.sendmailPath != null then cfg.sendmailPath else "/run/current-system/sw/bin/false"; 139 script = '' 140 export CERTSPOTTER_STATE_DIR="$STATE_DIRECTORY" 141 cd "$CERTSPOTTER_STATE_DIR" 142 ${lib.optionalString cfg.startAtEnd '' 143 if [[ ! -d logs ]]; then 144 # Don't download certificates issued before the first launch 145 exec ${cfg.package}/bin/certspotter -start_at_end ${lib.escapeShellArgs cfg.extraFlags} 146 fi 147 ''} 148 exec ${cfg.package}/bin/certspotter ${lib.escapeShellArgs cfg.extraFlags} 149 ''; 150 serviceConfig = { 151 User = "certspotter"; 152 Group = "certspotter"; 153 StateDirectory = "certspotter"; 154 }; 155 }; 156 }; 157 158 meta.maintainers = with lib.maintainers; [ chayleaf ]; 159 meta.doc = ./certspotter.md; 160}