move passwords/keys to files so that they can be encrypted
This commit is contained in:
parent
105e95b886
commit
9d3a72de1f
1 changed files with 196 additions and 98 deletions
224
flake.nix
224
flake.nix
|
@ -155,14 +155,16 @@
|
||||||
cipher = lib.options.mkOption {
|
cipher = lib.options.mkOption {
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
password = lib.options.mkOption {
|
passwordFile = lib.options.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.path;
|
||||||
|
description = "Path to file containing encryption password.";
|
||||||
};
|
};
|
||||||
type = lib.options.mkOption {
|
type = lib.options.mkOption {
|
||||||
type = lib.types.enum [
|
type = lib.types.enum [
|
||||||
"aes-256-cbc"
|
"aes-256-cbc"
|
||||||
];
|
];
|
||||||
default = "aes-256-cbc";
|
default = "aes-256-cbc";
|
||||||
|
description = "Type of encryption to use.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -176,15 +178,36 @@
|
||||||
"azure"
|
"azure"
|
||||||
"b2"
|
"b2"
|
||||||
];
|
];
|
||||||
|
description = "The type of storage used for backups.";
|
||||||
|
};
|
||||||
|
azure = lib.options.mkOption {
|
||||||
|
type = lib.types.submodule {
|
||||||
|
options = {
|
||||||
|
accountName = lib.options.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
accountKeyFile = lib.options.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
};
|
||||||
|
container = lib.options.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
path = lib.options.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = { };
|
||||||
|
description = "Options for connecting to Azure Blob storage";
|
||||||
};
|
};
|
||||||
b2 = lib.options.mkOption {
|
b2 = lib.options.mkOption {
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
account_id = lib.options.mkOption {
|
accountId = lib.options.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
};
|
};
|
||||||
account_key = lib.options.mkOption {
|
accountKeyFile = lib.options.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.path;
|
||||||
};
|
};
|
||||||
endpoint = lib.options.mkOption {
|
endpoint = lib.options.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
@ -201,25 +224,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default = { };
|
default = { };
|
||||||
};
|
description = "Options for connection to BackBlaze B2";
|
||||||
azure = lib.options.mkOption {
|
|
||||||
type = lib.types.submodule {
|
|
||||||
options = {
|
|
||||||
account_name = lib.options.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
account_key = lib.options.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
container = lib.options.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
path = lib.options.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
default = { };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -262,6 +267,7 @@
|
||||||
};
|
};
|
||||||
password = lib.options.mkOption {
|
password = lib.options.mkOption {
|
||||||
type = lib.types.addCheck lib.types.str (x: lib.hasPrefix "SCRAM-SHA-256$" x);
|
type = lib.types.addCheck lib.types.str (x: lib.hasPrefix "SCRAM-SHA-256$" x);
|
||||||
|
description = "Encrypted password for the database account.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -326,41 +332,82 @@
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
rcloneConfig = pkgs.writeTextFile {
|
# rcloneConfig = pkgs.writeTextFile {
|
||||||
name = "rclone.conf";
|
# name = "rclone.conf";
|
||||||
text = {
|
# text = {
|
||||||
"b2" = ''
|
# "b2" = ''
|
||||||
[b2]
|
# [b2]
|
||||||
type = b2
|
# type = b2
|
||||||
account = ${cfg.backup.storage.b2.account_id}
|
# account = ${cfg.backup.storage.b2.accountId}
|
||||||
key = ${cfg.backup.storage.b2.account_key}
|
# key = ${cfg.backup.storage.b2.accountKey}
|
||||||
'';
|
# '';
|
||||||
"azure" = ''
|
# "azure" = ''
|
||||||
[azure]
|
# [azure]
|
||||||
type = azureblob
|
# type = azureblob
|
||||||
account = ${cfg.backup.storage.azure.account_name}
|
# account = ${cfg.backup.storage.azure.accountName}
|
||||||
key = ${cfg.backup.storage.azure.account_key}
|
# key = ${cfg.backup.storage.azure.accountKey}
|
||||||
'';
|
# '';
|
||||||
}.${cfg.backup.storage.type};
|
# }.${cfg.backup.storage.type};
|
||||||
|
# };
|
||||||
|
|
||||||
|
rcloneEnvironment = {
|
||||||
|
RCLONE_CONFIG = "/dev/null";
|
||||||
|
} // (
|
||||||
|
{
|
||||||
|
"azure" = {
|
||||||
|
RCLONE_CONFIG_AZURE_TYPE = "azureblob";
|
||||||
|
RCLONE_CONFIG_AZURE_ACCOUNT = cfg.backup.storage.azure.accountName;
|
||||||
};
|
};
|
||||||
|
"b2" = {
|
||||||
|
RCLONE_CONFIG_B2_TYPE = "b2";
|
||||||
|
RCLONE_CONFIG_B2_ACCOUNT = cfg.backup.storage.b2.accountId;
|
||||||
|
};
|
||||||
|
}.${cfg.backup.storage.type}
|
||||||
|
);
|
||||||
|
rcloneEnvironmentFiles = {
|
||||||
|
"azure" = {
|
||||||
|
RCLONE_CONFIG_AZURE_KEY = cfg.backup.storage.azure.accountKeyFile;
|
||||||
|
};
|
||||||
|
"b2" = {
|
||||||
|
RCLONE_CONFIG_B2_KEY = cfg.backup.storage.b2.accountKeyFile;
|
||||||
|
};
|
||||||
|
}.${cfg.backup.storage.type};
|
||||||
|
|
||||||
rclone = lib.mkIf (cfg.backup.enable) (
|
rclone = lib.mkIf (cfg.backup.enable) (
|
||||||
|
let
|
||||||
|
environment = lib.concatStringsSep "\n" (
|
||||||
|
lib.mapAttrsToList
|
||||||
|
(
|
||||||
|
n: v:
|
||||||
|
''export ${n}="${builtins.toString v}"''
|
||||||
|
)
|
||||||
|
rcloneEnvironment
|
||||||
|
);
|
||||||
|
environmentFiles = lib.concatStringsSep "\n" (
|
||||||
|
lib.mapAttrsToList
|
||||||
|
(
|
||||||
|
n: v:
|
||||||
|
''export ${n}=''$(<${v})''
|
||||||
|
)
|
||||||
|
rcloneEnvironmentFiles
|
||||||
|
);
|
||||||
|
in
|
||||||
pkgs.writeShellScriptBin "rclone" ''
|
pkgs.writeShellScriptBin "rclone" ''
|
||||||
exec ${pkgs.rclone}/bin/rclone --config ${rcloneConfig} "''$@"
|
${environment}
|
||||||
|
${environmentFiles}
|
||||||
|
exec ${pkgs.rclone}/bin/rclone "''$@"
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
|
||||||
rootDir = "/var/lib/postgresql";
|
rootDir = "/var/lib/postgresql";
|
||||||
dataDir = "${rootDir}/15";
|
dataDir = "${rootDir}/15";
|
||||||
|
|
||||||
pgbackrestEnvironment =
|
pgbackrestEnvironment = {
|
||||||
{
|
|
||||||
PGBACKREST_LOG_LEVEL_CONSOLE = cfg.backup.log.console;
|
PGBACKREST_LOG_LEVEL_CONSOLE = cfg.backup.log.console;
|
||||||
PGBACKREST_LOG_LEVEL_FILE = cfg.backup.log.file;
|
PGBACKREST_LOG_LEVEL_FILE = cfg.backup.log.file;
|
||||||
PGBACKREST_LOG_LEVEL_STDERR = cfg.backup.log.stderr;
|
PGBACKREST_LOG_LEVEL_STDERR = cfg.backup.log.stderr;
|
||||||
PGBACKREST_PG1_PATH = dataDir;
|
PGBACKREST_PG1_PATH = dataDir;
|
||||||
PGBACKREST_PROCESS_MAX = "${builtins.toString cfg.backup.processMax}";
|
PGBACKREST_PROCESS_MAX = "${builtins.toString cfg.backup.processMax}";
|
||||||
PGBACKREST_REPO1_CIPHER_PASS = cfg.backup.cipher.password;
|
|
||||||
PGBACKREST_REPO1_CIPHER_TYPE = cfg.backup.cipher.type;
|
PGBACKREST_REPO1_CIPHER_TYPE = cfg.backup.cipher.type;
|
||||||
PGBACKREST_REPO1_RETENTION_FULL = "14";
|
PGBACKREST_REPO1_RETENTION_FULL = "14";
|
||||||
PGBACKREST_REPO1_RETENTION_FULL_TYPE = "time";
|
PGBACKREST_REPO1_RETENTION_FULL_TYPE = "time";
|
||||||
|
@ -368,9 +415,8 @@
|
||||||
} // (
|
} // (
|
||||||
{
|
{
|
||||||
"azure" = {
|
"azure" = {
|
||||||
PGBACKREST_REPO1_AZURE_ACCOUNT = cfg.backup.storage.azure.account_name;
|
PGBACKREST_REPO1_AZURE_ACCOUNT = cfg.backup.storage.azure.accountName;
|
||||||
PGBACKREST_REPO1_AZURE_CONTAINER = cfg.backup.storage.azure.container;
|
PGBACKREST_REPO1_AZURE_CONTAINER = cfg.backup.storage.azure.container;
|
||||||
PGBACKREST_REPO1_AZURE_KEY = cfg.backup.storage.azure.account_key;
|
|
||||||
PGBACKREST_REPO1_PATH = cfg.backup.storage.azure.path;
|
PGBACKREST_REPO1_PATH = cfg.backup.storage.azure.path;
|
||||||
PGBACKREST_REPO1_TYPE = "azure";
|
PGBACKREST_REPO1_TYPE = "azure";
|
||||||
};
|
};
|
||||||
|
@ -378,14 +424,28 @@
|
||||||
PGBACKREST_REPO1_PATH = cfg.backup.storage.b2.path;
|
PGBACKREST_REPO1_PATH = cfg.backup.storage.b2.path;
|
||||||
PGBACKREST_REPO1_S3_BUCKET = cfg.backup.storage.b2.bucket;
|
PGBACKREST_REPO1_S3_BUCKET = cfg.backup.storage.b2.bucket;
|
||||||
PGBACKREST_REPO1_S3_ENDPOINT = cfg.backup.storage.b2.endpoint;
|
PGBACKREST_REPO1_S3_ENDPOINT = cfg.backup.storage.b2.endpoint;
|
||||||
PGBACKREST_REPO1_S3_KEY = cfg.backup.storage.b2.account_id;
|
PGBACKREST_REPO1_S3_KEY = cfg.backup.storage.b2.accountId;
|
||||||
PGBACKREST_REPO1_S3_KEY_SECRET = cfg.backup.storage.b2.account_key;
|
|
||||||
PGBACKREST_REPO1_S3_REGION = cfg.backup.storage.b2.region;
|
PGBACKREST_REPO1_S3_REGION = cfg.backup.storage.b2.region;
|
||||||
PGBACKREST_REPO1_TYPE = "s3";
|
PGBACKREST_REPO1_TYPE = "s3";
|
||||||
};
|
};
|
||||||
}.${cfg.backup.storage.type}
|
}.${cfg.backup.storage.type}
|
||||||
);
|
);
|
||||||
pgbackrest = lib.mkIf (cfg.backup.enable) (
|
|
||||||
|
pgbackrestEnvironmentFiles = {
|
||||||
|
PGBACKREST_REPO1_CIPHER_PASS = cfg.backup.cipher.passwordFile;
|
||||||
|
} // {
|
||||||
|
"azure" = {
|
||||||
|
PGBACKREST_REPO1_AZURE_KEY = cfg.backup.storage.azure.accountKeyFile;
|
||||||
|
};
|
||||||
|
"b2" = {
|
||||||
|
PGBACKREST_REPO1_S3_KEY_SECRET = cfg.backup.storage.b2.accountKeyFile;
|
||||||
|
};
|
||||||
|
}.${cfg.backup.storage.type};
|
||||||
|
|
||||||
|
pgbackrest =
|
||||||
|
if (cfg.backup.enable)
|
||||||
|
then
|
||||||
|
(
|
||||||
let
|
let
|
||||||
environment = lib.concatStringsSep "\n" (
|
environment = lib.concatStringsSep "\n" (
|
||||||
lib.mapAttrsToList
|
lib.mapAttrsToList
|
||||||
|
@ -395,14 +455,46 @@
|
||||||
)
|
)
|
||||||
pgbackrestEnvironment
|
pgbackrestEnvironment
|
||||||
);
|
);
|
||||||
|
environmentFiles = lib.concatStringsSep "\n" (
|
||||||
|
lib.mapAttrsToList
|
||||||
|
(
|
||||||
|
n: v:
|
||||||
|
''export ${n}=''$(<${v})''
|
||||||
|
)
|
||||||
|
pgbackrestEnvironmentFiles
|
||||||
|
);
|
||||||
in
|
in
|
||||||
pkgs.writeShellScriptBin "pgbackrest" ''
|
pkgs.writeShellScriptBin "pgbackrest" ''
|
||||||
${environment}
|
${environment}
|
||||||
|
${environmentFiles}
|
||||||
exec ${pkgs.pgbackrest}/bin/pgbackrest "''$@"
|
exec ${pkgs.pgbackrest}/bin/pgbackrest "''$@"
|
||||||
''
|
''
|
||||||
);
|
)
|
||||||
|
else
|
||||||
|
{ };
|
||||||
|
# pgbackrestnu = lib.mkIf (cfg.backup.enable) (
|
||||||
|
# let
|
||||||
|
# environment = writeText "pgbackrest-environment.json" (builtins.toJSON pgbackrestEnvironment);
|
||||||
|
# in
|
||||||
|
# pkgs.writeScriptBin "pgbackrest" ''
|
||||||
|
# #!${pkgs.nushell}/bin/nu
|
||||||
|
|
||||||
|
# def main [...args: string] {
|
||||||
|
# load-env (open ${data})
|
||||||
|
|
||||||
|
# exec ${pkgs.pgbackrest}/bin/pgbackrest $args
|
||||||
|
# }
|
||||||
|
# ''
|
||||||
|
# );
|
||||||
in
|
in
|
||||||
lib.mkIf cfg.enable {
|
lib.mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
# {
|
||||||
|
# assertion = !(cfg.backup.storage.b2.accountKey != null && cfg.backup.storage.b2.accountKeyFile != null);
|
||||||
|
# message = "cannot set both accountKey and accountKeyFile on B2 storage";
|
||||||
|
# }
|
||||||
|
];
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
postgresql
|
postgresql
|
||||||
pgbackrest
|
pgbackrest
|
||||||
|
@ -447,7 +539,7 @@
|
||||||
default root postgres
|
default root postgres
|
||||||
default postgres postgres
|
default postgres postgres
|
||||||
'';
|
'';
|
||||||
archiveCommand = "${pkgs.pgbackrest}/bin/pgbackrest archive-push %p";
|
archiveCommand = "${pgbackrest}/bin/pgbackrest archive-push %p";
|
||||||
settings = {
|
settings = {
|
||||||
bgwriter_flush_after = "512kB";
|
bgwriter_flush_after = "512kB";
|
||||||
checkpoint_flush_after = "256kB";
|
checkpoint_flush_after = "256kB";
|
||||||
|
@ -506,16 +598,28 @@
|
||||||
if (cfg.backup.enable)
|
if (cfg.backup.enable)
|
||||||
then
|
then
|
||||||
''
|
''
|
||||||
init=''$(${pkgs.pgbackrest}/bin/pgbackrest info --output=json | ${pkgs.jq}/bin/jq '.[0].status.code == 0')
|
init=''$(${pgbackrest}/bin/pgbackrest info --output=json | ${pkgs.jq}/bin/jq '.[0].status.code == 0')
|
||||||
if [ "$init" != "true" ]
|
if [ "$init" != "true" ]
|
||||||
then
|
then
|
||||||
${postgresql}/bin/pg_ctl -o "-c ssl=off -c listen_addresses=''' -p 55432" -w start
|
${postgresql}/bin/pg_ctl -o "-c ssl=off -c listen_addresses=''' -p 55432" -w start
|
||||||
${pkgs.pgbackrest}/bin/pgbackrest --pg1-port=55432 stanza-create
|
${pgbackrest}/bin/pgbackrest --pg1-port=55432 stanza-create
|
||||||
${postgresql}/bin/pg_ctl -m fast -w stop
|
${postgresql}/bin/pg_ctl -m fast -w stop
|
||||||
fi
|
fi
|
||||||
''
|
''
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
|
pgpass =
|
||||||
|
if (cfg.replication.enable && cfg.replication.role == "replica")
|
||||||
|
then
|
||||||
|
lib.concatStringsSep ":" [
|
||||||
|
cfg.replication.primary.hostname
|
||||||
|
(builtins.toString cfg.replication.primary.port)
|
||||||
|
"replication"
|
||||||
|
cfg.replication.username
|
||||||
|
''''$(<${cfg.replication.passwordFile}''
|
||||||
|
]
|
||||||
|
else
|
||||||
|
"";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
description = "PostgreSQL Server";
|
description = "PostgreSQL Server";
|
||||||
|
@ -524,11 +628,6 @@
|
||||||
environment = {
|
environment = {
|
||||||
PGDATA = dataDir;
|
PGDATA = dataDir;
|
||||||
} // (
|
} // (
|
||||||
if (cfg.backup.enable && (!cfg.replication.enable || cfg.replication.role == "primary"))
|
|
||||||
then
|
|
||||||
pgbackrestEnvironment
|
|
||||||
else { }
|
|
||||||
) // (
|
|
||||||
if (cfg.replication.enable && cfg.replication.role == "replica")
|
if (cfg.replication.enable && cfg.replication.role == "replica")
|
||||||
then {
|
then {
|
||||||
PGPASSFILE = "${rootDir}/.pgpass";
|
PGPASSFILE = "${rootDir}/.pgpass";
|
||||||
|
@ -563,8 +662,7 @@
|
||||||
''
|
''
|
||||||
else
|
else
|
||||||
''
|
''
|
||||||
read -r password < ${cfg.replication.passwordFile}
|
(umask 077; echo "${pgpass}" > ${rootDir}/.pgpass)
|
||||||
(umask 077; echo "${cfg.replication.primary.hostname}:${builtins.toString cfg.replication.primary.port}:replication:${cfg.replication.username}:''${password}" > ${rootDir}/.pgpass)
|
|
||||||
chmod 0600 ${rootDir}/.pgpass
|
chmod 0600 ${rootDir}/.pgpass
|
||||||
|
|
||||||
if [ ! -s "${dataDir}/PG_VERSION" ]
|
if [ ! -s "${dataDir}/PG_VERSION" ]
|
||||||
|
@ -720,7 +818,7 @@
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
|
|
||||||
${pkgs.pgbackrest}/bin/pgbackrest --type=full --start-fast --stop-auto --delta backup
|
${pgbackrest}/bin/pgbackrest --type=full --start-fast --stop-auto --delta backup
|
||||||
'';
|
'';
|
||||||
environment = pgbackrestEnvironment;
|
environment = pgbackrestEnvironment;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -749,7 +847,7 @@
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
|
|
||||||
${pkgs.pgbackrest}/bin/pgbackrest --type=diff --start-fast --stop-auto --delta backup
|
${pgbackrest}/bin/pgbackrest --type=diff --start-fast --stop-auto --delta backup
|
||||||
'';
|
'';
|
||||||
environment = pgbackrestEnvironment;
|
environment = pgbackrestEnvironment;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -778,7 +876,7 @@
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
|
|
||||||
${pkgs.pgbackrest}/bin/pgbackrest --type=incr --start-fast --stop-auto --delta backup
|
${pgbackrest}/bin/pgbackrest --type=incr --start-fast --stop-auto --delta backup
|
||||||
'';
|
'';
|
||||||
environment = pgbackrestEnvironment;
|
environment = pgbackrestEnvironment;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|
Loading…
Reference in a new issue