diff --git a/modules/default.nix b/modules/default.nix index 52d725b..e5e8daa 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -36,6 +36,7 @@ ./services/borgmatic ./services/coturn ./services/gitea + ./services/gitea-runner ./services/headscale ./services/mail ./services/matrix-synapse diff --git a/modules/services/gitea-runner/default.nix b/modules/services/gitea-runner/default.nix new file mode 100644 index 0000000..09ff1b2 --- /dev/null +++ b/modules/services/gitea-runner/default.nix @@ -0,0 +1,226 @@ +{ pkgs, config, lib, inputs, ... }: + +# Based on: https://git.clan.lol/clan/clan-infra/src/branch/main/modules/web01/gitea/actions-runner.nix + +with lib; + +let + cfg = config.modules.services.gitea-runner; + hostname = config.networking.hostName; + giteaUrl = "https://git.vimium.com"; + + storeDepsBins = with pkgs; [ + coreutils + findutils + gnugrep + gawk + git + nix + nix-update + bash + jq + nodejs + ]; + + storeDeps = pkgs.runCommand "store-deps" { } '' + mkdir -p $out/bin + for dir in ${toString storeDepsBins}; do + for bin in "$dir"/bin/*; do + ln -s "$bin" "$out/bin/$(basename "$bin")" + done + done + + # Add SSL CA certs + mkdir -p $out/etc/ssl/certs + cp -a "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" $out/etc/ssl/certs/ca-bundle.crt + ''; +in +{ + options.modules.services.gitea-runner = { + enable = mkOption { + default = false; + example = true; + description = mdDoc "Enable a runner for Gitea Actions on this host"; + }; + }; + + config = mkIf cfg.enable { + modules.podman.enable = true; + + systemd.services = { + gitea-runner-nix-image = { + wantedBy = [ "multi-user.target" ]; + after = [ "podman.service" ]; + requires = [ "podman.service" ]; + path = [ config.virtualisation.podman.package pkgs.gnutar pkgs.shadow pkgs.getent ]; + script = '' + set -eux -o pipefail + mkdir -p etc/nix + + # Create an unpriveleged user that we can use also without the run-as-user.sh script + touch etc/passwd etc/group + groupid=$(cut -d: -f3 < <(getent group nix-ci-user)) + userid=$(cut -d: -f3 < <(getent passwd nix-ci-user)) + groupadd --prefix $(pwd) --gid "$groupid" nix-ci-user + emptypassword='$6$1ero.LwbisiU.h3D$GGmnmECbPotJoPQ5eoSTD6tTjKnSWZcjHoVTkxFLZP17W9hRi/XkmCiAMOfWruUwy8gMjINrBMNODc7cYEo4K.' + useradd --prefix $(pwd) -p "$emptypassword" -m -d /tmp -u "$userid" -g "$groupid" -G nix-ci-user nix-ci-user + + cat < etc/nix/nix.conf + accept-flake-config = true + experimental-features = nix-command flakes + NIX_CONFIG + + cat < etc/nsswitch.conf + passwd: files mymachines systemd + group: files mymachines systemd + shadow: files + + hosts: files mymachines dns myhostname + networks: files + + ethers: files + services: files + protocols: files + rpc: files + NSSWITCH + + # list the content as it will be imported into the container + tar -cv . | tar -tvf - + tar -cv . | podman import - gitea-runner-nix + ''; + serviceConfig = { + RuntimeDirectory = "gitea-runner-nix-image"; + WorkingDirectory = "/run/gitea-runner-nix-image"; + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + + gitea-runner-nix = { + after = [ "gitea-runner-nix-image.service" ]; + requires = [ "gitea-runner-nix-image.service" ]; + + serviceConfig = { + # Hardening (may overlap with DynamicUser=) + # The following options are only for optimizing output of systemd-analyze + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + # ProtectClock= adds DeviceAllow=char-rtc r + DeviceAllow = ""; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + UMask = "0066"; + ProtectProc = "invisible"; + SystemCallFilter = [ + "~@clock" + "~@cpu-emulation" + "~@module" + "~@mount" + "~@obsolete" + "~@raw-io" + "~@reboot" + "~@swap" + # needed by go? + #"~@resources" + "~@privileged" + "~capset" + "~setdomainname" + "~sethostname" + ]; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" "AF_NETLINK" ]; + + # Needs network access + PrivateNetwork = false; + # Cannot be true due to Node + MemoryDenyWriteExecute = false; + + # The more restrictive "pid" option makes `nix` commands in CI emit + # "GC Warning: Couldn't read /proc/stat" + # You may want to set this to "pid" if not using `nix` commands + ProcSubset = "all"; + # Coverage programs for compiled code such as `cargo-tarpaulin` disable + # ASLR (address space layout randomization) which requires the + # `personality` syscall + # You may want to set this to `true` if not using coverage tooling on + # compiled code + LockPersonality = false; + + # Note that this has some interactions with the User setting; so you may + # want to consult the systemd docs if using both. + DynamicUser = true; + }; + }; + }; + + users.users.nix-ci-user = { + group = "nix-ci-user"; + description = "Used for running nix-based CI jobs"; + home = "/var/empty"; + isSystemUser = true; + }; + users.groups.nix-ci-user = { }; + + age.secrets."files/services/gitea-runner/${hostname}-token" = { + file = "${inputs.secrets}/files/services/gitea-runner/${hostname}-token.age"; + group = "podman"; + }; + + services.gitea-actions-runner.instances = { + act = { + enable = true; + url = giteaUrl; + name = "act-runner-${hostname}"; + + tokenFile = config.age.secrets."files/services/gitea-runner/${hostname}-token".path; + settings = { + cache.enabled = true; + runner.capacity = 4; + }; + + labels = [ + "debian-latest:docker://ghcr.io/catthehacker/ubuntu:act-latest" + "ubuntu-latest:docker://ghcr.io/catthehacker/ubuntu:act-latest" + ]; + }; + nix = { + enable = true; + url = giteaUrl; + name = "nix-runner-${hostname}"; + + tokenFile = config.age.secrets."files/services/gitea-runner/${hostname}-token".path; + settings = { + cache.enabled = true; + container = { + options = "-e NIX_BUILD_SHELL=/bin/bash -e PAGER=cat -e PATH=/bin -e SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt --device /dev/kvm -v /nix:/nix -v ${storeDeps}/bin:/bin -v ${storeDeps}/etc/ssl:/etc/ssl --user nix-ci-user"; + network = "host"; + valid_volumes = [ + "/nix" + "${storeDeps}/bin" + "${storeDeps}/etc/ssl" + ]; + }; + runner.capacity = 4; + }; + + labels = [ + "nix:docker://gitea-runner-nix" + ]; + }; + }; + }; +}