1 { lib, pkgs, config, ... }:
3 cfg = config.myServices.databases.postgresql;
5 options.myServices.databases = {
7 enable = lib.mkOption {
10 description = "Whether to enable postgresql database";
11 type = lib.types.bool;
13 package = lib.mkOption {
14 type = lib.types.package;
15 default = pkgs.postgresql;
17 Postgresql package to use.
20 ldapConfig = lib.mkOption {
21 description = "LDAP configuration to allow PAM identification via LDAP";
22 type = lib.types.submodule {
24 host = lib.mkOption { type = lib.types.str; };
25 base = lib.mkOption { type = lib.types.str; };
26 dn = lib.mkOption { type = lib.types.str; };
27 password = lib.mkOption { type = lib.types.str; };
28 filter = lib.mkOption { type = lib.types.str; };
32 replicationLdapConfig = lib.mkOption {
33 description = "LDAP configuration to allow replication";
34 type = lib.types.submodule {
36 host = lib.mkOption { type = lib.types.str; };
37 base = lib.mkOption { type = lib.types.str; };
38 dn = lib.mkOption { type = lib.types.str; };
39 password = lib.mkOption { type = lib.types.str; };
43 authorizedHosts = lib.mkOption {
45 description = "Hosts to allow connections from";
46 type = lib.types.attrsOf (lib.types.listOf (lib.types.submodule {
48 method = lib.mkOption {
52 username = lib.mkOption {
56 database = lib.mkOption {
62 type = lib.types.listOf lib.types.str;
66 type = lib.types.listOf lib.types.str;
71 replicationHosts = lib.mkOption {
73 description = "Hosts to allow replication from";
74 type = lib.types.attrsOf (lib.types.submodule {
77 type = lib.types.listOf lib.types.str;
80 type = lib.types.listOf lib.types.str;
86 socketsDir = lib.mkOption {
87 type = lib.types.path;
88 default = "/run/postgresql";
90 The directory where Postgresql puts sockets.
94 systemdRuntimeDirectory = lib.mkOption {
96 # Use ReadWritePaths= instead if socketsDir is outside of /run
97 default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
98 lib.strings.removePrefix "/run/" cfg.socketsDir;
100 Adjusted Postgresql sockets directory for systemd
107 config = lib.mkIf cfg.enable {
108 networking.firewall.allowedTCPPorts = [ 5432 ];
110 security.acme.certs."postgresql" = config.myServices.databasesCerts // {
113 plugins = [ "fullchain.pem" "key.pem" "account_key.json" ];
114 domain = "db-1.immae.eu";
116 systemctl reload postgresql.service
120 systemd.services.postgresql.serviceConfig = {
121 SupplementaryGroups = "keys";
122 RuntimeDirectory = cfg.systemdRuntimeDirectory;
124 services.postgresql = {
126 package = cfg.package;
129 max_connections = 100
131 shared_buffers = 512MB
135 log_timezone = 'Europe/Paris'
136 datestyle = 'iso, mdy'
137 timezone = 'Europe/Paris'
138 lc_messages = 'en_US.UTF-8'
139 lc_monetary = 'en_US.UTF-8'
140 lc_numeric = 'en_US.UTF-8'
141 lc_time = 'en_US.UTF-8'
142 default_text_search_config = 'pg_catalog.english'
144 ssl_cert_file = '${config.security.acme.directory}/postgresql/fullchain.pem'
145 ssl_key_file = '${config.security.acme.directory}/postgresql/key.pem'
148 hosts = builtins.concatStringsSep "\n" (
149 lib.lists.flatten (lib.mapAttrsToList (k: vs: map (v:
150 map (ip6: "hostssl ${v.database} ${v.username} ${ip6}/128 ${v.method}") v.ip6
151 ++ map (ip4: "hostssl ${v.database} ${v.username} ${ip4}/32 ${v.method}") v.ip4
152 ) vs) cfg.authorizedHosts
154 replication = builtins.concatStringsSep "\n" (
155 lib.lists.flatten (lib.mapAttrsToList (k: v:
156 map (ip6: "hostssl replication ${k} ${ip6}/128 pam pamservice=postgresql_replication") v.ip6
157 ++ map (ip4: "hostssl replication ${k} ${ip4}/32 pam pamservice=postgresql_replication") v.ip4
158 ) cfg.replicationHosts
161 local all postgres ident
164 hostssl all all all pam
171 dest = "postgresql/pam";
172 permissions = "0400";
175 text = with cfg.ldapConfig; ''
185 dest = "postgresql/pam_replication";
186 permissions = "0400";
189 text = with cfg.replicationLdapConfig; ''
194 pam_login_attribute cn
200 security.pam.services = let
201 pam_ldap = "${pkgs.pam_ldap}/lib/security/pam_ldap.so";
206 auth required ${pam_ldap} config=${config.secrets.location}/postgresql/pam
207 account required ${pam_ldap} config=${config.secrets.location}/postgresql/pam
211 name = "postgresql_replication";
213 auth required ${pam_ldap} config=${config.secrets.location}/postgresql/pam_replication
214 account required ${pam_ldap} config=${config.secrets.location}/postgresql/pam_replication