{...}: { flake.nixosModules.forgejo-ssh = { lib, config, pkgs, ... }: let gitUser = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER; forgejoUser = config.services.forgejo.user; forgejo = config.services.forgejo.package; stateDir = config.services.forgejo.stateDir; forgejoExe = lib.getExe forgejo; separateUsers = gitUser != forgejoUser; # Run the AuthorizedKeysCommand as the forgejo user when users differ, # so it can read app.ini without adding git to the forgejo group. keysCommandUser = if separateUsers then forgejoUser else gitUser; forgejoKeysCmd = "FORGEJO_WORK_DIR=${stateDir} ${forgejoExe} keys -e git -u \"$1\" -t \"$2\" -k \"$3\""; # When the SSH user differs from the forgejo service user, rewrite # the command= wrapper to use sudo so forgejo serv runs as the user # that owns the repository data. forgejoKeysScript = pkgs.writeShellScript "forgejo-keys" ( if separateUsers then '' ${forgejoKeysCmd} \ | ${pkgs.gnused}/bin/sed 's|command="${forgejoExe}|command="/run/wrappers/bin/sudo -u ${forgejoUser} --preserve-env=SSH_ORIGINAL_COMMAND ${forgejoExe}|' '' else forgejoKeysCmd ); forgejoKeysPath = "/run/forgejo-keys"; in { config = lib.mkIf config.services.forgejo.enable (lib.mkMerge [ { users.users.${gitUser}.shell = pkgs.bash; services.openssh.settings.AllowUsers = [gitUser]; # Copy the key lookup script to a root-owned path outside /nix/store. # sshd StrictModes requires AuthorizedKeysCommand and all parent dirs # to be owned by root with no group/world writes. /nix/store and /etc # symlinks both fail this check. system.activationScripts.forgejo-ssh-keys = lib.stringAfter ["etc"] '' install -m 0755 -o root -g root ${forgejoKeysScript} ${forgejoKeysPath} ''; services.openssh.extraConfig = '' Match User ${gitUser} AuthorizedKeysCommandUser ${keysCommandUser} AuthorizedKeysCommand ${forgejoKeysPath} %u %t %k AuthenticationMethods publickey KbdInteractiveAuthentication no PasswordAuthentication no AllowAgentForwarding no AllowTcpForwarding no X11Forwarding no PermitTTY no ''; } (lib.mkIf separateUsers { # Allow the git user to run forgejo serv as the forgejo user security.sudo.extraRules = [ { users = [gitUser]; runAs = forgejoUser; commands = [ { command = "${forgejoExe} --config=${stateDir}/custom/conf/app.ini serv *"; options = ["NOPASSWD" "SETENV"]; } ]; } ]; }) ]); }; }