Install postgres and dendrite
diff --git a/modules/grafana.nix b/modules/grafana.nix
index 69c231e..6aee70f 100644
--- a/modules/grafana.nix
+++ b/modules/grafana.nix
@@ -1,15 +1,26 @@
-{
+{ lib, config, ... }: {
services.grafana = {
enable = true;
settings = {
server = rec {
domain = "logs.clicks.codes";
- root_url ="https://${domain}";
+ root_url = "https://${domain}";
http_port = 9052;
enable_gzip = true;
};
analytics.reporting_enabled = false;
};
+
+ provision.datasources.settings.datasources = [{
+ name = "clicks-postgresql";
+ type = "postgres";
+ access = "proxy";
+
+ url = "postgres://localhost:${toString config.services.postgresql.port}";
+ user = "clicks_grafana";
+ password = "$__file{${config.sops.secrets.clicks_grafana_db_password.path}}";
+ # defined in postgres.nix
+ }];
};
}
diff --git a/modules/home-manager-users.nix b/modules/home-manager-users.nix
index e83e0cb..a3f450e 100644
--- a/modules/home-manager-users.nix
+++ b/modules/home-manager-users.nix
@@ -1,6 +1,6 @@
# Home manager is used separately from this deploy, but we still need to create
# user accounts in the system config
-{ pkgs, lib, ... }:
+{ base, pkgs, lib, config, ... }:
let
mkUser = username: {
isSystemUser = true;
@@ -9,7 +9,11 @@
home = "/services/${username}";
group = "clicks";
shell = pkgs.bashInteractive;
- };
+ } // (
+ if builtins.pathExists "${../services}/${username}/system.nix"
+ then import "${../services}/${username}/system.nix"
+ else { }
+ );
in
{
imports = [
@@ -26,4 +30,14 @@
(map (name: { inherit name; value = mkUser name; }))
builtins.listToAttrs
];
-}
+} // (
+ if (base != null)
+ then {
+/* users.groups = lib.mapAttrs'
+ (_: user: {
+ name = user.group;
+ value = { };
+ })
+ base.config.users.users;*/
+ } else { }
+)
diff --git a/modules/matrix.nix b/modules/matrix.nix
new file mode 100644
index 0000000..f669943
--- /dev/null
+++ b/modules/matrix.nix
@@ -0,0 +1,103 @@
+{ base, config, lib, pkgs, ... }:
+let
+ postgresUrlFor = service:
+ "postgres://dendrite:!!dendrite_db_password!!@localhost:${toString config.services.postgresql.port}/dendrite_${service}?sslmode=disable";
+in
+{
+ services.dendrite = {
+ enable = true;
+ httpPort = 4527;
+ settings = {
+ global = {
+ server_name = "coded.codes";
+ private_key = config.sops.secrets.matrix_private_key.path;
+ };
+ user_api = {
+ account_database.connection_string = postgresUrlFor "account_database";
+ device_database.connection_string = postgresUrlFor "device_database";
+ };
+ sync_api = {
+ search.enable = true;
+ database.connection_string = postgresUrlFor "sync_api";
+ };
+ room_server.database.connection_string = postgresUrlFor "room_server";
+ mscs.database.connection_string = postgresUrlFor "mscs";
+ media_api.database.connection_string = postgresUrlFor "media_api";
+ key_server.database.connection_string = postgresUrlFor "key_server";
+ federation_api.database.connection_string = postgresUrlFor "federation_api";
+ app_service_api.database.connection_string = postgresUrlFor "app_service_api";
+
+ client_api.registration_shared_secret = "!!registration_shared_secret!!";
+ };
+ };
+
+ users.users.dendrite = {
+ isSystemUser = true;
+ createHome = true;
+ home = config.systemd.services.dendrite.serviceConfig.WorkingDirectory;
+ group = "clicks";
+ shell = pkgs.bashInteractive;
+ };
+
+ systemd.services.dendrite.serviceConfig = {
+ DynamicUser = lib.mkForce false;
+ User = lib.mkForce config.users.users.dendrite.name;
+ Group = lib.mkForce config.users.users.dendrite.group;
+ };
+
+ sops.secrets = (lib.pipe [
+ "registration_shared_secret"
+ ] [
+ (map (name: {
+ inherit name;
+ value = {
+ mode = "0400";
+ owner = config.users.users.root.name;
+ group = config.users.users.nobody.group;
+ sopsFile = ../secrets/matrix.json;
+ format = "json";
+ };
+ }))
+ builtins.listToAttrs
+ ]) // {
+ matrix_private_key = {
+ mode = "0400";
+ owner = config.users.users.dendrite.name;
+ group = config.users.users.dendrite.group;
+ sopsFile = ../secrets/matrix_private_key.pem;
+ format = "binary";
+ };
+ };
+} // (
+ let
+ isDerived = base != null;
+ in
+ if isDerived
+ # We cannot use mkIf as both sides are evaluated no matter the condition value
+ # Given we use base as an attrset, mkIf will error if base is null in here
+ then
+ let
+ ExecStartPre = "${base.config.systemd.services.dendrite.serviceConfig.ExecStartPre}";
+ dendrite_cfgfile = builtins.head (builtins.match ".*-i ([^[:space:]]+).*" "${ExecStartPre}");
+ in
+ {
+ scalpel.trafos."dendrite.yaml" = {
+ source = dendrite_cfgfile;
+ matchers."dendrite_db_password".secret =
+ config.sops.secrets.dendrite_db_password.path; # Defined in postgres.nix
+ matchers."registration_shared_secret".secret =
+ config.sops.secrets.registration_shared_secret.path;
+ owner = config.users.users.dendrite.name;
+ group = config.users.users.dendrite.group;
+ mode = "0400";
+ };
+
+ systemd.services.dendrite.serviceConfig.ExecStartPre = lib.mkForce (
+ builtins.replaceStrings
+ [ "${dendrite_cfgfile}" ]
+ [ "${config.scalpel.trafos."dendrite.yaml".destination}" ]
+ "${ExecStartPre}"
+ );
+ }
+ else { }
+)
diff --git a/modules/postgres.nix b/modules/postgres.nix
new file mode 100644
index 0000000..63e7697
--- /dev/null
+++ b/modules/postgres.nix
@@ -0,0 +1,84 @@
+{ lib, config, pkgs, ... }: {
+ services.postgresql = {
+ enable = true;
+
+ package = pkgs.postgresql;
+ settings = {
+ log_connections = true;
+ log_statement = "all";
+ logging_collector = true;
+ log_disconnections = true;
+ log_destination = lib.mkForce "syslog";
+ };
+
+ ensureUsers = [
+ {
+ name = "clicks_grafana";
+ ensurePermissions = {
+ "ALL TABLES IN SCHEMA public" = "SELECT";
+ "SCHEMA public" = "USAGE";
+ };
+ }
+ {
+ name = "dendrite";
+ ensurePermissions = {
+ "DATABASE dendrite_account_database" = "ALL PRIVILEGES";
+ "DATABASE dendrite_device_database" = "ALL PRIVILEGES";
+ "DATABASE dendrite_sync_api" = "ALL PRIVILEGES";
+ "DATABASE dendrite_room_server" = "ALL PRIVILEGES";
+ "DATABASE dendrite_mscs" = "ALL PRIVILEGES";
+ "DATABASE dendrite_media_api" = "ALL PRIVILEGES";
+ "DATABASE dendrite_key_server" = "ALL PRIVILEGES";
+ "DATABASE dendrite_federation_api" = "ALL PRIVILEGES";
+ "DATABASE dendrite_app_service_api" = "ALL PRIVILEGES";
+ };
+ }
+ ] ++ (map
+ (name: (
+ {
+ inherit name;
+ ensurePermissions = { "ALL TABLES IN SCHEMA public" = "ALL PRIVILEGES"; };
+ }
+ )) [ "minion" "coded" "pinea" ]);
+
+ ensureDatabases = [
+ "dendrite_account_database"
+ "dendrite_device_database"
+ "dendrite_sync_api"
+ "dendrite_sync_api"
+ "dendrite_room_server"
+ "dendrite_mscs"
+ "dendrite_media_api"
+ "dendrite_key_server"
+ "dendrite_federation_api"
+ "dendrite_app_service_api"
+ ];
+ };
+
+ systemd.services.postgresql.postStart = lib.mkAfter (lib.pipe [
+ { user = "clicks_grafana"; passwordFile = config.sops.secrets.clicks_grafana_db_password.path; }
+ { user = "dendrite"; passwordFile = config.sops.secrets.dendrite_db_password.path; }
+ ] [
+ (map (userData: ''
+ $PSQL -tAc "ALTER USER ${userData.user} PASSWORD '$(cat ${userData.passwordFile})';"
+ ''))
+ (lib.concatStringsSep "\n")
+ ]);
+
+ sops.secrets = lib.pipe [
+ "clicks_grafana_db_password"
+ "dendrite_db_password"
+ ] [
+ (map (name: {
+ inherit name;
+ value = {
+ mode = "0400";
+ owner = config.services.postgresql.superUser;
+ group = config.users.users.${config.services.postgresql.superUser}.group;
+ sopsFile = ../secrets/postgres.json;
+ format = "json";
+ };
+ }))
+ builtins.listToAttrs
+ ];
+}
diff --git a/modules/scalpel.nix b/modules/scalpel.nix
new file mode 100644
index 0000000..569d2b4
--- /dev/null
+++ b/modules/scalpel.nix
@@ -0,0 +1,12 @@
+{ lib, config, ... }: let
+ cfg = config.scalpel;
+in {
+ system.activationScripts.scalpelCreateStore.text = lib.mkForce ''
+ echo "[scalpel] Ensuring existance of ${cfg.secretsDir}"
+ mkdir -p ${cfg.secretsDir}
+ grep -q "${cfg.secretsDir} ramfs" /proc/mounts || mount -t ramfs none "${cfg.secretsDir}" -o nodev,nosuid,mode=0751
+
+ echo "[scalpel] Clearing old secrets from ${cfg.secretsDir}"
+ find '${cfg.secretsDir}' -wholename '${cfg.secretsDir}' -o -prune -exec rm -rf -- {} +
+ '';
+}