{ config, lib, pkgs, ... }: let inherit (lib) mkEnableOption mkIf mkOption types ; settingsFormat = pkgs.formats.toml { }; pykanidm = pkgs.python3.pkgs.callPackage ./packages/pykanidm.nix { }; rlm_python = pkgs.callPackage ./packages/rlm_python.nix { inherit pykanidm; }; cfg = config.services.k-radius; in { options.services.k-radius = { enable = mkEnableOption "a freeradius service linked to kanidm."; settings = mkOption { inherit (settingsFormat) type; }; freeradius = mkOption { type = types.package; default = pkgs.freeradius.overrideAttrs (old: { buildInputs = (old.buildInputs or [ ]) ++ [ (pkgs.python3.withPackages (ps: [ ps.kanidm ])) ]; }); }; configDir = mkOption { type = types.path; default = "/var/lib/radius/raddb"; description = "The path of the freeradius server configuration directory."; }; authTokenFile = mkOption { type = types.path; description = "File to the auth token for the service account."; }; radiusClients = mkOption { type = types.attrsOf ( types.submodule { options = { secret = mkOption { type = types.path; }; ipaddr = mkOption { type = types.str; }; }; } ); default = { }; description = "A mapping of clients and their authentication tokens."; }; certs = { ca = mkOption { type = types.str; description = "The signing CA of the RADIUS certificate."; }; dh = mkOption { type = types.str; description = "The output of `openssl dhparam -in ca.pem -out dh.pem 2048`."; }; cert = mkOption { type = types.str; description = "The certificate for the RADIUS server."; }; key = mkOption { type = types.str; description = "The signing key for the RADIUS certificate."; }; }; privateKeyPasswordFile = mkOption { type = types.path; }; }; config = mkIf cfg.enable { users = { users.radius = { group = "radius"; description = "Radius daemon user"; isSystemUser = true; }; groups.radius = { }; }; services.k-radius.settings = { ca_path = cfg.certs.ca; radius_cert_path = cfg.certs.cert; radius_key_path = cfg.certs.key; radius_dh_path = cfg.certs.dh; radius_ca_path = cfg.certs.ca; }; systemd.services.radius = { description = "FreeRadius server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; wants = [ "network.target" ]; preStart = '' cp -R ${cfg.freeradius}/etc/raddb/* ${cfg.configDir} cp -R ${rlm_python}/etc/raddb/* ${cfg.configDir} chmod -R u+w ${cfg.configDir} # disable auth via methods kanidm doesn't support rm ${cfg.configDir}/mods-available/sql rm ${cfg.configDir}/mods-enabled/{passwd,totp} # enable the python and cache modules ln -nsf ${cfg.configDir}/mods-available/python3 ${cfg.configDir}/mods-enabled/python3 ln -nsf ${cfg.configDir}/sites-available/check-eap-tls ${cfg.configDir}/sites-enabled/check-eap-tls # write the clients configuration rm ${cfg.configDir}/clients.conf && touch ${cfg.configDir}/clients.conf ${builtins.concatStringsSep "\n" ( builtins.attrValues ( builtins.mapAttrs ( name: { secret, ipaddr }: '' cat <> ${cfg.configDir}/clients.conf client ${name} { ipaddr = ${ipaddr} secret = $(cat "${secret}") proto = * } EOF '' ) cfg.radiusClients ) )} # Copy the kanidm configuration cat < /var/lib/radius/kanidm.toml auth_token = "$(cat "${cfg.authTokenFile}")" EOF cat ${settingsFormat.generate "kanidm.toml" cfg.settings} >> /var/lib/radius/kanidm.toml chmod u+w /var/lib/radius/kanidm.toml # Copy the certificates to the correct directory rm -rf ${cfg.configDir}/certs && mkdir -p ${cfg.configDir}/certs cp ${cfg.certs.ca} ${cfg.configDir}/certs/ca.pem ${pkgs.openssl}/bin/openssl rehash ${cfg.configDir}/certs cp ${cfg.certs.dh} ${cfg.configDir}/certs/dh.pem cat ${cfg.certs.cert} ${cfg.certs.key} > ${cfg.configDir}/certs/server.pem # Write the password of the private_key in the eap module sed -i ${cfg.configDir}/mods-available/eap \ -e "s/whatever/$(cat "${cfg.privateKeyPasswordFile}")/" # Check the configuration # ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout ''; path = [ pkgs.openssl pkgs.gnused ]; serviceConfig = { ExecStart = "${cfg.freeradius}/bin/radiusd -X -f -d ${cfg.configDir} -l stdout"; ExecReload = [ "${cfg.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" "${pkgs.coreutils}/bin/kill -HUP $MAINPID" ]; User = "radius"; Group = "radius"; DynamicUser = true; Restart = "on-failure"; RestartSec = 2; LogsDirectory = "radius"; StateDirectory = "radius"; RuntimeDirectory = "radius"; Environment = [ "KANIDM_RLM_CONFIG=/var/lib/radius/kanidm.toml" "PYTHONPATH=${rlm_python.pythonPath}" ]; }; }; }; }