{ lib, pkgs, config, myconfig, mylibs, ... }: let cfg = config.services.myDatabases; in { options.services.myDatabases = { mariadb = { enable = lib.mkOption { default = cfg.enable; example = true; description = "Whether to enable mariadb database"; type = lib.types.bool; }; }; }; config = lib.mkIf cfg.enable { nixpkgs.config.packageOverrides = oldpkgs: rec { mariadb = mariadbPAM; mariadbPAM = oldpkgs.mariadb.overrideAttrs(old: rec { cmakeFlags = old.cmakeFlags ++ [ "-DWITH_AUTHENTICATION_PAM=ON" ]; buildInputs = old.buildInputs ++ [ pkgs.pam ]; }); }; networking.firewall.allowedTCPPorts = [ 3306 ]; # 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'; services.mysql = rec { enable = cfg.mariadb.enable; package = pkgs.mariadb; extraOptions = '' ssl_ca = ${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt ssl_key = /var/lib/acme/mysql/key.pem ssl_cert = /var/lib/acme/mysql/fullchain.pem ''; }; security.acme.certs."mysql" = config.services.myCertificates.certConfig // { user = "mysql"; group = "mysql"; plugins = [ "fullchain.pem" "key.pem" "account_key.json" ]; domain = "db-1.immae.eu"; postRun = '' systemctl restart mysql.service ''; }; security.pam.services = let pam_ldap = "${pkgs.pam_ldap}/lib/security/pam_ldap.so"; pam_ldap_mysql = with myconfig.env.databases.mysql.pam; pkgs.writeText "mysql.conf" '' host ${myconfig.env.ldap.host} base ${myconfig.env.ldap.base} binddn ${dn} bindpw ${password} pam_filter ${filter} ssl start_tls ''; in [ { name = "mysql"; text = '' # https://mariadb.com/kb/en/mariadb/pam-authentication-plugin/ auth required ${pam_ldap} config=${pam_ldap_mysql} account required ${pam_ldap} config=${pam_ldap_mysql} ''; } ]; }; }