lol

Merge pull request #262915 from chayleaf/certspotter

certspotter: init at 0.17.0; nixos/certspotter: init

authored by

Peder Bergebakken Sundt and committed by
GitHub
37c7104f 16f39dd7

+259
+2
nixos/doc/manual/release-notes/rl-2311.section.md
··· 113 113 114 114 - [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for interacting with hardware from TUXEDO Computers. 115 115 116 + - [certspotter](https://github.com/SSLMate/certspotter), a certificate transparency log monitor. Available as [services.certspotter](#opt-services.certspotter.enable). 117 + 116 118 - [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted audiobook and podcast server. Available as [services.audiobookshelf](#opt-services.audiobookshelf.enable). 117 119 118 120 - [ZITADEL](https://zitadel.com), a turnkey identity and access management platform. Available as [services.zitadel](#opt-services.zitadel.enable).
+1
nixos/modules/module-list.nix
··· 767 767 ./services/monitoring/below.nix 768 768 ./services/monitoring/bosun.nix 769 769 ./services/monitoring/cadvisor.nix 770 + ./services/monitoring/certspotter.nix 770 771 ./services/monitoring/cockpit.nix 771 772 ./services/monitoring/collectd.nix 772 773 ./services/monitoring/das_watchdog.nix
+74
nixos/modules/services/monitoring/certspotter.md
··· 1 + # Cert Spotter {#module-services-certspotter} 2 + 3 + Cert Spotter is a tool for monitoring [Certificate Transparency](https://en.wikipedia.org/wiki/Certificate_Transparency) 4 + logs. 5 + 6 + ## Service Configuration {#modules-services-certspotter-service-configuration} 7 + 8 + A basic config that notifies you of all certificate changes for your 9 + domain would look as follows: 10 + 11 + ```nix 12 + services.certspotter = { 13 + enable = true; 14 + # replace example.org with your domain name 15 + watchlist = [ ".example.org" ]; 16 + emailRecipients = [ "webmaster@example.org" ]; 17 + }; 18 + 19 + # Configure an SMTP client 20 + programs.msmtp.enable = true; 21 + # Or you can use any other module that provides sendmail, like 22 + # services.nullmailer, services.opensmtpd, services.postfix 23 + ``` 24 + 25 + In this case, the leading dot in `".example.org"` means that Cert 26 + Spotter should monitor not only `example.org`, but also all of its 27 + subdomains. 28 + 29 + ## Operation {#modules-services-certspotter-operation} 30 + 31 + **By default, NixOS configures Cert Spotter to skip all certificates 32 + issued before its first launch**, because checking the entire 33 + Certificate Transparency logs requires downloading tens of terabytes of 34 + data. If you want to check the *entire* logs for previously issued 35 + certificates, you have to set `services.certspotter.startAtEnd` to 36 + `false` and remove all previously saved log state in 37 + `/var/lib/certspotter/logs`. The downloaded logs aren't saved, so if you 38 + add a new domain to the watchlist and want Cert Spotter to go through 39 + the logs again, you will have to remove `/var/lib/certspotter/logs` 40 + again. 41 + 42 + After catching up with the logs, Cert Spotter will start monitoring live 43 + logs. As of October 2023, it uses around **20 Mbps** of traffic on 44 + average. 45 + 46 + ## Hooks {#modules-services-certspotter-hooks} 47 + 48 + Cert Spotter supports running custom hooks instead of (or in addition 49 + to) sending emails. Hooks are shell scripts that will be passed certain 50 + environment variables. 51 + 52 + To see hook documentation, see Cert Spotter's man pages: 53 + 54 + ```ShellSession 55 + nix-shell -p certspotter --run 'man 8 certspotter-script' 56 + ``` 57 + 58 + For example, you can remove `emailRecipients` and send email 59 + notifications manually using the following hook: 60 + 61 + ```nix 62 + services.certspotter.hooks = [ 63 + (pkgs.writeShellScript "certspotter-hook" '' 64 + function print_email() { 65 + echo "Subject: [certspotter] $SUMMARY" 66 + echo "Mime-Version: 1.0" 67 + echo "Content-Type: text/plain; charset=US-ASCII" 68 + echo 69 + cat "$TEXT_FILENAME" 70 + } 71 + print_email | ${config.services.certspotter.sendmailPath} -i webmaster@example.org 72 + '') 73 + ]; 74 + ```
+143
nixos/modules/services/monitoring/certspotter.nix
··· 1 + { config 2 + , lib 3 + , pkgs 4 + , ... }: 5 + 6 + let 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 + }); 26 + in 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 + }
+39
pkgs/by-name/ce/certspotter/package.nix
··· 1 + { lib 2 + , fetchFromGitHub 3 + , buildGoModule 4 + , lowdown 5 + }: 6 + 7 + buildGoModule rec { 8 + pname = "certspotter"; 9 + version = "0.17.0"; 10 + 11 + src = fetchFromGitHub { 12 + owner = "SSLMate"; 13 + repo = "certspotter"; 14 + rev = "v${version}"; 15 + hash = "sha256-6ghS+9b8FZiYdiTk54XRHP46lOq98sN1RDYvRYTt6eU="; 16 + }; 17 + 18 + vendorHash = "sha256-6dV9FoPV8UfS0z5RuuopE99fHcT3RAWCdDi7jpHzVRE="; 19 + 20 + ldflags = [ "-s" "-w" ]; 21 + 22 + nativeBuildInputs = [ lowdown ]; 23 + 24 + postInstall = '' 25 + cd man 26 + make 27 + mkdir -p $out/share/man/man8 28 + mv *.8 $out/share/man/man8 29 + ''; 30 + 31 + meta = with lib; { 32 + description = "Certificate Transparency Log Monitor"; 33 + homepage = "https://github.com/SSLMate/certspotter"; 34 + changelog = "https://github.com/SSLMate/certspotter/blob/${src.rev}/CHANGELOG.md"; 35 + license = licenses.mpl20; 36 + mainProgram = "certspotter"; 37 + maintainers = with maintainers; [ chayleaf ]; 38 + }; 39 + }