blob: b4a6917a76018aaea2bc41ee5591bf4133b5ced4 (
plain) (
tree)
|
|
{ lib, pkgs, config, ... }:
let
cfg = config.myServices.databases.mariadb;
in {
options.myServices.databases = {
mariadb = {
enable = lib.mkOption {
default = false;
example = true;
description = "Whether to enable mariadb database";
type = lib.types.bool;
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.mariadb;
description = ''
Mariadb package to use.
'';
};
credentials = lib.mkOption {
default = {};
description = "Credentials";
type = lib.types.attrsOf lib.types.str;
};
ldapConfig = lib.mkOption {
description = "LDAP configuration to allow PAM identification via LDAP";
type = lib.types.submodule {
options = {
host = lib.mkOption { type = lib.types.str; };
base = lib.mkOption { type = lib.types.str; };
dn = lib.mkOption { type = lib.types.str; };
password = lib.mkOption { type = lib.types.str; };
filter = lib.mkOption { type = lib.types.str; };
};
};
};
replicationLdapConfig = lib.mkOption {
description = "LDAP configuration to allow replication";
type = lib.types.submodule {
options = {
host = lib.mkOption { type = lib.types.str; };
base = lib.mkOption { type = lib.types.str; };
dn = lib.mkOption { type = lib.types.str; };
password = lib.mkOption { type = lib.types.str; };
};
};
};
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/mysql";
description = ''
The directory where Mariadb stores its data.
'';
};
# Output variables
socketsDir = lib.mkOption {
type = lib.types.path;
default = "/run/mysqld";
description = ''
The directory where Mariadb puts sockets.
'';
};
sockets = lib.mkOption {
type = lib.types.attrsOf lib.types.path;
default = {
mysqld = "${cfg.socketsDir}/mysqld.sock";
};
readOnly = true;
description = ''
Mariadb sockets
'';
};
};
};
config = lib.mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ config.myEnv.databases.mysql.port ];
# for adminer, ssl is implemented with mysqli only, which is
# currently disabled because it’s not compatible with pam.
# Thus we need to generate two users for each 'remote': one remote
# with SSL, and one localhost without SSL.
# User identified by LDAP:
# CREATE USER foo@% IDENTIFIED VIA pam USING 'mysql' REQUIRE SSL;
# CREATE USER foo@localhost IDENTIFIED VIA pam USING 'mysql';
# To create a user (host) for replication:
# CREATE USER 'host'@'%' IDENTIFIED VIA pam USING 'mysql_replication' REQUIRE SSL;
# GRANT REPLICATION SLAVE, REPLICATION CLIENT, RELOAD, LOCK TABLES, SELECT, SHOW VIEW ON *.* TO 'host'@'%';
# (the lock/select grant permits to let the replication host handle
# the initial fetch of the database)
# % should be valid for both localhost (for cron dumps) and the origin host.
services.mysql = {
enable = true;
package = cfg.package;
dataDir = cfg.dataDir;
settings = {
mysqld = {
port = config.myEnv.databases.mysql.port;
ssl_ca = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
ssl_key = "${config.security.acme.certs.mysql.directory}/key.pem";
ssl_cert = "${config.security.acme.certs.mysql.directory}/fullchain.pem";
# for replication
log-bin = "mariadb-bin";
server-id = "1";
# this introduces a small delay before storing on disk, but
# makes it order of magnitudes quicker
innodb_flush_log_at_trx_commit = "0";
# This is necessary since the default ("dialog") is not
# supported by php's mysqlnd plugin (in mysqli). But with that
# change only regular login+password schemes can work (no
# "fancy" authentication methods like fprintd or keys)
pam_use_cleartext_plugin = true;
};
};
};
users.users.mysql.extraGroups = [ "keys" ];
security.acme.certs."mysql" = {
group = "mysql";
domain = "db-1.immae.eu";
postRun = ''
systemctl restart mysql.service
'';
};
secrets.keys = {
"mysql/mysqldump" = {
permissions = "0400";
user = "root";
group = "root";
text = ''
[mysqldump]
user = root
password = ${cfg.credentials.root}
'';
};
"mysql/pam" = {
permissions = "0400";
user = "mysql";
group = "mysql";
text = with cfg.ldapConfig; ''
host ${host}
base ${base}
binddn ${dn}
bindpw ${password}
pam_filter ${filter}
ssl start_tls
'';
};
"mysql/pam_replication" = {
permissions = "0400";
user = "mysql";
group = "mysql";
text = with cfg.replicationLdapConfig; ''
host ${host}
base ${base}
binddn ${dn}
bindpw ${password}
pam_login_attribute cn
ssl start_tls
'';
};
};
security.pam.services = let
pam_ldap = "${pkgs.pam_ldap}/lib/security/pam_ldap.so";
in {
mysql = {
text = ''
# https://mariadb.com/kb/en/mariadb/pam-authentication-plugin/
auth required ${pam_ldap} config=${config.secrets.fullPaths."mysql/pam"}
account required ${pam_ldap} config=${config.secrets.fullPaths."mysql/pam"}
'';
};
mysql_replication = {
text = ''
auth required ${pam_ldap} config=${config.secrets.fullPaths."mysql/pam_replication"}
account required ${pam_ldap} config=${config.secrets.fullPaths."mysql/pam_replication"}
'';
};
};
};
}
|