1 { lib, pkgs, config, ... }:
3 cfg = config.myServices.databases.mariadb;
5 options.myServices.databases = {
7 enable = lib.mkOption {
10 description = "Whether to enable mariadb database";
11 type = lib.types.bool;
13 package = lib.mkOption {
14 type = lib.types.package;
15 default = pkgs.mariadb;
17 Mariadb package to use.
20 credentials = lib.mkOption {
22 description = "Credentials";
23 type = lib.types.attrsOf lib.types.str;
25 ldapConfig = lib.mkOption {
26 description = "LDAP configuration to allow PAM identification via LDAP";
27 type = lib.types.submodule {
29 host = lib.mkOption { type = lib.types.str; };
30 base = lib.mkOption { type = lib.types.str; };
31 dn = lib.mkOption { type = lib.types.str; };
32 password = lib.mkOption { type = lib.types.str; };
33 filter = lib.mkOption { type = lib.types.str; };
37 replicationLdapConfig = lib.mkOption {
38 description = "LDAP configuration to allow replication";
39 type = lib.types.submodule {
41 host = lib.mkOption { type = lib.types.str; };
42 base = lib.mkOption { type = lib.types.str; };
43 dn = lib.mkOption { type = lib.types.str; };
44 password = lib.mkOption { type = lib.types.str; };
48 dataDir = lib.mkOption {
49 type = lib.types.path;
50 default = "/var/lib/mysql";
52 The directory where Mariadb stores its data.
56 socketsDir = lib.mkOption {
57 type = lib.types.path;
58 default = "/run/mysqld";
60 The directory where Mariadb puts sockets.
63 sockets = lib.mkOption {
64 type = lib.types.attrsOf lib.types.path;
66 mysqld = "${cfg.socketsDir}/mysqld.sock";
76 config = lib.mkIf cfg.enable {
77 networking.firewall.allowedTCPPorts = [ 3306 ];
79 # for adminer, ssl is implemented with mysqli only, which is
80 # currently disabled because it’s not compatible with pam.
81 # Thus we need to generate two users for each 'remote': one remote
82 # with SSL, and one localhost without SSL.
83 # User identified by LDAP:
84 # CREATE USER foo@% IDENTIFIED VIA pam USING 'mysql' REQUIRE SSL;
85 # CREATE USER foo@localhost IDENTIFIED VIA pam USING 'mysql';
87 # To create a user (host) for replication:
88 # CREATE USER 'host'@'%' IDENTIFIED VIA pam USING 'mysql_replication' REQUIRE SSL;
89 # GRANT REPLICATION SLAVE, REPLICATION CLIENT, RELOAD, LOCK TABLES, SELECT, SHOW VIEW ON *.* TO 'host'@'%';
90 # (the lock/select grant permits to let the replication host handle
91 # the initial fetch of the database)
92 # % should be valid for both localhost (for cron dumps) and the origin host.
95 package = cfg.package;
96 dataDir = cfg.dataDir;
99 ssl_ca = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
100 ssl_key = "${config.security.acme.certs.mysql.directory}/key.pem";
101 ssl_cert = "${config.security.acme.certs.mysql.directory}/fullchain.pem";
104 log-bin = "mariadb-bin";
107 # this introduces a small delay before storing on disk, but
108 # makes it order of magnitudes quicker
109 innodb_flush_log_at_trx_commit = "0";
114 users.users.mysql.extraGroups = [ "keys" ];
115 security.acme.certs."mysql" = config.myServices.databasesCerts // {
118 domain = "db-1.immae.eu";
120 systemctl restart mysql.service
126 dest = "mysql/mysqldump";
127 permissions = "0400";
133 password = ${cfg.credentials.root}
138 permissions = "0400";
141 text = with cfg.ldapConfig; ''
151 dest = "mysql/pam_replication";
152 permissions = "0400";
155 text = with cfg.replicationLdapConfig; ''
160 pam_login_attribute cn
166 security.pam.services = let
167 pam_ldap = "${pkgs.pam_ldap}/lib/security/pam_ldap.so";
171 # https://mariadb.com/kb/en/mariadb/pam-authentication-plugin/
172 auth required ${pam_ldap} config=${config.secrets.location}/mysql/pam
173 account required ${pam_ldap} config=${config.secrets.location}/mysql/pam
176 mysql_replication = {
178 auth required ${pam_ldap} config=${config.secrets.location}/mysql/pam_replication
179 account required ${pam_ldap} config=${config.secrets.location}/mysql/pam_replication