From 9e9f7c4aa648ff7fa4d919a235bcce068d3f5fd0 Mon Sep 17 00:00:00 2001 From: Sanjin Sehic Date: Thu, 24 Aug 2023 08:50:48 +0100 Subject: [PATCH 1/3] nixos/healthchecks: define default DB_NAME for postgres and mysql Previously, if someone changed DB to postgres or mysql and forgot to change DB_NAME, services.healthchecks would have used the hardcoded path that was meant for the sqlite as DB_NAME. This change introduces DB and DB_NAME options in services.healthchecks.settings. --- .../services/web-apps/healthchecks.nix | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix index b3fdb681e2f3..657cf387d9ee 100644 --- a/nixos/modules/services/web-apps/healthchecks.nix +++ b/nixos/modules/services/web-apps/healthchecks.nix @@ -1,16 +1,16 @@ -{ config, lib, pkgs, buildEnv, ... }: +{ config, lib, options, pkgs, buildEnv, ... }: with lib; let defaultUser = "healthchecks"; cfg = config.services.healthchecks; + opt = options.services.healthchecks; pkg = cfg.package; boolToPython = b: if b then "True" else "False"; environment = { PYTHONPATH = pkg.pythonPath; STATIC_ROOT = cfg.dataDir + "/static"; - DB_NAME = "${cfg.dataDir}/healthchecks.sqlite"; } // cfg.settings; environmentFile = pkgs.writeText "healthchecks-environment" (lib.generators.toKeyValue { } environment); @@ -98,7 +98,7 @@ in description = lib.mdDoc '' Environment variables which are read by healthchecks `(local)_settings.py`. - Settings which are explicitly covered in options bewlow, are type-checked and/or transformed + Settings which are explicitly covered in options below, are type-checked and/or transformed before added to the environment, everything else is passed as a string. See @@ -108,7 +108,7 @@ in - STATIC_ROOT to set a state directory for dynamically generated static files. - SECRET_KEY_FILE to read SECRET_KEY from a file at runtime and keep it out of /nix/store. ''; - type = types.submodule { + type = types.submodule (settings: { freeformType = types.attrsOf types.str; options = { ALLOWED_HOSTS = lib.mkOption { @@ -143,8 +143,28 @@ in ''; apply = boolToPython; }; + + DB = mkOption { + type = types.enum [ "sqlite" "postgres" "mysql" ]; + default = "sqlite"; + description = lib.mdDoc "Database engine to use."; + }; + + DB_NAME = mkOption { + type = types.str; + default = + if settings.config.DB == "sqlite" + then "${cfg.dataDir}/healthchecks.sqlite" + else "hc"; + defaultText = lib.literalExpression '' + if config.${settings.options.DB} == "sqlite" + then "''${config.${opt.dataDir}}/healthchecks.sqlite" + else "hc" + ''; + description = lib.mdDoc "Database name."; + }; }; - }; + }); }; }; @@ -168,7 +188,7 @@ in StateDirectoryMode = mkIf (cfg.dataDir == "/var/lib/healthchecks") "0750"; }; in - { + { healthchecks-migration = { description = "Healthchecks migrations"; wantedBy = [ "healthchecks.target" ]; From 4a81613aa6cd11349948476f17daf350b4d07740 Mon Sep 17 00:00:00 2001 From: Sanjin Sehic Date: Fri, 25 Aug 2023 08:59:06 +0100 Subject: [PATCH 2/3] nixos/healthchecks: add EMAIL_HOST_PASSWORD_FILE option This allows keeping EMAIL_HOST_PASSWORD out of /nix/store. --- nixos/modules/services/web-apps/healthchecks.nix | 8 ++++++++ pkgs/servers/web-apps/healthchecks/default.nix | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix index 657cf387d9ee..3b541e12481b 100644 --- a/nixos/modules/services/web-apps/healthchecks.nix +++ b/nixos/modules/services/web-apps/healthchecks.nix @@ -107,6 +107,8 @@ in We add two variables to this list inside the packages `local_settings.py.` - STATIC_ROOT to set a state directory for dynamically generated static files. - SECRET_KEY_FILE to read SECRET_KEY from a file at runtime and keep it out of /nix/store. + - EMAIL_HOST_PASSWORD_FILE to read EMAIL_HOST_PASSWORD from a file at runtime and keep it + out of /nix/store. ''; type = types.submodule (settings: { freeformType = types.attrsOf types.str; @@ -163,6 +165,12 @@ in ''; description = lib.mdDoc "Database name."; }; + + EMAIL_HOST_PASSWORD_FILE = mkOption { + type = types.str; + default = ""; + description = lib.mdDoc "Path to a file containing the email password."; + }; }; }); }; diff --git a/pkgs/servers/web-apps/healthchecks/default.nix b/pkgs/servers/web-apps/healthchecks/default.nix index 142a67d3367a..59ddf659832b 100644 --- a/pkgs/servers/web-apps/healthchecks/default.nix +++ b/pkgs/servers/web-apps/healthchecks/default.nix @@ -41,11 +41,18 @@ py.pkgs.buildPythonApplication rec { localSettings = writeText "local_settings.py" '' import os + STATIC_ROOT = os.getenv("STATIC_ROOT") + SECRET_KEY_FILE = os.getenv("SECRET_KEY_FILE") if SECRET_KEY_FILE: with open(SECRET_KEY_FILE, "r") as file: SECRET_KEY = file.readline() + + EMAIL_HOST_PASSWORD_FILE = os.getenv("EMAIL_HOST_PASSWORD_FILE") + if EMAIL_HOST_PASSWORD_FILE: + with open(EMAIL_HOST_PASSWORD_FILE, "r") as file: + EMAIL_HOST_PASSWORD = file.readline() ''; installPhase = '' From 7f5e8a01137bc1227673dd28b22a4a5c659cc9eb Mon Sep 17 00:00:00 2001 From: Sanjin Sehic Date: Fri, 25 Aug 2023 21:46:07 +0100 Subject: [PATCH 3/3] nixos/healthchecks: enable _FILE variants for all secrets This change enables _FILE variants for all secrets in Healthchecks configuration so they can be read from a file and not stored in /nix/store. In particular, it adds support for these secrets: DB_PASSWORD, DISCORD_CLIENT_SECRET, EMAIL_HOST_PASSWORD, LINENOTIFY_CLIENT_SECRET, MATRIX_ACCESS_TOKEN, PD_APP_ID, PUSHBULLET_CLIENT_SECRET, PUSHOVER_API_TOKEN, S3_SECRET_KEY, SECRET_KEY, SLACK_CLIENT_SECRET, TELEGRAM_TOKEN, TRELLO_APP_KEY, and TWILIO_AUTH. --- .../services/web-apps/healthchecks.nix | 21 ++++++------ .../servers/web-apps/healthchecks/default.nix | 34 ++++++++++++++----- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/nixos/modules/services/web-apps/healthchecks.nix b/nixos/modules/services/web-apps/healthchecks.nix index 3b541e12481b..b92525075541 100644 --- a/nixos/modules/services/web-apps/healthchecks.nix +++ b/nixos/modules/services/web-apps/healthchecks.nix @@ -104,11 +104,16 @@ in See for a full documentation of settings. - We add two variables to this list inside the packages `local_settings.py.` - - STATIC_ROOT to set a state directory for dynamically generated static files. - - SECRET_KEY_FILE to read SECRET_KEY from a file at runtime and keep it out of /nix/store. - - EMAIL_HOST_PASSWORD_FILE to read EMAIL_HOST_PASSWORD from a file at runtime and keep it - out of /nix/store. + We add additional variables to this list inside the packages `local_settings.py.` + - `STATIC_ROOT` to set a state directory for dynamically generated static files. + - `SECRET_KEY_FILE` to read `SECRET_KEY` from a file at runtime and keep it out of + /nix/store. + - `_FILE` variants for several values that hold sensitive information in + [Healthchecks configuration](https://healthchecks.io/docs/self_hosted_configuration/) so + that they also can be read from a file and kept out of /nix/store. To see which values + have support for a `_FILE` variant, run: + - `nix-instantiate --eval --expr '(import {}).healthchecks.secrets'` + - or `nix eval 'nixpkgs#healthchecks.secrets'` if the flake support has been enabled. ''; type = types.submodule (settings: { freeformType = types.attrsOf types.str; @@ -165,12 +170,6 @@ in ''; description = lib.mdDoc "Database name."; }; - - EMAIL_HOST_PASSWORD_FILE = mkOption { - type = types.str; - default = ""; - description = lib.mdDoc "Path to a file containing the email password."; - }; }; }); }; diff --git a/pkgs/servers/web-apps/healthchecks/default.nix b/pkgs/servers/web-apps/healthchecks/default.nix index 59ddf659832b..193452c4354c 100644 --- a/pkgs/servers/web-apps/healthchecks/default.nix +++ b/pkgs/servers/web-apps/healthchecks/default.nix @@ -39,20 +39,36 @@ py.pkgs.buildPythonApplication rec { whitenoise ]; + secrets = [ + "DB_PASSWORD" + "DISCORD_CLIENT_SECRET" + "EMAIL_HOST_PASSWORD" + "LINENOTIFY_CLIENT_SECRET" + "MATRIX_ACCESS_TOKEN" + "PD_APP_ID" + "PUSHBULLET_CLIENT_SECRET" + "PUSHOVER_API_TOKEN" + "S3_SECRET_KEY" + "SECRET_KEY" + "SLACK_CLIENT_SECRET" + "TELEGRAM_TOKEN" + "TRELLO_APP_KEY" + "TWILIO_AUTH" + ]; + localSettings = writeText "local_settings.py" '' import os STATIC_ROOT = os.getenv("STATIC_ROOT") - SECRET_KEY_FILE = os.getenv("SECRET_KEY_FILE") - if SECRET_KEY_FILE: - with open(SECRET_KEY_FILE, "r") as file: - SECRET_KEY = file.readline() - - EMAIL_HOST_PASSWORD_FILE = os.getenv("EMAIL_HOST_PASSWORD_FILE") - if EMAIL_HOST_PASSWORD_FILE: - with open(EMAIL_HOST_PASSWORD_FILE, "r") as file: - EMAIL_HOST_PASSWORD = file.readline() + ${lib.concatLines (map + (secret: '' + ${secret}_FILE = os.getenv("${secret}_FILE") + if ${secret}_FILE: + with open(${secret}_FILE, "r") as file: + ${secret} = file.readline() + '') + secrets)} ''; installPhase = ''