]> git.immae.eu Git - perso/Immae/Config/Nix.git/blame - modules/private/databases/postgresql.nix
Upgrade nixos
[perso/Immae/Config/Nix.git] / modules / private / databases / postgresql.nix
CommitLineData
4aac110f 1{ lib, pkgs, config, ... }:
4ff90563 2let
182ae57f 3 cfg = config.myServices.databases.postgresql;
4ff90563 4in {
182ae57f 5 options.myServices.databases = {
4ff90563
IB
6 postgresql = {
7 enable = lib.mkOption {
8415083e 8 default = false;
4ff90563
IB
9 example = true;
10 description = "Whether to enable postgresql database";
11 type = lib.types.bool;
12 };
4aac110f
IB
13 package = lib.mkOption {
14 type = lib.types.package;
15 default = pkgs.postgresql;
16 description = ''
17 Postgresql package to use.
18 '';
19 };
20 ldapConfig = lib.mkOption {
21 description = "LDAP configuration to allow PAM identification via LDAP";
22 type = lib.types.submodule {
23 options = {
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; };
29 };
30 };
31 };
32 replicationLdapConfig = lib.mkOption {
33 description = "LDAP configuration to allow replication";
34 type = lib.types.submodule {
35 options = {
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; };
40 };
41 };
42 };
43 authorizedHosts = lib.mkOption {
44 default = {};
45 description = "Hosts to allow connections from";
46 type = lib.types.attrsOf (lib.types.listOf (lib.types.submodule {
47 options = {
48 method = lib.mkOption {
49 default = "md5";
50 type = lib.types.str;
51 };
52 username = lib.mkOption {
53 default = "all";
54 type = lib.types.str;
55 };
56 database = lib.mkOption {
57 default = "all";
58 type = lib.types.str;
59 };
60 ip4 = lib.mkOption {
61 default = [];
62 type = lib.types.listOf lib.types.str;
63 };
64 ip6 = lib.mkOption {
65 default = [];
66 type = lib.types.listOf lib.types.str;
67 };
68 };
69 }));
70 };
71 replicationHosts = lib.mkOption {
72 default = {};
73 description = "Hosts to allow replication from";
74 type = lib.types.attrsOf (lib.types.submodule {
75 options = {
76 ip4 = lib.mkOption {
77 type = lib.types.listOf lib.types.str;
78 };
79 ip6 = lib.mkOption {
80 type = lib.types.listOf lib.types.str;
81 };
82 };
83 });
84 };
182ae57f
IB
85 # Output variables
86 socketsDir = lib.mkOption {
87 type = lib.types.path;
88 default = "/run/postgresql";
89 description = ''
90 The directory where Postgresql puts sockets.
91 '';
92 readOnly = true;
93 };
4ff90563
IB
94 };
95 };
96
97 config = lib.mkIf cfg.enable {
4ff90563
IB
98 networking.firewall.allowedTCPPorts = [ 5432 ];
99
5400b9b6 100 security.acme.certs."postgresql" = config.myServices.databasesCerts // {
4ff90563
IB
101 user = "postgres";
102 group = "postgres";
981fa803 103 plugins = [ "fullchain.pem" "key.pem" "account_key.json" "account_reg.json" ];
4ff90563
IB
104 domain = "db-1.immae.eu";
105 postRun = ''
106 systemctl reload postgresql.service
107 '';
108 };
109
182ae57f
IB
110 systemd.services.postgresql.serviceConfig = {
111 SupplementaryGroups = "keys";
182ae57f 112 };
ec9b6564
IB
113 systemd.services.postgresql.postStart = lib.mkAfter ''
114 # This line is already defined in 19.09
115 PSQL="${pkgs.sudo}/bin/sudo -u postgres psql --port=5432"
116
117 ${builtins.concatStringsSep "\n" (lib.mapAttrsToList (role: _: ''
118 $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${role}'" \
119 | grep -q 1 \
120 || $PSQL -tAc 'CREATE USER "${role}" WITH REPLICATION'
121 '') cfg.replicationHosts)}
122
123 ${builtins.concatStringsSep "\n" (lib.mapAttrsToList (role: _:
124 let
125 sname = builtins.replaceStrings ["-"] ["_"] role;
126 in
127 ''
128 $PSQL -tAc "SELECT 1 FROM pg_replication_slots WHERE slot_name='${sname}'" \
129 | grep -q 1 \
130 || $PSQL -tAc "SELECT * FROM pg_create_physical_replication_slot('${sname}')"
131 '') cfg.replicationHosts)}
132 '';
133
4aac110f 134 services.postgresql = {
182ae57f 135 enable = true;
4aac110f 136 package = cfg.package;
4ff90563
IB
137 enableTCPIP = true;
138 extraConfig = ''
139 max_connections = 100
140 wal_level = logical
141 shared_buffers = 512MB
142 work_mem = 10MB
143 max_wal_size = 1GB
144 min_wal_size = 80MB
145 log_timezone = 'Europe/Paris'
146 datestyle = 'iso, mdy'
147 timezone = 'Europe/Paris'
148 lc_messages = 'en_US.UTF-8'
149 lc_monetary = 'en_US.UTF-8'
150 lc_numeric = 'en_US.UTF-8'
151 lc_time = 'en_US.UTF-8'
152 default_text_search_config = 'pg_catalog.english'
0907cf1b
IB
153 # this introduces a small delay before storing on disk, but
154 # makes it order of magnitudes quicker
155 synchronous_commit = off
4ff90563 156 ssl = on
5400b9b6
IB
157 ssl_cert_file = '${config.security.acme.certs.postgresql.directory}/fullchain.pem'
158 ssl_key_file = '${config.security.acme.certs.postgresql.directory}/key.pem'
4ff90563 159 '';
4aac110f
IB
160 authentication = let
161 hosts = builtins.concatStringsSep "\n" (
162 lib.lists.flatten (lib.mapAttrsToList (k: vs: map (v:
163 map (ip6: "hostssl ${v.database} ${v.username} ${ip6}/128 ${v.method}") v.ip6
164 ++ map (ip4: "hostssl ${v.database} ${v.username} ${ip4}/32 ${v.method}") v.ip4
165 ) vs) cfg.authorizedHosts
166 ));
167 replication = builtins.concatStringsSep "\n" (
168 lib.lists.flatten (lib.mapAttrsToList (k: v:
169 map (ip6: "hostssl replication ${k} ${ip6}/128 pam pamservice=postgresql_replication") v.ip6
170 ++ map (ip4: "hostssl replication ${k} ${ip4}/32 pam pamservice=postgresql_replication") v.ip4
171 ) cfg.replicationHosts
172 ));
173 in ''
4ff90563
IB
174 local all postgres ident
175 local all all md5
4aac110f 176 ${hosts}
4ff90563 177 hostssl all all all pam
4aac110f 178 ${replication}
4ff90563
IB
179 '';
180 };
181
1a718805 182 secrets.keys = [
7178c2b1
IB
183 {
184 dest = "postgresql/pam";
e1da84b0
IB
185 permissions = "0400";
186 group = "postgres";
187 user = "postgres";
4aac110f
IB
188 text = with cfg.ldapConfig; ''
189 host ${host}
190 base ${base}
e1da84b0
IB
191 binddn ${dn}
192 bindpw ${password}
193 pam_filter ${filter}
194 ssl start_tls
4ff90563 195 '';
7178c2b1
IB
196 }
197 {
198 dest = "postgresql/pam_replication";
e1da84b0
IB
199 permissions = "0400";
200 group = "postgres";
201 user = "postgres";
4aac110f
IB
202 text = with cfg.replicationLdapConfig; ''
203 host ${host}
204 base ${base}
205 binddn ${dn}
206 bindpw ${password}
e1da84b0
IB
207 pam_login_attribute cn
208 ssl start_tls
4ff90563 209 '';
7178c2b1
IB
210 }
211 ];
e1da84b0
IB
212
213 security.pam.services = let
214 pam_ldap = "${pkgs.pam_ldap}/lib/security/pam_ldap.so";
4ff90563
IB
215 in [
216 {
217 name = "postgresql";
218 text = ''
182ae57f
IB
219 auth required ${pam_ldap} config=${config.secrets.location}/postgresql/pam
220 account required ${pam_ldap} config=${config.secrets.location}/postgresql/pam
4ff90563
IB
221 '';
222 }
223 {
224 name = "postgresql_replication";
225 text = ''
182ae57f
IB
226 auth required ${pam_ldap} config=${config.secrets.location}/postgresql/pam_replication
227 account required ${pam_ldap} config=${config.secrets.location}/postgresql/pam_replication
4ff90563
IB
228 '';
229 }
230 ];
231 };
232}
233