server: add certspotter
This commit is contained in:
parent
eda0322bc7
commit
67f43298e8
|
@ -156,6 +156,7 @@
|
||||||
./system/devices/radxa-rock5a-server.nix
|
./system/devices/radxa-rock5a-server.nix
|
||||||
(if devMaubot then import /${devPath}/maubot.nix/module else maubot.nixosModules.default)
|
(if devMaubot then import /${devPath}/maubot.nix/module else maubot.nixosModules.default)
|
||||||
./system/modules/scanservjs.nix
|
./system/modules/scanservjs.nix
|
||||||
|
./system/modules/certspotter.nix
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
server-cross = crossConfig server;
|
server-cross = crossConfig server;
|
||||||
|
|
71
pkgs/certspotter/configurable-sendmail.patch
Normal file
71
pkgs/certspotter/configurable-sendmail.patch
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
diff --git a/cmd/certspotter/main.go b/cmd/certspotter/main.go
|
||||||
|
index 9730789..f2eb081 100644
|
||||||
|
--- a/cmd/certspotter/main.go
|
||||||
|
+++ b/cmd/certspotter/main.go
|
||||||
|
@@ -163,6 +163,7 @@ func main() {
|
||||||
|
logs string
|
||||||
|
noSave bool
|
||||||
|
script string
|
||||||
|
+ sendmail string
|
||||||
|
startAtEnd bool
|
||||||
|
stateDir string
|
||||||
|
stdout bool
|
||||||
|
@@ -176,6 +177,7 @@ func main() {
|
||||||
|
flag.StringVar(&flags.logs, "logs", defaultLogList, "File path or URL of JSON list of logs to monitor")
|
||||||
|
flag.BoolVar(&flags.noSave, "no_save", false, "Do not save a copy of matching certificates in state directory")
|
||||||
|
flag.StringVar(&flags.script, "script", "", "Program to execute when a matching certificate is discovered")
|
||||||
|
+ flag.StringVar(&flags.sendmail, "sendmail", "/usr/sbin/sendmail", "Path to the sendmail-compatible program to use")
|
||||||
|
flag.BoolVar(&flags.startAtEnd, "start_at_end", false, "Start monitoring logs from the end rather than the beginning (saves considerable bandwidth)")
|
||||||
|
flag.StringVar(&flags.stateDir, "state_dir", defaultStateDir(), "Directory for storing log position and discovered certificates")
|
||||||
|
flag.BoolVar(&flags.stdout, "stdout", false, "Write matching certificates to stdout")
|
||||||
|
@@ -201,6 +203,7 @@ func main() {
|
||||||
|
Verbose: flags.verbose,
|
||||||
|
Script: flags.script,
|
||||||
|
ScriptDir: defaultScriptDir(),
|
||||||
|
+ SendmailPath: flags.sendmail,
|
||||||
|
Email: flags.email,
|
||||||
|
Stdout: flags.stdout,
|
||||||
|
HealthCheckInterval: flags.healthcheck,
|
||||||
|
diff --git a/monitor/config.go b/monitor/config.go
|
||||||
|
index 1e0d60c..d1bc430 100644
|
||||||
|
--- a/monitor/config.go
|
||||||
|
+++ b/monitor/config.go
|
||||||
|
@@ -20,6 +20,7 @@ type Config struct {
|
||||||
|
WatchList WatchList
|
||||||
|
Verbose bool
|
||||||
|
SaveCerts bool
|
||||||
|
+ SendmailPath string
|
||||||
|
Script string
|
||||||
|
ScriptDir string
|
||||||
|
Email []string
|
||||||
|
diff --git a/monitor/notify.go b/monitor/notify.go
|
||||||
|
index 8fc6d09..86cabca 100644
|
||||||
|
--- a/monitor/notify.go
|
||||||
|
+++ b/monitor/notify.go
|
||||||
|
@@ -36,7 +36,7 @@ func notify(ctx context.Context, config *Config, notif notification) error {
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(config.Email) > 0 {
|
||||||
|
- if err := sendEmail(ctx, config.Email, notif); err != nil {
|
||||||
|
+ if err := sendEmail(ctx, config.SendmailPath, config.Email, notif); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -62,7 +62,7 @@ func writeToStdout(notif notification) {
|
||||||
|
os.Stdout.WriteString(notif.Text() + "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
-func sendEmail(ctx context.Context, to []string, notif notification) error {
|
||||||
|
+func sendEmail(ctx context.Context, sendmailPath string, to []string, notif notification) error {
|
||||||
|
stdin := new(bytes.Buffer)
|
||||||
|
stderr := new(bytes.Buffer)
|
||||||
|
|
||||||
|
@@ -77,7 +77,7 @@ func sendEmail(ctx context.Context, to []string, notif notification) error {
|
||||||
|
args := []string{"-i", "--"}
|
||||||
|
args = append(args, to...)
|
||||||
|
|
||||||
|
- sendmail := exec.CommandContext(ctx, "/usr/sbin/sendmail", args...)
|
||||||
|
+ sendmail := exec.CommandContext(ctx, sendmailPath, args...)
|
||||||
|
sendmail.Stdin = stdin
|
||||||
|
sendmail.Stderr = stderr
|
||||||
|
|
41
pkgs/certspotter/default.nix
Normal file
41
pkgs/certspotter/default.nix
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{ lib
|
||||||
|
, buildGoModule
|
||||||
|
, fetchFromGitHub
|
||||||
|
, lowdown
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildGoModule rec {
|
||||||
|
pname = "certspotter";
|
||||||
|
version = "0.16.0";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "SSLMate";
|
||||||
|
repo = "certspotter";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-0+7GWxbV4j2vVdmool8J9hqRqUi8O/yKedCyynWJDkE=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-haYmWc2FWZNFwMhmSy3DAtj9oW5G82dX0fxpGqI8Hbw=";
|
||||||
|
|
||||||
|
patches = [ ./configurable-sendmail.patch ];
|
||||||
|
|
||||||
|
ldflags = [ "-s" "-w" ];
|
||||||
|
|
||||||
|
nativeBuildInputs = [ lowdown ];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
cd man
|
||||||
|
make
|
||||||
|
mkdir -p $out/share/man/man8
|
||||||
|
mv *.8 $out/share/man/man8
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Certificate Transparency Log Monitor";
|
||||||
|
homepage = "https://github.com/SSLMate/certspotter";
|
||||||
|
changelog = "https://github.com/SSLMate/certspotter/blob/${src.rev}/CHANGELOG.md";
|
||||||
|
license = licenses.mpl20;
|
||||||
|
mainProgram = "certspotter";
|
||||||
|
maintainers = with maintainers; [ chayleaf ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -60,6 +60,7 @@ in
|
||||||
meta = builtins.removeAttrs old.meta [ "broken" ];
|
meta = builtins.removeAttrs old.meta [ "broken" ];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
certspotter = callPackage ./certspotter { };
|
||||||
clang-tools_latest = pkgs.clang-tools_16;
|
clang-tools_latest = pkgs.clang-tools_16;
|
||||||
clang_latest = pkgs.clang_16;
|
clang_latest = pkgs.clang_16;
|
||||||
/*ghidra = pkgs.ghidra.overrideAttrs (old: {
|
/*ghidra = pkgs.ghidra.overrideAttrs (old: {
|
||||||
|
|
|
@ -349,6 +349,25 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
users.users.certspotter.extraGroups = [ "acme" ];
|
||||||
|
services.certspotter = {
|
||||||
|
enable = true;
|
||||||
|
watchlist = [ ".pavluk.org" ];
|
||||||
|
hooks = let
|
||||||
|
openssl = "${pkgs.openssl.bin}/bin/openssl";
|
||||||
|
in lib.toList (pkgs.writeShellScript "certspotter-hook" ''
|
||||||
|
if [[ "$EVENT" == discovered_cert ]]; then
|
||||||
|
mkdir -p /var/lib/certspotter/allowed_tbs
|
||||||
|
for cert in $(find /var/lib/acme -regex ".*/fullchain.pem"); do
|
||||||
|
hash="$(${openssl} x509 -in "$cert" -pubkey -noout | ${openssl} pkey -pubin -outform DER | ${openssl} sha256 | cut -d" " -f2)"
|
||||||
|
touch "/var/lib/certspotter/allowed_tbs/$hash"
|
||||||
|
done
|
||||||
|
[[ -f "/var/lib/certspotter/allowed_tbs/$TBS_SHA256" ]] && exit 0
|
||||||
|
fi
|
||||||
|
(echo "Subject: $SUMMARY" && echo && cat "$TEXT_FILENAME") | /run/wrappers/bin/sendmail -i webmaster-certspotter@${cfg.domainName}
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
/*locations."/dns-query".extraConfig = ''
|
/*locations."/dns-query".extraConfig = ''
|
||||||
grpc_pass grpc://127.0.0.1:53453;
|
grpc_pass grpc://127.0.0.1:53453;
|
||||||
'';*/
|
'';*/
|
||||||
|
|
112
system/modules/certspotter.nix
Normal file
112
system/modules/certspotter.nix
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
{ config
|
||||||
|
, lib
|
||||||
|
, pkgs
|
||||||
|
, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.certspotter;
|
||||||
|
in {
|
||||||
|
options.services.certspotter = {
|
||||||
|
enable = lib.mkEnableOption "Cert Spotter, a Certificate Transparency log monitor";
|
||||||
|
sendmailPath = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
description = ''
|
||||||
|
Path to the `sendmail` binary. By default, the local sendmail wrapper is used
|
||||||
|
(see `config.services.mail.sendmailSetuidWrapper`).
|
||||||
|
'';
|
||||||
|
example = lib.literalExpression ''"''${pkgs.system-sendmail}/bin/sendmail"'';
|
||||||
|
};
|
||||||
|
watchlist = lib.mkOption {
|
||||||
|
type = with lib.types; listOf str;
|
||||||
|
description = "Domain names to watch. To monitor a domain with all subdomains, prefix its name with `.` (e.g. `.example.org`).";
|
||||||
|
default = [ ];
|
||||||
|
example = [ ".example.org" "another.example.com" ];
|
||||||
|
};
|
||||||
|
emailRecipients = lib.mkOption {
|
||||||
|
type = with lib.types; listOf str;
|
||||||
|
description = "A list of email addresses to send certificate updates to.";
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
hooks = lib.mkOption {
|
||||||
|
type = with lib.types; listOf path;
|
||||||
|
description = ''
|
||||||
|
Scripts to run upon the detection of a new certificate. See `man 8 certspotter-script` or [the GitHub page](https://github.com/SSLMate/certspotter/blob/master/man/certspotter-script.md) for more info.
|
||||||
|
'';
|
||||||
|
default = [];
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
[
|
||||||
|
(pkgs.writeShellScript "certspotter-hook" '''
|
||||||
|
echo "Event summary: $SUMMARY."
|
||||||
|
''')
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
extraFlags = lib.mkOption {
|
||||||
|
type = with lib.types; listOf str;
|
||||||
|
description = "Extra command-line arguments to pass to Cert Spotter";
|
||||||
|
example = [ "-start_at_end" ];
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = cfg.watchlist != [ ];
|
||||||
|
message = "You must specify at least one domain for Cert Spotter to watch";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.hooks != [] || cfg.emailRecipients != [];
|
||||||
|
message = "You must specify at least one hook or email recipient for Cert Spotter";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = (cfg.emailRecipients != []) -> (cfg.sendmailPath != "/run/current-system/sw/bin/false");
|
||||||
|
message = ''
|
||||||
|
You must configure the sendmail setuid wrapper (services.mail.sendmailSetuidWrapper)
|
||||||
|
or services.certspotter.sendmailPath
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.certspotter.sendmailPath = lib.mkMerge [
|
||||||
|
(lib.mkIf (config.services.mail.sendmailSetuidWrapper != null) (lib.mkOptionDefault "/run/wrappers/bin/sendmail"))
|
||||||
|
(lib.mkIf (config.services.mail.sendmailSetuidWrapper == null) (lib.mkOptionDefault "/run/current-system/sw/bin/false"))
|
||||||
|
];
|
||||||
|
users.users.certspotter = {
|
||||||
|
group = "certspotter";
|
||||||
|
home = "/var/lib/certspotter";
|
||||||
|
createHome = true;
|
||||||
|
isSystemUser = true;
|
||||||
|
# uid = config.ids.uids.certspotter;
|
||||||
|
};
|
||||||
|
users.groups.certspotter = {
|
||||||
|
# gid = config.ids.gids.certspotter;
|
||||||
|
};
|
||||||
|
systemd.services.certspotter = {
|
||||||
|
description = "Cert Spotter - Certificate Transparency Monitor";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
environment.CERTSPOTTER_CONFIG_DIR = pkgs.linkFarm "certspotter-config"
|
||||||
|
(lib.toList {
|
||||||
|
name = "watchlist";
|
||||||
|
path = pkgs.writeText "cerspotter-watchlist" (builtins.concatStringsSep "\n" cfg.watchlist);
|
||||||
|
}
|
||||||
|
++ lib.optional (cfg.emailRecipients != [ ]) {
|
||||||
|
name = "email_recipients";
|
||||||
|
path = pkgs.writeText "cerspotter-email_recipients" (builtins.concatStringsSep "\n" cfg.emailRecipients);
|
||||||
|
}
|
||||||
|
++ lib.optional (cfg.hooks != [ ]) {
|
||||||
|
name = "hooks.d";
|
||||||
|
path = pkgs.linkFarm "certspotter-hooks" (lib.imap1 (i: path: {
|
||||||
|
inherit path;
|
||||||
|
name = "hook${toString i}";
|
||||||
|
}) cfg.hooks);
|
||||||
|
});
|
||||||
|
environment.CERTSPOTTER_STATE_DIR = "/var/lib/certspotter";
|
||||||
|
serviceConfig = {
|
||||||
|
User = "certspotter";
|
||||||
|
Group = "certspotter";
|
||||||
|
WorkingDirectory = "/var/lib/certspotter";
|
||||||
|
ExecStart = "${pkgs.certspotter}/bin/certspotter -sendmail ${cfg.sendmailPath} ${lib.escapeShellArgs cfg.extraFlags}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue