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