210 lines
5.5 KiB
Nix
210 lines
5.5 KiB
Nix
{ config, lib, pkgs, environment, ... }:
|
|
|
|
with lib;
|
|
let
|
|
|
|
cfg = config.fudo.postgresql;
|
|
|
|
userOpts = { username, ... }: {
|
|
options = {
|
|
password = mkOption {
|
|
type = with types; nullOr str;
|
|
description = "The user's (plaintext) password.";
|
|
default = null;
|
|
};
|
|
|
|
databases = mkOption {
|
|
type = with types; loaOf str;
|
|
description = "Map of databases to which this user has access, to the required perms.";
|
|
default = {};
|
|
example = {
|
|
my_database = "ALL PRIVILEGES";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
databaseOpts = { dbname, ... }: {
|
|
options = {
|
|
users = mkOption {
|
|
type = with types; listOf str;
|
|
description = "A list of users who should have full access to this database.";
|
|
default = [];
|
|
};
|
|
};
|
|
};
|
|
|
|
userDatabaseAccess = user: databases:
|
|
mapAttrs' (database: perms:
|
|
nameValuePair "DATABASE ${database}" perms)
|
|
databases;
|
|
|
|
stringJoin = joiner: els:
|
|
if (length els) == 0 then
|
|
""
|
|
else
|
|
foldr(lel: rel: "${lel}${joiner}${rel}") (last els) (init els);
|
|
|
|
makeEntry = nw:
|
|
"host all all ${nw} gss include_realm=0 krb_realm=FUDO.ORG";
|
|
|
|
makeNetworksEntry = networks:
|
|
stringJoin "\n" (map makeEntry networks);
|
|
|
|
setPasswordSql = username: attrs:
|
|
"ALTER USER ${username} ENCRYPTED PASSWORD '${attrs.password}';";
|
|
|
|
setPasswordsSql = users:
|
|
(stringJoin "\n"
|
|
(mapAttrsToList (username: attrs: setPasswordSql username attrs)
|
|
(filterAttrs (user: attrs: attrs.password != null) users))) + "\n";
|
|
|
|
makeLocalUserPasswordEntries = users:
|
|
stringJoin "\n"
|
|
(mapAttrsToList
|
|
(username: attrs:
|
|
stringJoin "\n"
|
|
(map (db: ''
|
|
host ${username} ${db} 127.0.0.1/16 md5
|
|
host ${username} ${db} ::1/128 md5
|
|
'') (attrNames attrs.databases)))
|
|
users);
|
|
|
|
|
|
in {
|
|
|
|
options.fudo.postgresql = {
|
|
enable = mkEnableOption "Fudo PostgreSQL Server";
|
|
|
|
ssl-private-key = mkOption {
|
|
type = types.str;
|
|
description = "Location of the server SSL private key.";
|
|
};
|
|
|
|
ssl-certificate = mkOption {
|
|
type = types.str;
|
|
description = "Location of the server SSL certificate.";
|
|
};
|
|
|
|
keytab = mkOption {
|
|
type = types.str;
|
|
description = "Location of the server Kerberos keytab.";
|
|
};
|
|
|
|
local-networks = mkOption {
|
|
type = with types; listOf str;
|
|
description = "A list of networks from which to accept connections.";
|
|
example = [
|
|
"10.0.0.1/16"
|
|
];
|
|
default = [];
|
|
};
|
|
|
|
users = mkOption {
|
|
type = with types; loaOf (submodule userOpts);
|
|
description = "A map of users to user attributes.";
|
|
example = {
|
|
sampleUser = {
|
|
password = "some-password";
|
|
databases = [ "sample_user_db" ];
|
|
};
|
|
};
|
|
default = {};
|
|
};
|
|
|
|
databases = mkOption {
|
|
type = with types; loaOf (submodule databaseOpts);
|
|
description = "A map of databases to database options.";
|
|
default = {};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
environment = {
|
|
systemPackages = with pkgs; [
|
|
postgresql_11_gssapi
|
|
];
|
|
|
|
etc = {
|
|
"postgresql/private/privkey.pem" = {
|
|
mode = "0400";
|
|
user = "postgres";
|
|
group = "postgres";
|
|
source = cfg.ssl-private-key;
|
|
};
|
|
|
|
"postgresql/cert.pem" = {
|
|
mode = "0444";
|
|
user = "postgres";
|
|
group = "postgres";
|
|
source = cfg.ssl-certificate;
|
|
};
|
|
|
|
"postgresql/private/postgres.keytab" = {
|
|
mode = "0400";
|
|
user = "postgres";
|
|
group = "postgres";
|
|
source = cfg.keytab;
|
|
};
|
|
|
|
"postgresql/private/user-script.sql" = {
|
|
mode = "0400";
|
|
user = "postgres";
|
|
group = "postgres";
|
|
text = setPasswordsSql cfg.users;
|
|
};
|
|
};
|
|
};
|
|
|
|
services.postgresql = {
|
|
enable = true;
|
|
package = pkgs.postgresql_11_gssapi;
|
|
enableTCPIP = true;
|
|
ensureDatabases = mapAttrsToList (name: value: name) cfg.databases;
|
|
ensureUsers = mapAttrsToList
|
|
(username: attrs:
|
|
{
|
|
name = username;
|
|
ensurePermissions =
|
|
#{ "DATABASE ${username}" = "ALL PRIVILEGES"; };
|
|
(userDatabaseAccess username attrs.databases);
|
|
})
|
|
cfg.users;
|
|
|
|
extraConfig =
|
|
''
|
|
krb_server_keyfile = '/etc/postgresql/private/postgres.keytab'
|
|
|
|
ssl = true
|
|
ssl_cert_file = '/etc/postgresql/cert.pem'
|
|
ssl_key_file = '/etc/postgresql/private/privkey.pem'
|
|
|
|
unix_socket_directories = '/var/run/postgresql'
|
|
'';
|
|
|
|
authentication =
|
|
''
|
|
local all all ident
|
|
|
|
${makeLocalUserPasswordEntries cfg.users}
|
|
|
|
# host-local
|
|
host all all 127.0.0.1/32 gss include_realm=0 krb_realm=FUDO.ORG
|
|
host all all ::1/128 gss include_realm=0 krb_realm=FUDO.ORG
|
|
|
|
# local networks
|
|
${makeNetworksEntry cfg.local-networks}
|
|
'';
|
|
|
|
# initialScript = pkgs.writeText "database-init.sql" ''
|
|
# ${setPasswordsSql cfg.users}
|
|
# '';
|
|
};
|
|
|
|
systemd.services.postgresql.postStart = ''
|
|
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${pkgs.postgresql}/bin/psql --port ${toString config.services.postgresql.port} -f /etc/postgresql/private/user-script.sql -d postgres
|
|
'';
|
|
};
|
|
}
|