mirror of
https://github.com/vale981/phoebe
synced 2025-03-04 17:31:41 -05:00
Breaking Change: Completely Change PostgreSQL Account Management
This is a breaking change that will require you to change your Phoebe settings for PostgreSQL. * New database configuration options * Accounts no longer automatically create databases * Databases have `owners' that tie them back to an account * Databases have `users' that grant accounts full access * Databases have `readers' that grant read-only access to accounts * Accounts can use `ident' authentication for local connections if you enable the `allowIdent' option. * Existing accounts that are not configured via Phoebe will be locked so they cannot be used. That way if you delete a user from Phoebe the account will continue to exist, but won't have access to anything.
This commit is contained in:
parent
3a322a114a
commit
b2fd566c36
8 changed files with 380 additions and 72 deletions
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
pkgs.stdenvNoCC.mkDerivation rec {
|
pkgs.stdenvNoCC.mkDerivation rec {
|
||||||
name = "phoebe-${version}";
|
name = "phoebe-${version}";
|
||||||
version = "0.1";
|
version = "0.2";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
phases =
|
phases =
|
||||||
|
|
79
modules/services/databases/postgresql/create-db.sh
Executable file
79
modules/services/databases/postgresql/create-db.sh
Executable file
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Create a database if it's missing.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
option_database=""
|
||||||
|
option_owner="@superuser@"
|
||||||
|
option_extensions=""
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
usage () {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: create-db.sh [options]
|
||||||
|
|
||||||
|
-d NAME Database name to create
|
||||||
|
-e LIST Space-separated list of extensions to enable
|
||||||
|
-h This message
|
||||||
|
-o USER The owner of the new database.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
while getopts "d:e:ho:" o; do
|
||||||
|
case "${o}" in
|
||||||
|
d) option_database=$OPTARG
|
||||||
|
;;
|
||||||
|
|
||||||
|
e) option_extensions=$OPTARG
|
||||||
|
;;
|
||||||
|
|
||||||
|
h) usage
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
|
||||||
|
o) option_owner=$OPTARG
|
||||||
|
;;
|
||||||
|
|
||||||
|
*) exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
_psql() {
|
||||||
|
@sudo@ -u @superuser@ -H psql "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
create_database() {
|
||||||
|
has_db=$(_psql -tAl | cut -d'|' -f1 | grep -cF "$option_database" || :)
|
||||||
|
|
||||||
|
if [ "$has_db" -eq 0 ]; then
|
||||||
|
@sudo@ -u @superuser@ -H \
|
||||||
|
createdb --owner "$option_owner" "$option_database"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
enable_extensions() {
|
||||||
|
if [ -n "$option_extensions" ]; then
|
||||||
|
for ext in $option_extensions; do
|
||||||
|
_psql "$option_database" -c "CREATE EXTENSION IF NOT EXISTS $ext"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
if [ -z "$option_database" ]; then
|
||||||
|
>&2 echo "ERROR: must give -d"
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
create_database
|
||||||
|
enable_extensions
|
108
modules/services/databases/postgresql/create-grant.sh
Executable file
108
modules/services/databases/postgresql/create-grant.sh
Executable file
|
@ -0,0 +1,108 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Grant a user specific rights to a database.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
option_user=""
|
||||||
|
option_database=""
|
||||||
|
option_access="r"
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
usage () {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: create-grant.sh [options]
|
||||||
|
|
||||||
|
-a LEVEL Access level (r, w, or rw)
|
||||||
|
-d NAME Database name to grant access to
|
||||||
|
-h This message
|
||||||
|
-u USER The user to grant access to
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
verify_access_level() {
|
||||||
|
local level=$1
|
||||||
|
|
||||||
|
case $level in
|
||||||
|
r|w|rw)
|
||||||
|
echo "$level"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
>&2 echo "ERROR: invalid access level: $level"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
while getopts "a:d:hu:" o; do
|
||||||
|
case "${o}" in
|
||||||
|
a) option_access=$(verify_access_level "$OPTARG")
|
||||||
|
;;
|
||||||
|
|
||||||
|
d) option_database=$OPTARG
|
||||||
|
;;
|
||||||
|
|
||||||
|
h) usage
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
|
||||||
|
u) option_user=$OPTARG
|
||||||
|
;;
|
||||||
|
|
||||||
|
*) exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
_psql() {
|
||||||
|
@sudo@ -u @superuser@ -H psql "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
echo_grants() {
|
||||||
|
local r_list="SELECT"
|
||||||
|
local w_list="INSERT,UPDATE,DELETE,TRUNCATE,REFERENCES,TRIGGER"
|
||||||
|
|
||||||
|
# Needed to resolve ambiguous role memberships.
|
||||||
|
echo "SET ROLE @superuser@;"
|
||||||
|
|
||||||
|
# Start by removing all access then granting the ability to connect:
|
||||||
|
echo "REVOKE ALL PRIVILEGES ON DATABASE $option_database FROM $option_user;"
|
||||||
|
echo "GRANT CONNECT ON DATABASE $option_database TO $option_user;"
|
||||||
|
|
||||||
|
# Basic options:
|
||||||
|
echo "GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO $option_user;"
|
||||||
|
echo "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO $option_user;"
|
||||||
|
|
||||||
|
if [ "$option_access" = "r" ] || [ "$option_access" = "rw" ]; then
|
||||||
|
echo "GRANT USAGE ON SCHEMA public TO $option_user;"
|
||||||
|
|
||||||
|
echo "GRANT $r_list ON ALL TABLES IN SCHEMA public TO $option_user;"
|
||||||
|
echo "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT $r_list ON TABLES TO $option_user;"
|
||||||
|
|
||||||
|
echo "GRANT USAGE,SELECT ON ALL SEQUENCES IN SCHEMA public TO $option_user;"
|
||||||
|
echo "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE,SELECT ON SEQUENCES TO $option_user;"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$option_access" = "w" ] || [ "$option_access" = "rw" ]; then
|
||||||
|
echo "GRANT $w_list ON ALL TABLES IN SCHEMA public TO $option_user;"
|
||||||
|
echo "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT $w_list ON TABLES TO $option_user;"
|
||||||
|
|
||||||
|
echo "GRANT UPDATE ON ALL SEQUENCES IN SCHEMA public TO $option_user;"
|
||||||
|
echo "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT UPDATE ON SEQUENCES TO $option_user;"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Let's do it!
|
||||||
|
sql_file=$(mktemp)
|
||||||
|
echo_grants > "$sql_file"
|
||||||
|
chown @superuser@ "$sql_file"
|
||||||
|
_psql --dbname="$option_database" --file="$sql_file" --single-transaction
|
||||||
|
rm "$sql_file"
|
|
@ -6,8 +6,6 @@ set -e
|
||||||
################################################################################
|
################################################################################
|
||||||
option_username=""
|
option_username=""
|
||||||
option_password_file=""
|
option_password_file=""
|
||||||
option_database=""
|
|
||||||
option_extensions=""
|
|
||||||
option_sqlfile="@out@/sql/create-user.sql"
|
option_sqlfile="@out@/sql/create-user.sql"
|
||||||
option_superuser=0
|
option_superuser=0
|
||||||
|
|
||||||
|
@ -16,8 +14,6 @@ usage () {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Usage: create-user.sh [options]
|
Usage: create-user.sh [options]
|
||||||
|
|
||||||
-d NAME Database name to create for USER
|
|
||||||
-e LIST Space-separated list of extensions to enable
|
|
||||||
-h This message
|
-h This message
|
||||||
-p FILE File containing USER's password
|
-p FILE File containing USER's password
|
||||||
-s FILE The SQL template file (pg-create-user.sql)
|
-s FILE The SQL template file (pg-create-user.sql)
|
||||||
|
@ -27,14 +23,8 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
while getopts "d:e:hp:s:Su:" o; do
|
while getopts "hp:s:Su:" o; do
|
||||||
case "${o}" in
|
case "${o}" in
|
||||||
d) option_database=$OPTARG
|
|
||||||
;;
|
|
||||||
|
|
||||||
e) option_extensions=$OPTARG
|
|
||||||
;;
|
|
||||||
|
|
||||||
h) usage
|
h) usage
|
||||||
exit
|
exit
|
||||||
;;
|
;;
|
||||||
|
@ -109,26 +99,5 @@ create_user() {
|
||||||
_psql -d postgres -c "ALTER ROLE $option_username $superuser"
|
_psql -d postgres -c "ALTER ROLE $option_username $superuser"
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
|
||||||
create_database() {
|
|
||||||
has_db=$(_psql -tAl | cut -d'|' -f1 | grep -cF "$option_database" || :)
|
|
||||||
|
|
||||||
if [ "$has_db" -eq 0 ]; then
|
|
||||||
@sudo@ -u @superuser@ -H \
|
|
||||||
createdb --owner "$option_username" "$option_database"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
enable_extensions() {
|
|
||||||
if [ -n "$option_extensions" ]; then
|
|
||||||
for ext in $option_extensions; do
|
|
||||||
_psql "$option_database" -c "CREATE EXTENSION IF NOT EXISTS $ext"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
create_user
|
create_user
|
||||||
create_database
|
|
||||||
enable_extensions
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ BEGIN
|
||||||
FROM pg_catalog.pg_roles
|
FROM pg_catalog.pg_roles
|
||||||
WHERE rolname = '@@USERNAME@@') THEN
|
WHERE rolname = '@@USERNAME@@') THEN
|
||||||
|
|
||||||
CREATE ROLE @@USERNAME@@ LOGIN ENCRYPTED PASSWORD '@@PASSWORD@@';
|
CREATE ROLE @@USERNAME@@ NOINHERIT LOGIN ENCRYPTED PASSWORD '@@PASSWORD@@';
|
||||||
END IF;
|
END IF;
|
||||||
END
|
END
|
||||||
$body$;
|
$body$;
|
||||||
|
|
|
@ -8,9 +8,55 @@ let
|
||||||
cfg = config.phoebe.services.postgresql;
|
cfg = config.phoebe.services.postgresql;
|
||||||
plib = config.phoebe.lib;
|
plib = config.phoebe.lib;
|
||||||
superuser = config.services.postgresql.superUser;
|
superuser = config.services.postgresql.superUser;
|
||||||
create-user = import ./create-user.nix { inherit config lib pkgs; };
|
scripts = import ./scripts.nix { inherit config lib pkgs; };
|
||||||
afterservices = concatMap (a: plib.keyService a.passwordFile) (attrValues cfg.accounts);
|
afterservices = concatMap (a: plib.keyService a.passwordFile) (attrValues cfg.accounts);
|
||||||
|
|
||||||
|
# Per-database options:
|
||||||
|
database = { name, ...}: {
|
||||||
|
|
||||||
|
#### Interface:
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "sales";
|
||||||
|
description = "The name of the database.";
|
||||||
|
};
|
||||||
|
|
||||||
|
owner = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = superuser;
|
||||||
|
example = "jdoe";
|
||||||
|
description = "Name of the account that owns the database.";
|
||||||
|
};
|
||||||
|
|
||||||
|
users = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "alice" ];
|
||||||
|
description = "List of user names who have full access to the database.";
|
||||||
|
};
|
||||||
|
|
||||||
|
readers = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "bob" ];
|
||||||
|
description = "List of user names who have read-only access to the database";
|
||||||
|
};
|
||||||
|
|
||||||
|
extensions = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
example = [ "pg_trgm" ];
|
||||||
|
description = "A list of extension modules to enable for the database.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#### Implementation:
|
||||||
|
config = {
|
||||||
|
name = mkDefault name;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
# Per-account options:
|
# Per-account options:
|
||||||
account = { name, ... }: {
|
account = { name, ... }: {
|
||||||
|
|
||||||
|
@ -38,23 +84,6 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
database = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = null;
|
|
||||||
example = "jdoe";
|
|
||||||
description = ''
|
|
||||||
The name of the database this user can access. Defaults to
|
|
||||||
the account name.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extensions = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
example = [ "pg_trgm" ];
|
|
||||||
description = "A list of extension modules to enable for the database.";
|
|
||||||
};
|
|
||||||
|
|
||||||
superuser = mkOption {
|
superuser = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
@ -70,6 +99,16 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
allowIdent = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
example = true;
|
||||||
|
description = ''
|
||||||
|
Whether or not this account can use ident authentication
|
||||||
|
when connecting locally.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
netmask = mkOption {
|
netmask = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -85,31 +124,100 @@ let
|
||||||
#### Implementation:
|
#### Implementation:
|
||||||
config = {
|
config = {
|
||||||
user = mkDefault name;
|
user = mkDefault name;
|
||||||
database = mkDefault name;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create HBA authentication entries:
|
# Create HBA authentication entries:
|
||||||
accountToHBA = account:
|
accountToHBA = account:
|
||||||
''
|
let local = if account.allowIdent then "ident" else "md5";
|
||||||
local ${account.database} ${account.user} md5
|
template = database: (''
|
||||||
host ${account.database} ${account.user} 127.0.0.1/32 md5
|
local ${database} ${account.user} ${local}
|
||||||
host ${account.database} ${account.user} ::1/28 md5
|
host ${database} ${account.user} 127.0.0.1/32 md5
|
||||||
|
host ${database} ${account.user} ::1/28 md5
|
||||||
'' + optionalString (account.netmask != null) ''
|
'' + optionalString (account.netmask != null) ''
|
||||||
host ${account.database} ${account.user} ${account.netmask} md5
|
host ${database} ${account.user} ${account.netmask} md5
|
||||||
|
'');
|
||||||
|
databases = map (d: d.name)
|
||||||
|
(filter (d: d.owner == account.user ||
|
||||||
|
elem account.user d.users ||
|
||||||
|
elem account.user d.readers)
|
||||||
|
(attrValues cfg.databases));
|
||||||
|
in if account.superuser
|
||||||
|
then template "all"
|
||||||
|
else concatMapStringsSep "\n" template databases;
|
||||||
|
|
||||||
|
# Commands to run to create accounts:
|
||||||
|
createUser = account:
|
||||||
|
let options = [
|
||||||
|
''-u "${account.user}"''
|
||||||
|
''-p "${account.passwordFile}"''
|
||||||
|
] ++ optional account.superuser "-S";
|
||||||
|
in ''
|
||||||
|
${scripts}/bin/create-user.sh ${concatStringsSep " " options}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Commands to run to create accounts/databases:
|
# Commands to run to create databases:
|
||||||
createScript = account:
|
createDB = database:
|
||||||
''
|
''
|
||||||
${create-user}/bin/create-user.sh \
|
${scripts}/bin/create-db.sh \
|
||||||
-u "${account.user}" \
|
-d "${database.name}" \
|
||||||
-d "${account.database}" \
|
-o "${database.owner}" \
|
||||||
-p "${account.passwordFile}" \
|
-e "${concatStringsSep " " database.extensions}"
|
||||||
-e "${concatStringsSep " " account.extensions}" \
|
|
||||||
-S "${toString account.superuser}"
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# Commands to run to create full grants:
|
||||||
|
createGrant = database: account:
|
||||||
|
''
|
||||||
|
${scripts}/bin/create-grant.sh \
|
||||||
|
-a rw \
|
||||||
|
-u "${account.user}" \
|
||||||
|
-d "${database.name}"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Commands to run to create read-only grants:
|
||||||
|
createReadGrant = database: account:
|
||||||
|
''
|
||||||
|
${scripts}/bin/create-grant.sh \
|
||||||
|
-a r \
|
||||||
|
-u "${account.user}" \
|
||||||
|
-d "${database.name}"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Generate a SQL statement that allows a user to login:
|
||||||
|
allowLogin = accounts: concatMapStringsSep "\n" (account: ''
|
||||||
|
echo "ALTER ROLE ${account.user} LOGIN;"
|
||||||
|
'') accounts;
|
||||||
|
|
||||||
|
# Lock out accounts that are not configured:
|
||||||
|
lockAccounts = accounts: ''
|
||||||
|
sql_file=$(mktemp)
|
||||||
|
|
||||||
|
# Lock all accounts:
|
||||||
|
${scripts}/bin/nologin.sh > "$sql_file"
|
||||||
|
|
||||||
|
# Unlock configured accounts:
|
||||||
|
(
|
||||||
|
${allowLogin accounts}
|
||||||
|
) >> "$sql_file"
|
||||||
|
|
||||||
|
chown ${superuser} "$sql_file"
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo -u ${superuser} -H \
|
||||||
|
psql --dbname="postgres" --file="$sql_file" --single-transaction
|
||||||
|
|
||||||
|
rm "$sql_file"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Master grant creation function:
|
||||||
|
createGrants = database:
|
||||||
|
let find = names: map (name: cfg.accounts."${name}")
|
||||||
|
(filter (name: cfg.accounts ? "${name}")
|
||||||
|
names);
|
||||||
|
ro = find database.readers;
|
||||||
|
rw = find (database.users ++ [database.owner]);
|
||||||
|
owner = find [database.owner];
|
||||||
|
in (concatMapStringsSep "\n" (createReadGrant database) ro) +
|
||||||
|
(concatMapStringsSep "\n" (createGrant database) rw);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
#### Interface
|
#### Interface
|
||||||
|
@ -119,7 +227,13 @@ in
|
||||||
accounts = mkOption {
|
accounts = mkOption {
|
||||||
type = types.attrsOf (types.submodule account);
|
type = types.attrsOf (types.submodule account);
|
||||||
default = { };
|
default = { };
|
||||||
description = "Additional user accounts";
|
description = "Additional user accounts.";
|
||||||
|
};
|
||||||
|
|
||||||
|
databases = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule database);
|
||||||
|
default = { };
|
||||||
|
description = "Additional databases to create.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -142,13 +256,19 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create missing accounts:
|
# Create missing accounts:
|
||||||
systemd.services.pg-accounts = mkIf (length (attrValues cfg.accounts) > 0) {
|
systemd.services.postgres-account-manager = {
|
||||||
description = "PostgreSQL Account Manager";
|
description = "PostgreSQL Account Manager";
|
||||||
path = [ pkgs.gawk config.services.postgresql.package ];
|
path = [ pkgs.gawk config.services.postgresql.package ];
|
||||||
script = (concatMapStringsSep "\n" createScript (attrValues cfg.accounts));
|
|
||||||
wantedBy = [ "postgresql.service" ];
|
wantedBy = [ "postgresql.service" ];
|
||||||
after = [ "postgresql.service" ] ++ afterservices;
|
after = [ "postgresql.service" ] ++ afterservices;
|
||||||
wants = afterservices;
|
wants = afterservices;
|
||||||
|
|
||||||
|
script = ''
|
||||||
|
set -e
|
||||||
|
'' + (concatMapStringsSep "\n" createUser (attrValues cfg.accounts))
|
||||||
|
+ (lockAccounts (attrValues cfg.accounts))
|
||||||
|
+ (concatMapStringsSep "\n" createDB (attrValues cfg.databases))
|
||||||
|
+ (concatMapStringsSep "\n" createGrants (attrValues cfg.databases));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
27
modules/services/databases/postgresql/nologin.sh
Executable file
27
modules/services/databases/postgresql/nologin.sh
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Generate SQL that locks out all users (except the superuser).
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
_psql() {
|
||||||
|
@sudo@ -u @superuser@ -H psql "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
accounts() {
|
||||||
|
echo "SELECT rolname FROM pg_catalog.pg_roles;" | \
|
||||||
|
_psql --tuples-only postgres | \
|
||||||
|
sed 's/^[[:space:]]*//' | \
|
||||||
|
grep --fixed-strings --invert-match --line-regexp '@superuser@' | \
|
||||||
|
grep --extended-regexp --invert-match '^pg_'
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
for name in $(accounts); do
|
||||||
|
if [ -n "$name" ]; then
|
||||||
|
echo "ALTER ROLE $name NOLOGIN;"
|
||||||
|
fi
|
||||||
|
done
|
|
@ -10,9 +10,14 @@ pkgs.stdenvNoCC.mkDerivation {
|
||||||
export superuser=${config.services.postgresql.superUser}
|
export superuser=${config.services.postgresql.superUser}
|
||||||
|
|
||||||
mkdir -p $out/bin $out/sql
|
mkdir -p $out/bin $out/sql
|
||||||
|
|
||||||
cp ${./create-user.sql} $out/sql/create-user.sql
|
cp ${./create-user.sql} $out/sql/create-user.sql
|
||||||
substituteAll ${./create-user.sh} $out/bin/create-user.sh
|
substituteAll ${./create-user.sh} $out/bin/create-user.sh
|
||||||
chmod 555 $out/bin/create-user.sh
|
substituteAll ${./create-db.sh} $out/bin/create-db.sh
|
||||||
|
substituteAll ${./create-grant.sh} $out/bin/create-grant.sh
|
||||||
|
substituteAll ${./nologin.sh} $out/bin/nologin.sh
|
||||||
|
|
||||||
|
chmod 555 $out/bin/*.sh
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
Loading…
Add table
Reference in a new issue