diff options
Diffstat (limited to 'nixos')
58 files changed, 1146 insertions, 239 deletions
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml index 582b1715d1a..e105d689864 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml @@ -270,6 +270,13 @@ </listitem> <listitem> <para> + <link xlink:href="https://github.com/shizunge/endlessh-go">endlessh-go</link>, + an SSH tarpit that exposes Prometheus metrics. Available as + <link linkend="opt-services.endlessh-go.enable">services.endlessh-go</link>. + </para> + </listitem> + <listitem> + <para> <link xlink:href="https://netbird.io">netbird</link>, a zero configuration VPN. Available as <link xlink:href="options.html#opt-services.netbird.enable">services.netbird</link>. @@ -322,6 +329,15 @@ </listitem> <listitem> <para> + <link xlink:href="https://github.com/tmate-io/tmate-ssh-server">tmate-ssh-server</link>, + server side part of + <link xlink:href="https://tmate.io/">tmate</link>. Available + as + <link linkend="opt-services.tmate-ssh-server.enable">services.tmate-ssh-server</link>. + </para> + </listitem> + <listitem> + <para> <link xlink:href="https://www.grafana.com/oss/tempo/">Grafana Tempo</link>, a distributed tracing store. Available as <link linkend="opt-services.tempo.enable">services.tempo</link>. @@ -474,6 +490,16 @@ </listitem> <listitem> <para> + The <literal>p4</literal> package now only includes the + open-source Perforce Helix Core command-line client and APIs. + It no longer installs the unfree Helix Core Server binaries + <literal>p4d</literal>, <literal>p4broker</literal>, and + <literal>p4p</literal>. To install the Helix Core Server + binaries, use the <literal>p4d</literal> package instead. + </para> + </listitem> + <listitem> + <para> The <literal>coq</literal> package and versioned variants starting at <literal>coq_8_14</literal> no longer include CoqIDE, which is now available through @@ -492,7 +518,9 @@ <listitem> <para> <literal>pkgs.cosign</literal> does not provide the - <literal>cosigned</literal> binary anymore. + <literal>cosigned</literal> binary anymore. The + <literal>sget</literal> binary has been moved into its own + package. </para> </listitem> <listitem> @@ -529,6 +557,16 @@ </listitem> <listitem> <para> + <literal>teleport</literal> has been upgraded to major version + 10. Please see upstream + <link xlink:href="https://goteleport.com/docs/ver/10.0/management/operations/upgrading/">upgrade + instructions</link> and + <link xlink:href="https://goteleport.com/docs/ver/10.0/changelog/#1000">release + notes</link>. + </para> + </listitem> + <listitem> + <para> lemmy module option <literal>services.lemmy.settings.database.createLocally</literal> moved to @@ -589,6 +627,12 @@ </listitem> <listitem> <para> + The default <literal>kops</literal> version is now 1.25.1 and + support for 1.22 and older has been dropped. + </para> + </listitem> + <listitem> + <para> <literal>k3s</literal> no longer supports docker as runtime due to upstream dropping support. </para> diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index 3e38f85b8f1..43e28836a4e 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -95,6 +95,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [alps](https://git.sr.ht/~migadu/alps), a simple and extensible webmail. Available as [services.alps](#opt-services.alps.enable). +- [endlessh-go](https://github.com/shizunge/endlessh-go), an SSH tarpit that exposes Prometheus metrics. Available as [services.endlessh-go](#opt-services.endlessh-go.enable). + - [netbird](https://netbird.io), a zero configuration VPN. Available as [services.netbird](options.html#opt-services.netbird.enable). @@ -110,6 +112,8 @@ In addition to numerous new and upgraded packages, this release has the followin - [go-autoconfig](https://github.com/L11R/go-autoconfig), IMAP/SMTP autodiscover server. Available as [services.go-autoconfig](#opt-services.go-autoconfig.enable). +- [tmate-ssh-server](https://github.com/tmate-io/tmate-ssh-server), server side part of [tmate](https://tmate.io/). Available as [services.tmate-ssh-server](#opt-services.tmate-ssh-server.enable). + - [Grafana Tempo](https://www.grafana.com/oss/tempo/), a distributed tracing store. Available as [services.tempo](#opt-services.tempo.enable). - [AusweisApp2](https://www.ausweisapp.bund.de/), the authentication software for the German ID card. Available as [programs.ausweisapp](#opt-programs.ausweisapp.enable). @@ -158,6 +162,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable). - `services.hbase` has been renamed to `services.hbase-standalone`. For production HBase clusters, use `services.hadoop.hbase` instead. +- The `p4` package now only includes the open-source Perforce Helix Core command-line client and APIs. It no longer installs the unfree Helix Core Server binaries `p4d`, `p4broker`, and `p4p`. To install the Helix Core Server binaries, use the `p4d` package instead. + - The `coq` package and versioned variants starting at `coq_8_14` no longer include CoqIDE, which is now available through `coqPackages.coqide`. It is still possible to get CoqIDE as part of @@ -167,7 +173,7 @@ Available as [services.patroni](options.html#opt-services.patroni.enable). - PHP 7.4 is no longer supported due to upstream not supporting this version for the entire lifecycle of the 22.11 release. -- `pkgs.cosign` does not provide the `cosigned` binary anymore. +- `pkgs.cosign` does not provide the `cosigned` binary anymore. The `sget` binary has been moved into its own package. - Emacs now uses the Lucid toolkit by default instead of GTK because of stability and compatibility issues. Users who still wish to remain using GTK can do so by using `emacs-gtk`. @@ -178,6 +184,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable). - dd-agent package removed along with the `services.dd-agent` module, due to the project being deprecated in favor of `datadog-agent`, which is available via the `services.datadog-agent` module. +- `teleport` has been upgraded to major version 10. Please see upstream [upgrade instructions](https://goteleport.com/docs/ver/10.0/management/operations/upgrading/) and [release notes](https://goteleport.com/docs/ver/10.0/changelog/#1000). + - lemmy module option `services.lemmy.settings.database.createLocally` moved to `services.lemmy.database.createLocally`. @@ -198,6 +206,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable). Use `configure.packages` instead. - Neovim can not be configured with plug anymore (still works for vim). +- The default `kops` version is now 1.25.1 and support for 1.22 and older has been dropped. + - `k3s` no longer supports docker as runtime due to upstream dropping support. - `k3s` supports `clusterInit` option, and it is enabled by default, for servers. diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix index d7671a37499..f646f70323e 100644 --- a/nixos/lib/utils.nix +++ b/nixos/lib/utils.nix @@ -102,7 +102,11 @@ rec { if item ? ${attr} then nameValuePair prefix item.${attr} else if isAttrs item then - map (name: recurse (prefix + "." + name) item.${name}) (attrNames item) + map (name: + let + escapedName = ''"${replaceChars [''"'' "\\"] [''\"'' "\\\\"] name}"''; + in + recurse (prefix + "." + escapedName) item.${name}) (attrNames item) else if isList item then imap0 (index: item: recurse (prefix + "[${toString index}]") item) item else @@ -182,13 +186,13 @@ rec { '') (attrNames secrets)) + "\n" - + "${pkgs.jq}/bin/jq >'${output}' '" - + concatStringsSep + + "${pkgs.jq}/bin/jq >'${output}' " + + lib.escapeShellArg (concatStringsSep " | " (imap1 (index: name: ''${name} = $ENV.secret${toString index}'') - (attrNames secrets)) + (attrNames secrets))) + '' - ' <<'EOF' + <<'EOF' ${builtins.toJSON set} EOF (( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 3e969991f8f..80ff6c1aabf 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -102,7 +102,7 @@ in { each user that tries to use the sound system. The server runs with user privileges. If true, one system-wide PulseAudio server is launched on boot, running as the user "pulse", and - only users in the "audio" group will have access to the server. + only users in the "pulse-access" group will have access to the server. Please read the PulseAudio documentation for more details. Don't enable this option unless you know what you are doing. @@ -310,6 +310,7 @@ in { }; users.groups.pulse.gid = gid; + users.groups.pulse-access = {}; systemd.services.pulseaudio = { description = "PulseAudio System-Wide Server"; diff --git a/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix index a808429c999..8dadbd53b98 100644 --- a/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix +++ b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix @@ -23,8 +23,10 @@ in runCommand "uvcdynctrl-udev-rules-${version}" { inherit dataPath; - buildInputs = [ + nativeBuildInputs = [ makeWrapper + ]; + buildInputs = [ libwebcam ]; dontPatchELF = true; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix index c5976166fb3..4a00c52916f 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix @@ -38,9 +38,9 @@ with lib; # VM guest additions to improve host-guest interaction services.spice-vdagentd.enable = true; services.qemuGuest.enable = true; - virtualisation.vmware.guest.enable = true; + virtualisation.vmware.guest.enable = pkgs.stdenv.hostPlatform.isx86; virtualisation.hypervGuest.enable = true; - services.xe-guest-utilities.enable = true; + services.xe-guest-utilities.enable = pkgs.stdenv.hostPlatform.isx86; # The VirtualBox guest additions rely on an out-of-tree kernel module # which lags behind kernel releases, potentially causing broken builds. virtualisation.virtualbox.guest.enable = false; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c2545016707..494df03e3a3 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -960,6 +960,7 @@ ./services/networking/tinc.nix ./services/networking/tinydns.nix ./services/networking/tftpd.nix + ./services/networking/tmate-ssh-server.nix ./services/networking/trickster.nix ./services/networking/tox-bootstrapd.nix ./services/networking/tox-node.nix @@ -1003,6 +1004,7 @@ ./services/security/certmgr.nix ./services/security/cfssl.nix ./services/security/clamav.nix + ./services/security/endlessh-go.nix ./services/security/fail2ban.nix ./services/security/fprintd.nix ./services/security/haka.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 33dd80d7c5a..c415ca85743 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -1,7 +1,7 @@ # This module defines the software packages included in the "minimal" # installation CD. It might be useful elsewhere. -{ lib, pkgs, ... }: +{ config, lib, pkgs, ... }: { # Include some utilities that are useful for installing or repairing @@ -51,7 +51,9 @@ ]; # Include support for various filesystems. - boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "zfs" "ntfs" "cifs" ]; + boot.supportedFilesystems = + [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ] ++ + lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs"; # Configure host id for ZFS to work networking.hostId = lib.mkDefault "8425e349"; diff --git a/nixos/modules/programs/mininet.nix b/nixos/modules/programs/mininet.nix index 0b7e82cc5bd..02272729d23 100644 --- a/nixos/modules/programs/mininet.nix +++ b/nixos/modules/programs/mininet.nix @@ -14,7 +14,7 @@ let pyEnv = pkgs.python.withPackages(ps: [ ps.mininet-python ]); mnexecWrapped = pkgs.runCommand "mnexec-wrapper" - { buildInputs = [ pkgs.makeWrapper pkgs.pythonPackages.wrapPython ]; } + { nativeBuildInputs = [ pkgs.makeWrapper pkgs.pythonPackages.wrapPython ]; } '' makeWrapper ${pkgs.mininet}/bin/mnexec \ $out/bin/mnexec \ diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 865c0becdbc..36b724e04bd 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -14,6 +14,7 @@ let '' #! ${pkgs.runtimeShell} -e export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')" + export WAYLAND_DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^WAYLAND_DISPLAY=\(.*\)/\1/; t; d')" exec ${askPassword} "$@" ''; diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix index 377b543c581..e9299fb1b3a 100644 --- a/nixos/modules/security/acme/default.nix +++ b/nixos/modules/security/acme/default.nix @@ -190,7 +190,7 @@ let ); renewOpts = escapeShellArgs ( commonOpts - ++ [ "renew" ] + ++ [ "renew" "--no-random-sleep" ] ++ optionals data.ocspMustStaple [ "--must-staple" ] ++ data.extraLegoRenewFlags ); @@ -223,9 +223,9 @@ let # have many certificates, the renewals are distributed over # the course of the day to avoid rate limits. AccuracySec = "${toString (_24hSecs / numCerts)}s"; - # Skew randomly within the day, per https://letsencrypt.org/docs/integration-guide/. RandomizedDelaySec = "24h"; + FixedRandomDelay = true; }; }; @@ -325,6 +325,7 @@ let ''); } // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) { CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; }; # Working directory will be /tmp @@ -376,7 +377,8 @@ let # Check if we can renew. # We can only renew if the list of domains has not changed. - if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(ls -1 accounts)" ]; then + # We also need an account key. Avoids #190493 + if cmp -s domainhash.txt certificates/domainhash.txt && [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a -n "$(find accounts -name '${data.email}.key')" ]; then # Even if a cert is not expired, it may be revoked by the CA. # Try to renew, and silently fail if the cert is not expired. diff --git a/nixos/modules/security/acme/doc.xml b/nixos/modules/security/acme/doc.xml index 4817f7a7fc6..1439594a5ac 100644 --- a/nixos/modules/security/acme/doc.xml +++ b/nixos/modules/security/acme/doc.xml @@ -237,8 +237,8 @@ services.bind = { <programlisting> systemd.services.dns-rfc2136-conf = { - requiredBy = ["acme-example.com.service", "bind.service"]; - before = ["acme-example.com.service", "bind.service"]; + requiredBy = ["acme-example.com.service" "bind.service"]; + before = ["acme-example.com.service" "bind.service"]; unitConfig = { ConditionPathExists = "!/var/lib/secrets/dnskeys.conf"; }; @@ -249,18 +249,19 @@ systemd.services.dns-rfc2136-conf = { path = [ pkgs.bind ]; script = '' mkdir -p /var/lib/secrets + chmod 755 /var/lib/secrets tsig-keygen rfc2136key.example.com > /var/lib/secrets/dnskeys.conf chown named:root /var/lib/secrets/dnskeys.conf chmod 400 /var/lib/secrets/dnskeys.conf - # Copy the secret value from the dnskeys.conf, and put it in - # RFC2136_TSIG_SECRET below + # extract secret value from the dnskeys.conf + while read x y; do if [ "$x" = "secret" ]; then secret="''${y:1:''${#y}-3}"; fi; done < /var/lib/secrets/dnskeys.conf cat > /var/lib/secrets/certs.secret << EOF RFC2136_NAMESERVER='127.0.0.1:53' RFC2136_TSIG_ALGORITHM='hmac-sha256.' RFC2136_TSIG_KEY='rfc2136key.example.com' - RFC2136_TSIG_SECRET='your secret key' + RFC2136_TSIG_SECRET='$secret' EOF chmod 400 /var/lib/secrets/certs.secret ''; diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix index 50ee9a82451..40e8679f53d 100644 --- a/nixos/modules/services/audio/mopidy.nix +++ b/nixos/modules/services/audio/mopidy.nix @@ -14,7 +14,7 @@ let name = "mopidy-with-extensions-${mopidy.version}"; paths = closePropagation cfg.extensionPackages; pathsToLink = [ "/${mopidyPackages.python.sitePackages}" ]; - buildInputs = [ makeWrapper ]; + nativeBuildInputs = [ makeWrapper ]; postBuild = '' makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \ --prefix PYTHONPATH : $out/${mopidyPackages.python.sitePackages} diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index f02e15f2b98..7b29eb41e72 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -116,7 +116,7 @@ let original, name, set ? {} }: pkgs.runCommand "${name}-wrapper" { - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; } (with lib; '' makeWrapper "${original}" "$out/bin/${name}" \ ${concatStringsSep " \\\n " (mapAttrsToList (name: value: ''--set ${name} "${value}"'') set)} diff --git a/nixos/modules/services/continuous-integration/github-runner.nix b/nixos/modules/services/continuous-integration/github-runner.nix index 9abe13a89af..2ece75722a1 100644 --- a/nixos/modules/services/continuous-integration/github-runner.nix +++ b/nixos/modules/services/continuous-integration/github-runner.nix @@ -200,46 +200,65 @@ in ${lines} ''; - currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json"; runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" "ephemeral" ] cfg; newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig); - newConfigTokenFilename = ".new-token"; + currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json"; + newConfigTokenPath= "$STATE_DIRECTORY/.new-token"; + currentConfigTokenPath = "$STATE_DIRECTORY/${currentConfigTokenFilename}"; + runnerCredFiles = [ ".credentials" ".credentials_rsaparams" ".runner" ]; unconfigureRunner = writeScript "unconfigure" '' - differs= - - if [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then - # State directory is not empty - # Set `differs = 1` if current and new runner config differ or if `currentConfigPath` does not exist - ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 || differs=1 - # Also trigger a registration if the token content changed - ${pkgs.diffutils}/bin/diff -q \ - "$STATE_DIRECTORY"/${currentConfigTokenFilename} \ - ${escapeShellArg cfg.tokenFile} \ - >/dev/null 2>&1 || differs=1 - # If .credentials does not exist, assume a previous run de-registered the runner on stop (ephemeral mode) - [[ ! -f "$STATE_DIRECTORY/.credentials" ]] && differs=1 - fi - - if [[ -n "$differs" ]]; then - echo "Config has changed, removing old runner state." - # In ephemeral mode, the runner deletes the `.credentials` file after de-registering it with GitHub - [[ -f "$STATE_DIRECTORY/.credentials" ]] && echo "The old runner will still appear in the GitHub Actions UI." \ - "You have to remove it manually." - find "$STATE_DIRECTORY/" -mindepth 1 -delete - + copy_tokens() { # Copy the configured token file to the state dir and allow the service user to read the file - install --mode=666 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${newConfigTokenFilename}" + install --mode=666 ${escapeShellArg cfg.tokenFile} "${newConfigTokenPath}" # Also copy current file to allow for a diff on the next start - install --mode=600 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${currentConfigTokenFilename}" + install --mode=600 ${escapeShellArg cfg.tokenFile} "${currentConfigTokenPath}" + } + + clean_state() { + find "$STATE_DIRECTORY/" -mindepth 1 -delete + copy_tokens + } + + diff_config() { + changed=0 + + # Check for module config changes + [[ -f "${currentConfigPath}" ]] \ + && ${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 \ + || changed=1 + + # Also check the content of the token file + [[ -f "${currentConfigTokenPath}" ]] \ + && ${pkgs.diffutils}/bin/diff -q "${currentConfigTokenPath}" ${escapeShellArg cfg.tokenFile} >/dev/null 2>&1 \ + || changed=1 + + # If the config has changed, remove old state and copy tokens + if [[ "$changed" -eq 1 ]]; then + echo "Config has changed, removing old runner state." + echo "The old runner will still appear in the GitHub Actions UI." \ + "You have to remove it manually." + clean_state + fi + } + + if [[ "${optionalString cfg.ephemeral "1"}" ]]; then + # In ephemeral mode, we always want to start with a clean state + clean_state + elif [[ "$(ls -A "$STATE_DIRECTORY")" ]]; then + # There are state files from a previous run; diff them to decide if we need a new registration + diff_config + else + # The state directory is entirely empty which indicates a first start + copy_tokens fi ''; configureRunner = writeScript "configure" '' - if [[ -e "$STATE_DIRECTORY/${newConfigTokenFilename}" ]]; then + if [[ -e "${newConfigTokenPath}" ]]; then echo "Configuring GitHub Actions Runner" args=( @@ -256,7 +275,7 @@ in # If the token file contains a PAT (i.e., it starts with "ghp_"), we have to use the --pat option, # if it is not a PAT, we assume it contains a registration token and use the --token option - token=$(<"$STATE_DIRECTORY/${newConfigTokenFilename}") + token=$(<"${newConfigTokenPath}") if [[ "$token" =~ ^ghp_* ]]; then args+=(--pat "$token") else @@ -271,7 +290,7 @@ in rm -rf "$STATE_DIRECTORY/_diag/" # Cleanup token from config - rm "$STATE_DIRECTORY/${newConfigTokenFilename}" + rm "${newConfigTokenPath}" # Symlink to new config ln -s '${newConfigPath}' "${currentConfigPath}" @@ -305,8 +324,8 @@ in WorkingDirectory = runtimeDir; InaccessiblePaths = [ - # Token file path given in the configuration - cfg.tokenFile + # Token file path given in the configuration, if visible to the service + "-${cfg.tokenFile}" # Token file in the state directory "${stateDir}/${currentConfigTokenFilename}" ]; diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix index 8b5c1228c52..71147957504 100644 --- a/nixos/modules/services/continuous-integration/hydra/default.nix +++ b/nixos/modules/services/continuous-integration/hydra/default.nix @@ -42,7 +42,7 @@ let makeWrapperArgs = concatStringsSep " " (mapAttrsToList (key: value: "--set \"${key}\" \"${value}\"") hydraEnv); in pkgs.buildEnv rec { name = "hydra-env"; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; paths = [ cfg.package ]; postBuild = '' diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index 2249f866803..98f837bd782 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -33,18 +33,26 @@ let mkEtcFile = p: nameValuePair (mkName p) { source = p; }; in listToAttrs (map mkEtcFile cfg.extraTrustedKeys); - # We cannot include the file in $out and rely on filesInstalledToEtc - # to install it because it would create a cyclic dependency between - # the outputs. We also need to enable the remote, - # which should not be done by default. - testRemote = if cfg.enableTestRemote then { - "fwupd/remotes.d/fwupd-tests.conf" = { - source = pkgs.runCommand "fwupd-tests-enabled.conf" {} '' + enableRemote = base: remote: { + "fwupd/remotes.d/${remote}.conf" = { + source = pkgs.runCommand "${remote}-enabled.conf" {} '' sed "s,^Enabled=false,Enabled=true," \ - "${cfg.package.installedTests}/etc/fwupd/remotes.d/fwupd-tests.conf" > "$out" + "${base}/etc/fwupd/remotes.d/${remote}.conf" > "$out" ''; }; - } else {}; + }; + remotes = (foldl' + (configFiles: remote: configFiles // (enableRemote cfg.package remote)) + {} + cfg.extraRemotes + ) // ( + # We cannot include the file in $out and rely on filesInstalledToEtc + # to install it because it would create a cyclic dependency between + # the outputs. We also need to enable the remote, + # which should not be done by default. + if cfg.enableTestRemote then (enableRemote cfg.package.installedTests "fwupd-tests") else {} + ); + in { ###### interface @@ -86,6 +94,15 @@ in { ''; }; + extraRemotes = mkOption { + type = with types; listOf str; + default = []; + example = [ "lvfs-testing" ]; + description = lib.mdDoc '' + Enables extra remotes in fwupd. See `/etc/fwupd/remotes.d`. + ''; + }; + enableTestRemote = mkOption { type = types.bool; default = false; @@ -119,7 +136,7 @@ in { environment.systemPackages = [ cfg.package ]; # customEtc overrides some files from the package - environment.etc = originalEtc // customEtc // extraTrustedKeys // testRemote; + environment.etc = originalEtc // customEtc // extraTrustedKeys // remotes; services.dbus.packages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index fa9d06b441a..4b962da0c03 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -171,10 +171,10 @@ let mv etc/udev/hwdb.bin $out ''; - compressFirmware = if config.boot.kernelPackages.kernelAtLeast "5.3" then - pkgs.compressFirmwareXz + compressFirmware = firmware: if (config.boot.kernelPackages.kernelAtLeast "5.3" && (firmware.compressFirmware or true)) then + pkgs.compressFirmwareXz firmware else - id; + id firmware; # Udev has a 512-character limit for ENV{PATH}, so create a symlink # tree to work around this. diff --git a/nixos/modules/services/matrix/dendrite.nix b/nixos/modules/services/matrix/dendrite.nix index 9279af246f4..a5fea3da484 100644 --- a/nixos/modules/services/matrix/dendrite.nix +++ b/nixos/modules/services/matrix/dendrite.nix @@ -195,6 +195,25 @@ in ''; }; }; + options.sync_api.search = { + enable = lib.mkEnableOption (lib.mdDoc "Dendrite's full-text search engine"); + index_path = lib.mkOption { + type = lib.types.str; + default = "${workingDir}/searchindex"; + description = lib.mdDoc '' + The path the search index will be created in. + ''; + }; + language = lib.mkOption { + type = lib.types.str; + default = "en"; + description = lib.mdDoc '' + The language most likely to be used on the server - used when indexing, to + ensure the returned results match expectations. A full list of possible languages + can be found at https://github.com/blevesearch/bleve/tree/master/analysis/lang + ''; + }; + }; options.user_api = { account_database = { connection_string = lib.mkOption { diff --git a/nixos/modules/services/misc/etebase-server.nix b/nixos/modules/services/misc/etebase-server.nix index 76c7c6596c8..c3723d18814 100644 --- a/nixos/modules/services/misc/etebase-server.nix +++ b/nixos/modules/services/misc/etebase-server.nix @@ -162,7 +162,7 @@ in environment.systemPackages = with pkgs; [ (runCommand "etebase-server" { - buildInputs = [ makeWrapper ]; + nativeBuildInputs = [ makeWrapper ]; } '' makeWrapper ${pythonEnv}/bin/etebase-server \ $out/bin/etebase-server \ diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index e5de3a2b6ad..4988517a9b6 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -6,6 +6,9 @@ let cfg = config.services.gitlab; opt = options.services.gitlab; + toml = pkgs.formats.toml {}; + yaml = pkgs.formats.yaml {}; + ruby = cfg.packages.gitlab.ruby; postgresqlPackage = if config.services.postgresql.enable then @@ -89,17 +92,18 @@ let repos_path = "${cfg.statePath}/repositories"; secret_file = "${cfg.statePath}/gitlab_shell_secret"; log_file = "${cfg.statePath}/log/gitlab-shell.log"; - redis = { - bin = "${pkgs.redis}/bin/redis-cli"; - host = "127.0.0.1"; - port = config.services.redis.servers.gitlab.port; - database = 0; - namespace = "resque:gitlab"; - }; }; redisConfig.production.url = cfg.redisUrl; + cableYml = yaml.generate "cable.yml" { + production = { + adapter = "redis"; + url = cfg.redisUrl; + channel_prefix = "gitlab_production"; + }; + }; + pagesArgs = [ "-pages-domain" gitlabConfig.production.pages.host "-pages-root" "${gitlabConfig.production.shared.path}/pages" @@ -188,16 +192,27 @@ let MALLOC_ARENA_MAX = "2"; } // cfg.extraEnv; + runtimeDeps = with pkgs; [ + nodejs + gzip + git + gnutar + postgresqlPackage + coreutils + procps + findutils # Needed for gitlab:cleanup:orphan_job_artifact_files + ]; + gitlab-rake = pkgs.stdenv.mkDerivation { name = "gitlab-rake"; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; dontBuild = true; dontUnpack = true; installPhase = '' mkdir -p $out/bin makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rake $out/bin/gitlab-rake \ ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \ - --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar postgresqlPackage pkgs.coreutils pkgs.procps ]}:$PATH' \ + --set PATH '${lib.makeBinPath runtimeDeps}:$PATH' \ --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \ --chdir '${cfg.packages.gitlab}/share/gitlab' ''; @@ -205,14 +220,14 @@ let gitlab-rails = pkgs.stdenv.mkDerivation { name = "gitlab-rails"; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; dontBuild = true; dontUnpack = true; installPhase = '' mkdir -p $out/bin makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rails $out/bin/gitlab-rails \ ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \ - --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar postgresqlPackage pkgs.coreutils pkgs.procps ]}:$PATH' \ + --set PATH '${lib.makeBinPath runtimeDeps}:$PATH' \ --chdir '${cfg.packages.gitlab}/share/gitlab' ''; }; @@ -468,9 +483,9 @@ in { redisUrl = mkOption { type = types.str; - default = "redis://localhost:${toString config.services.redis.servers.gitlab.port}/"; - defaultText = literalExpression ''redis://localhost:''${toString config.services.redis.servers.gitlab.port}/''; - description = lib.mdDoc "Redis URL for all GitLab services except gitlab-shell"; + default = "unix:/run/gitlab/redis.sock"; + example = "redis://localhost:6379/"; + description = lib.mdDoc "Redis URL for all GitLab services."; }; extraGitlabRb = mkOption { @@ -867,8 +882,41 @@ in { }; }; + workhorse.config = mkOption { + type = toml.type; + default = {}; + example = literalExpression '' + { + object_storage.provider = "AWS"; + object_storage.s3 = { + aws_access_key_id = "AKIAXXXXXXXXXXXXXXXX"; + aws_secret_access_key = { _secret = "/var/keys/aws_secret_access_key"; }; + }; + }; + ''; + description = lib.mdDoc '' + Configuration options to add to Workhorse's configuration + file. + + See + <https://gitlab.com/gitlab-org/gitlab/-/blob/master/workhorse/config.toml.example> + and + <https://docs.gitlab.com/ee/development/workhorse/configuration.html> + for examples and option documentation. + + Options containing secret data should be set to an attribute + set containing the attribute `_secret` - a string pointing + to a file containing the value the option should be set + to. See the example to get a better picture of this: in the + resulting configuration file, the + `object_storage.s3.aws_secret_access_key` key will be set to + the contents of the {file}`/var/keys/aws_secret_access_key` + file. + ''; + }; + extraConfig = mkOption { - type = types.attrs; + type = yaml.type; default = {}; example = literalExpression '' { @@ -972,8 +1020,9 @@ in { # Redis is required for the sidekiq queue runner. services.redis.servers.gitlab = { enable = mkDefault true; - port = mkDefault 31636; - bind = mkDefault "127.0.0.1"; + user = mkDefault cfg.user; + unixSocket = mkDefault "/run/gitlab/redis.sock"; + unixSocketPerm = mkDefault 770; }; # We use postgres as the main data store. @@ -1062,6 +1111,7 @@ in { # Ensure Docker Registry launches after the certificate generation job systemd.services.docker-registry = optionalAttrs cfg.registry.enable { wants = [ "gitlab-registry-cert.service" ]; + after = [ "gitlab-registry-cert.service" ]; }; # Enable Docker Registry, if GitLab-Container Registry is enabled @@ -1115,6 +1165,7 @@ in { "d ${gitlabConfig.production.shared.path}/lfs-objects 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/packages 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/pages 0750 ${cfg.user} ${cfg.group} -" + "d ${gitlabConfig.production.shared.path}/registry 0750 ${cfg.user} ${cfg.group} -" "d ${gitlabConfig.production.shared.path}/terraform_state 0750 ${cfg.user} ${cfg.group} -" "L+ /run/gitlab/config - - - - ${cfg.statePath}/config" "L+ /run/gitlab/log - - - - ${cfg.statePath}/log" @@ -1168,6 +1219,7 @@ in { cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config cp -rf --no-preserve=mode ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db ln -sf ${extraGitlabRb} ${cfg.statePath}/config/initializers/extra-gitlab.rb + ln -sf ${cableYml} ${cfg.statePath}/config/cable.yml ${cfg.packages.gitlab-shell}/bin/install @@ -1357,6 +1409,7 @@ in { wantedBy = [ "gitlab.target" ]; partOf = [ "gitlab.target" ]; path = with pkgs; [ + remarshal exiftool gitPackage gnutar @@ -1371,6 +1424,17 @@ in { TimeoutSec = "infinity"; Restart = "on-failure"; WorkingDirectory = gitlabEnv.HOME; + ExecStartPre = pkgs.writeShellScript "gitlab-workhorse-pre-start" '' + set -o errexit -o pipefail -o nounset + shopt -s dotglob nullglob inherit_errexit + + ${utils.genJqSecretsReplacementSnippet + cfg.workhorse.config + "${cfg.statePath}/config/gitlab-workhorse.json"} + + json2toml "${cfg.statePath}/config/gitlab-workhorse.json" "${cfg.statePath}/config/gitlab-workhorse.toml" + rm "${cfg.statePath}/config/gitlab-workhorse.json" + ''; ExecStart = "${cfg.packages.gitlab-workhorse}/bin/workhorse " + "-listenUmask 0 " @@ -1378,6 +1442,7 @@ in { + "-listenAddr /run/gitlab/gitlab-workhorse.socket " + "-authSocket ${gitlabSocket} " + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public " + + "-config ${cfg.statePath}/config/gitlab-workhorse.toml " + "-secretPath ${cfg.statePath}/.gitlab_workhorse_secret"; }; }; diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix index 88b9ac4a0a3..012abda2d76 100644 --- a/nixos/modules/services/misc/gitolite.nix +++ b/nixos/modules/services/misc/gitolite.nix @@ -101,6 +101,14 @@ in ''; }; + description = mkOption { + type = types.str; + default = "Gitolite user"; + description = lib.mdDoc '' + Gitolite user account's description. + ''; + }; + group = mkOption { type = types.str; default = "gitolite"; @@ -145,7 +153,7 @@ in ''; users.users.${cfg.user} = { - description = "Gitolite user"; + description = cfg.description; home = cfg.dataDir; uid = config.ids.uids.gitolite; group = cfg.group; diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix index 4d83d2d48e3..2f34a72377c 100644 --- a/nixos/modules/services/networking/coturn.nix +++ b/nixos/modules/services/networking/coturn.nix @@ -335,9 +335,10 @@ in { preStart = '' cat ${configFile} > ${runConfig} ${optionalString (cfg.static-auth-secret-file != null) '' - STATIC_AUTH_SECRET="$(head -n1 ${cfg.static-auth-secret-file} || :)" - sed -e "s,#static-auth-secret#,$STATIC_AUTH_SECRET,g" \ - -i ${runConfig} + ${pkgs.replace-secret}/bin/replace-secret \ + "#static-auth-secret#" \ + ${cfg.static-auth-secret-file} \ + ${runConfig} '' } chmod 640 ${runConfig} ''; diff --git a/nixos/modules/services/networking/firefox-syncserver.nix b/nixos/modules/services/networking/firefox-syncserver.nix index fa8e4fcaed2..d7d5df59a4e 100644 --- a/nixos/modules/services/networking/firefox-syncserver.nix +++ b/nixos/modules/services/networking/firefox-syncserver.nix @@ -19,6 +19,9 @@ let fxa_email_domain = "api.accounts.firefox.com"; fxa_oauth_server_url = "https://oauth.accounts.firefox.com/v1"; run_migrations = true; + # if JWK caching is not enabled the token server must verify tokens + # using the fxa api, on a thread pool with a static size. + additional_blocking_threads_for_fxa_requests = 10; } // lib.optionalAttrs cfg.singleNode.enable { # Single-node mode is likely to be used on small instances with little # capacity. The default value (0.1) can only ever release capacity when @@ -309,11 +312,7 @@ in enableACME = cfg.singleNode.enableTLS; forceSSL = cfg.singleNode.enableTLS; locations."/" = { - proxyPass = "http://localhost:${toString cfg.settings.port}"; - # source mentions that this header should be set - extraConfig = '' - add_header X-Content-Type-Options nosniff; - ''; + proxyPass = "http://127.0.0.1:${toString cfg.settings.port}"; }; }; }; diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix index 526e6ab0a7a..a9908b01a58 100644 --- a/nixos/modules/services/networking/iwd.nix +++ b/nixos/modules/services/networking/iwd.nix @@ -67,5 +67,5 @@ in }; }; - meta.maintainers = with lib.maintainers; [ mic92 dtzWill ]; + meta.maintainers = with lib.maintainers; [ dtzWill ]; } diff --git a/nixos/modules/services/networking/jitsi-videobridge.nix b/nixos/modules/services/networking/jitsi-videobridge.nix index 4455b7bcee4..eefaa70604c 100644 --- a/nixos/modules/services/networking/jitsi-videobridge.nix +++ b/nixos/modules/services/networking/jitsi-videobridge.nix @@ -70,7 +70,7 @@ in description = lib.mdDoc '' Videobridge configuration. - See <https://github.com/jitsi/jitsi-videobridge/blob/master/src/main/resources/reference.conf> + See <https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf> for default configuration with comments. ''; }; diff --git a/nixos/modules/services/networking/knot.nix b/nixos/modules/services/networking/knot.nix index de238112826..ee7ea83456d 100644 --- a/nixos/modules/services/networking/knot.nix +++ b/nixos/modules/services/networking/knot.nix @@ -18,7 +18,7 @@ let knot-cli-wrappers = pkgs.stdenv.mkDerivation { name = "knot-cli-wrappers"; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; buildCommand = '' mkdir -p $out/bin makeWrapper ${cfg.package}/bin/knotc "$out/bin/knotc" \ diff --git a/nixos/modules/services/networking/mullvad-vpn.nix b/nixos/modules/services/networking/mullvad-vpn.nix index ca60682b4b8..42d55056084 100644 --- a/nixos/modules/services/networking/mullvad-vpn.nix +++ b/nixos/modules/services/networking/mullvad-vpn.nix @@ -39,7 +39,7 @@ with lib; startLimitBurst = 5; startLimitIntervalSec = 20; serviceConfig = { - ExecStart = "${pkgs.mullvad-vpn}/bin/mullvad-daemon -v --disable-stdout-timestamps"; + ExecStart = "${pkgs.mullvad}/bin/mullvad-daemon -v --disable-stdout-timestamps"; Restart = "always"; RestartSec = 1; }; diff --git a/nixos/modules/services/networking/pptpd.nix b/nixos/modules/services/networking/pptpd.nix index 2f206e813a5..703dda99803 100644 --- a/nixos/modules/services/networking/pptpd.nix +++ b/nixos/modules/services/networking/pptpd.nix @@ -82,7 +82,7 @@ with lib; ppp-pptpd-wrapped = pkgs.stdenv.mkDerivation { name = "ppp-pptpd-wrapped"; phases = [ "installPhase" ]; - buildInputs = with pkgs; [ makeWrapper ]; + nativeBuildInputs = with pkgs; [ makeWrapper ]; installPhase = '' mkdir -p $out/bin makeWrapper ${pkgs.ppp}/bin/pppd $out/bin/pppd \ diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix index 1f93d82f96e..09b23a60a4a 100644 --- a/nixos/modules/services/networking/tinc.nix +++ b/nixos/modules/services/networking/tinc.nix @@ -410,7 +410,7 @@ in environment.systemPackages = let cli-wrappers = pkgs.stdenv.mkDerivation { name = "tinc-cli-wrappers"; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; buildCommand = '' mkdir -p $out/bin ${concatStringsSep "\n" (mapAttrsToList (network: data: diff --git a/nixos/modules/services/networking/tmate-ssh-server.nix b/nixos/modules/services/networking/tmate-ssh-server.nix new file mode 100644 index 00000000000..1b8f6662ef4 --- /dev/null +++ b/nixos/modules/services/networking/tmate-ssh-server.nix @@ -0,0 +1,122 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.tmate-ssh-server; + + defaultKeysDir = "/etc/tmate-ssh-server-keys"; + edKey = "${defaultKeysDir}/ssh_host_ed25519_key"; + rsaKey = "${defaultKeysDir}/ssh_host_rsa_key"; + + keysDir = + if cfg.keysDir == null + then defaultKeysDir + else cfg.keysDir; + + domain = config.networking.domain; +in +{ + options.services.tmate-ssh-server = { + enable = mkEnableOption (mdDoc "tmate ssh server"); + + package = mkOption { + type = types.package; + description = mdDoc "The package containing tmate-ssh-server"; + defaultText = literalExpression "pkgs.tmate-ssh-server"; + default = pkgs.tmate-ssh-server; + }; + + host = mkOption { + type = types.str; + description = mdDoc "External host name"; + defaultText = lib.literalExpression "config.networking.domain or config.networking.hostName "; + default = + if domain == null then + config.networking.hostName + else + domain; + }; + + port = mkOption { + type = types.port; + description = mdDoc "Listen port for the ssh server"; + default = 2222; + }; + + openFirewall = mkOption { + type = types.bool; + default = true; + description = mdDoc "Whether to automatically open the specified ports in the firewall."; + }; + + advertisedPort = mkOption { + type = types.port; + description = mdDoc "External port advertised to clients"; + }; + + keysDir = mkOption { + type = with types; nullOr str; + description = mdDoc "Directory containing ssh keys, defaulting to auto-generation"; + default = null; + }; + }; + + config = mkIf cfg.enable { + + networking.firewall.allowedTCPPorts = optionals cfg.openFirewall [ cfg.port ]; + + services.tmate-ssh-server = { + advertisedPort = mkDefault cfg.port; + }; + + environment.systemPackages = + let + tmate-config = pkgs.writeText "tmate.conf" + '' + set -g tmate-server-host "${cfg.host}" + set -g tmate-server-port ${toString cfg.port} + set -g tmate-server-ed25519-fingerprint "@ed25519_fingerprint@" + set -g tmate-server-rsa-fingerprint "@rsa_fingerprint@" + ''; + in + [ + (pkgs.writeShellApplication { + name = "tmate-client-config"; + runtimeInputs = with pkgs;[ openssh coreutils sd ]; + text = '' + RSA_SIG="$(ssh-keygen -l -E SHA256 -f "${keysDir}/ssh_host_rsa_key.pub" | cut -d ' ' -f 2)" + ED25519_SIG="$(ssh-keygen -l -E SHA256 -f "${keysDir}/ssh_host_ed25519_key.pub" | cut -d ' ' -f 2)" + sd -sp '@ed25519_fingerprint@' "$ED25519_SIG" ${tmate-config} | \ + sd -sp '@rsa_fingerprint@' "$RSA_SIG" + ''; + }) + ]; + + systemd.services.tmate-ssh-server = { + description = "tmate SSH Server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${cfg.package}/bin/tmate-ssh-server -h ${cfg.host} -p ${toString cfg.port} -q ${toString cfg.advertisedPort} -k ${keysDir}"; + }; + preStart = mkIf (cfg.keysDir == null) '' + if [[ ! -d ${defaultKeysDir} ]] + then + mkdir -p ${defaultKeysDir} + fi + if [[ ! -f ${edKey} ]] + then + ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f ${edKey} -N "" + fi + if [[ ! -f ${rsaKey} ]] + then + ${pkgs.openssh}/bin/ssh-keygen -t rsa -f ${rsaKey} -N "" + fi + ''; + }; + }; + + meta = { + maintainers = with maintainers; [ jlesquembre ]; + }; + +} diff --git a/nixos/modules/services/networking/xl2tpd.nix b/nixos/modules/services/networking/xl2tpd.nix index 8f710bca322..7d259570761 100644 --- a/nixos/modules/services/networking/xl2tpd.nix +++ b/nixos/modules/services/networking/xl2tpd.nix @@ -84,7 +84,7 @@ with lib; xl2tpd-ppp-wrapped = pkgs.stdenv.mkDerivation { name = "xl2tpd-ppp-wrapped"; phases = [ "installPhase" ]; - buildInputs = with pkgs; [ makeWrapper ]; + nativeBuildInputs = with pkgs; [ makeWrapper ]; installPhase = '' mkdir -p $out/bin diff --git a/nixos/modules/services/security/endlessh-go.nix b/nixos/modules/services/security/endlessh-go.nix new file mode 100644 index 00000000000..61cca553173 --- /dev/null +++ b/nixos/modules/services/security/endlessh-go.nix @@ -0,0 +1,138 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.endlessh-go; +in +{ + options.services.endlessh-go = { + enable = mkEnableOption (mdDoc "endlessh-go service"); + + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0"; + example = "[::]"; + description = mdDoc '' + Interface address to bind the endlessh-go daemon to SSH connections. + ''; + }; + + port = mkOption { + type = types.port; + default = 2222; + example = 22; + description = mdDoc '' + Specifies on which port the endlessh-go daemon listens for SSH + connections. + + Setting this to `22` may conflict with {option}`services.openssh`. + ''; + }; + + prometheus = { + enable = mkEnableOption (mdDoc "Prometheus integration"); + + listenAddress = mkOption { + type = types.str; + default = "0.0.0.0"; + example = "[::]"; + description = mdDoc '' + Interface address to bind the endlessh-go daemon to answer Prometheus + queries. + ''; + }; + + port = mkOption { + type = types.port; + default = 2112; + example = 9119; + description = mdDoc '' + Specifies on which port the endlessh-go daemon listens for Prometheus + queries. + ''; + }; + }; + + extraOptions = mkOption { + type = with types; listOf str; + default = [ ]; + example = [ "-conn_type=tcp4" "-max_clients=8192" ]; + description = mdDoc '' + Additional command line options to pass to the endlessh-go daemon. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether to open a firewall port for the SSH listener. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.endlessh-go = { + description = "SSH tarpit"; + requires = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = + let + needsPrivileges = cfg.port < 1024 || cfg.prometheus.port < 1024; + capabilities = [ "" ] ++ optionals needsPrivileges [ "CAP_NET_BIND_SERVICE" ]; + rootDirectory = "/run/endlessh-go"; + in + { + Restart = "always"; + ExecStart = with cfg; concatStringsSep " " ([ + "${pkgs.endlessh-go}/bin/endlessh-go" + "-logtostderr" + "-host=${listenAddress}" + "-port=${toString port}" + ] ++ optionals prometheus.enable [ + "-enable_prometheus" + "-prometheus_host=${prometheus.listenAddress}" + "-prometheus_port=${toString prometheus.port}" + ] ++ extraOptions); + DynamicUser = true; + RootDirectory = rootDirectory; + BindReadOnlyPaths = [ builtins.storeDir ]; + InaccessiblePaths = [ "-+${rootDirectory}" ]; + RuntimeDirectory = baseNameOf rootDirectory; + RuntimeDirectoryMode = "700"; + AmbientCapabilities = capabilities; + CapabilityBoundingSet = capabilities; + UMask = "0077"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = !needsPrivileges; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ProtectProc = "noaccess"; + ProcSubset = "pid"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ]; + }; + }; + + networking.firewall.allowedTCPPorts = with cfg; + optionals openFirewall [ port prometheus.port ]; + }; + + meta.maintainers = with maintainers; [ azahi ]; +} diff --git a/nixos/modules/services/security/privacyidea.nix b/nixos/modules/services/security/privacyidea.nix index 5cd338ebf7f..e446e606cad 100644 --- a/nixos/modules/services/security/privacyidea.nix +++ b/nixos/modules/services/security/privacyidea.nix @@ -61,6 +61,12 @@ let (flip mapAttrs cfg.ldap-proxy.settings (const (mapAttrs (const renderValue))))); + privacyidea-token-janitor = pkgs.writeShellScriptBin "privacyidea-token-janitor" '' + exec -a privacyidea-token-janitor \ + /run/wrappers/bin/sudo -u ${cfg.user} \ + env PRIVACYIDEA_CONFIGFILE=${cfg.stateDir}/privacyidea.cfg \ + ${penv}/bin/privacyidea-token-janitor $@ + ''; in { @@ -178,6 +184,42 @@ in description = lib.mdDoc "Group account under which PrivacyIDEA runs."; }; + tokenjanitor = { + enable = mkEnableOption (lib.mdDoc "automatic runs of the token janitor"); + interval = mkOption { + default = "quarterly"; + type = types.str; + description = lib.mdDoc '' + Interval in which the cleanup program is supposed to run. + See {manpage}`systemd.time(7)` for further information. + ''; + }; + action = mkOption { + type = types.enum [ "delete" "mark" "disable" "unassign" ]; + description = lib.mdDoc '' + Which action to take for matching tokens. + ''; + }; + unassigned = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + Whether to search for **unassigned** tokens + and apply [](#opt-services.privacyidea.tokenjanitor.action) + onto them. + ''; + }; + orphaned = mkOption { + default = true; + type = types.bool; + description = lib.mdDoc '' + Whether to search for **orphaned** tokens + and apply [](#opt-services.privacyidea.tokenjanitor.action) + onto them. + ''; + }; + }; + ldap-proxy = { enable = mkEnableOption (lib.mdDoc "PrivacyIDEA LDAP Proxy"); @@ -228,10 +270,60 @@ in (mkIf cfg.enable { - environment.systemPackages = [ pkgs.privacyidea ]; + assertions = [ + { + assertion = cfg.tokenjanitor.enable -> (cfg.tokenjanitor.orphaned || cfg.tokenjanitor.unassigned); + message = '' + privacyidea-token-janitor has no effect if neither orphaned nor unassigned tokens + are to be searched. + ''; + } + ]; + + environment.systemPackages = [ pkgs.privacyidea (hiPrio privacyidea-token-janitor) ]; services.postgresql.enable = mkDefault true; + systemd.services.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable { + environment.PRIVACYIDEA_CONFIGFILE = "${cfg.stateDir}/privacyidea.cfg"; + path = [ penv ]; + serviceConfig = { + CapabilityBoundingSet = [ "" ]; + ExecStart = "${pkgs.writeShellScript "pi-token-janitor" '' + ${optionalString cfg.tokenjanitor.orphaned '' + echo >&2 "Removing orphaned tokens..." + privacyidea-token-janitor find \ + --orphaned true \ + --action ${cfg.tokenjanitor.action} + ''} + ${optionalString cfg.tokenjanitor.unassigned '' + echo >&2 "Removing unassigned tokens..." + privacyidea-token-janitor find \ + --assigned false \ + --action ${cfg.tokenjanitor.action} + ''} + ''}"; + Group = cfg.group; + LockPersonality = true; + MemoryDenyWriteExecute = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + ReadWritePaths = cfg.stateDir; + Type = "oneshot"; + User = cfg.user; + WorkingDirectory = cfg.stateDir; + }; + }; + systemd.timers.privacyidea-tokenjanitor = mkIf cfg.tokenjanitor.enable { + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = cfg.tokenjanitor.interval; + timerConfig.Persistent = true; + }; + systemd.services.privacyidea = let piuwsgi = pkgs.writeText "uwsgi.json" (builtins.toJSON { uwsgi = { diff --git a/nixos/modules/services/web-apps/mediawiki.nix b/nixos/modules/services/web-apps/mediawiki.nix index a32db718848..e332847f5a2 100644 --- a/nixos/modules/services/web-apps/mediawiki.nix +++ b/nixos/modules/services/web-apps/mediawiki.nix @@ -35,7 +35,7 @@ let }; mediawikiScripts = pkgs.runCommand "mediawiki-scripts" { - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; preferLocalBuild = true; } '' mkdir -p $out/bin diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index e843214f855..03f94c426cb 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -372,6 +372,8 @@ in { "/etc/os-release".source = config.boot.initrd.osRelease; "/etc/initrd-release".source = config.boot.initrd.osRelease; + } // optionalAttrs (config.environment.etc ? "modprobe.d/nixos.conf") { + "/etc/modprobe.d/nixos.conf".source = config.environment.etc."modprobe.d/nixos.conf".source; }; storePaths = [ diff --git a/nixos/modules/tasks/filesystems/jfs.nix b/nixos/modules/tasks/filesystems/jfs.nix index 700f05af2be..6d80c4c657d 100644 --- a/nixos/modules/tasks/filesystems/jfs.nix +++ b/nixos/modules/tasks/filesystems/jfs.nix @@ -12,7 +12,7 @@ in boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ]; - boot.initrd.extraUtilsCommands = mkIf (inInitrd && !boot.initrd.systemd.enable) '' + boot.initrd.extraUtilsCommands = mkIf (inInitrd && !config.boot.initrd.systemd.enable) '' copy_bin_and_libs ${pkgs.jfsutils}/sbin/fsck.jfs ''; }; diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix index 31047c4ddc0..abe6455a1a6 100644 --- a/nixos/modules/virtualisation/azure-agent.nix +++ b/nixos/modules/virtualisation/azure-agent.nix @@ -17,7 +17,7 @@ let patches = [ ./azure-agent-entropy.patch ]; - buildInputs = [ makeWrapper python pythonPackages.wrapPython ]; + nativeBuildInputs = [ makeWrapper python pythonPackages.wrapPython ]; runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh nettools # for hostname procps # for pidof diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix index 5a2ec4939d9..b1565a09682 100644 --- a/nixos/modules/virtualisation/virtualbox-host.nix +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -104,16 +104,18 @@ in group = "vboxusers"; setuid = true; }; + executables = [ + "VBoxHeadless" + "VBoxNetAdpCtl" + "VBoxNetDHCP" + "VBoxNetNAT" + "VBoxVolInfo" + ] ++ (lib.optionals (!cfg.headless) [ + "VBoxSDL" + "VirtualBoxVM" + ]); in mkIf cfg.enableHardening - (builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) [ - "VBoxHeadless" - "VBoxNetAdpCtl" - "VBoxNetDHCP" - "VBoxNetNAT" - "VBoxSDL" - "VBoxVolInfo" - "VirtualBoxVM" - ])); + (builtins.listToAttrs (map (x: { name = x; value = mkSuid x; }) executables)); users.groups.vboxusers.gid = config.ids.gids.vboxusers; diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index e8677f7e1e9..a11ee31ab8d 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -4,8 +4,8 @@ { nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; } , stableBranch ? false -, supportedSystems ? [ "x86_64-linux" ] -, limitedSupportedSystems ? [ "i686-linux" "aarch64-linux" ] +, supportedSystems ? [ "aarch64-linux" "x86_64-linux" ] +, limitedSupportedSystems ? [ "i686-linux" ] }: let @@ -50,17 +50,17 @@ in rec { (onFullSupported "nixos.dummy") (onAllSupported "nixos.iso_minimal") (onSystems ["x86_64-linux" "aarch64-linux"] "nixos.amazonImage") - (onSystems ["x86_64-linux"] "nixos.iso_plasma5") - (onSystems ["x86_64-linux"] "nixos.iso_gnome") + (onFullSupported "nixos.iso_plasma5") + (onFullSupported "nixos.iso_gnome") (onFullSupported "nixos.manual") (onSystems ["x86_64-linux"] "nixos.ova") (onSystems ["aarch64-linux"] "nixos.sd_image") (onSystems ["x86_64-linux"] "nixos.tests.boot.biosCdrom") (onSystems ["x86_64-linux"] "nixos.tests.boot.biosUsb") (onFullSupported "nixos.tests.boot-stage1") - (onSystems ["x86_64-linux"] "nixos.tests.boot.uefiCdrom") - (onSystems ["x86_64-linux"] "nixos.tests.boot.uefiUsb") - (onSystems ["x86_64-linux"] "nixos.tests.chromium") + (onFullSupported "nixos.tests.boot.uefiCdrom") + (onFullSupported "nixos.tests.boot.uefiUsb") + (onFullSupported "nixos.tests.chromium") (onFullSupported "nixos.tests.containers-imperative") (onFullSupported "nixos.tests.containers-ip") (onSystems ["x86_64-linux"] "nixos.tests.docker") diff --git a/nixos/release-small.nix b/nixos/release-small.nix index 8367610fb7f..1719d6738c5 100644 --- a/nixos/release-small.nix +++ b/nixos/release-small.nix @@ -4,7 +4,7 @@ { nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; } , stableBranch ? false -, supportedSystems ? [ "x86_64-linux" ] # no i686-linux +, supportedSystems ? [ "aarch64-linux" "x86_64-linux" ] # no i686-linux }: let @@ -53,7 +53,8 @@ in rec { }; boot = { inherit (nixos'.tests.boot) - biosCdrom; + biosCdrom + uefiCdrom; }; }; }; @@ -83,45 +84,56 @@ in rec { vim; }; - tested = pkgs.releaseTools.aggregate { + tested = let + onSupported = x: map (system: "${x}.${system}") supportedSystems; + onSystems = systems: x: map (system: "${x}.${system}") + (pkgs.lib.intersectLists systems supportedSystems); + in pkgs.releaseTools.aggregate { name = "nixos-${nixos.channel.version}"; meta = { description = "Release-critical builds for the NixOS channel"; maintainers = [ lib.maintainers.eelco ]; }; - constituents = - [ "nixos.channel" - "nixos.dummy.x86_64-linux" - "nixos.iso_minimal.x86_64-linux" - "nixos.amazonImage.x86_64-linux" - "nixos.manual.x86_64-linux" - "nixos.tests.boot.biosCdrom.x86_64-linux" - "nixos.tests.containers-imperative.x86_64-linux" - "nixos.tests.containers-ip.x86_64-linux" - "nixos.tests.firewall.x86_64-linux" - "nixos.tests.installer.lvm.x86_64-linux" - "nixos.tests.installer.separateBoot.x86_64-linux" - "nixos.tests.installer.simple.x86_64-linux" - "nixos.tests.ipv6.x86_64-linux" - "nixos.tests.login.x86_64-linux" - "nixos.tests.misc.x86_64-linux" - "nixos.tests.nat.firewall-conntrack.x86_64-linux" - "nixos.tests.nat.firewall.x86_64-linux" - "nixos.tests.nat.standalone.x86_64-linux" - # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314 - #"nixos.tests.nfs3.simple.x86_64-linux" - "nixos.tests.openssh.x86_64-linux" - "nixos.tests.php.fpm.x86_64-linux" - "nixos.tests.php.pcre.x86_64-linux" - "nixos.tests.predictable-interface-names.predictable.x86_64-linux" - "nixos.tests.predictable-interface-names.predictableNetworkd.x86_64-linux" - "nixos.tests.predictable-interface-names.unpredictable.x86_64-linux" - "nixos.tests.predictable-interface-names.unpredictableNetworkd.x86_64-linux" - "nixos.tests.proxy.x86_64-linux" - "nixos.tests.simple.x86_64-linux" - "nixpkgs.jdk.x86_64-linux" + constituents = lib.flatten [ + [ + "nixos.channel" "nixpkgs.tarball" - ]; + ] + (map (onSystems [ "x86_64-linux" ]) [ + "nixos.tests.boot.biosCdrom" + "nixos.tests.installer.lvm" + "nixos.tests.installer.separateBoot" + "nixos.tests.installer.simple" + ]) + (map onSupported [ + "nixos.dummy" + "nixos.iso_minimal" + "nixos.amazonImage" + "nixos.manual" + "nixos.tests.boot.uefiCdrom" + "nixos.tests.containers-imperative" + "nixos.tests.containers-ip" + "nixos.tests.firewall" + "nixos.tests.ipv6" + "nixos.tests.login" + "nixos.tests.misc" + "nixos.tests.nat.firewall-conntrack" + "nixos.tests.nat.firewall" + "nixos.tests.nat.standalone" + # fails with kernel >= 5.15 https://github.com/NixOS/nixpkgs/pull/152505#issuecomment-1005049314 + #"nixos.tests.nfs3.simple" + "nixos.tests.openssh" + "nixos.tests.php.fpm" + "nixos.tests.php.pcre" + "nixos.tests.predictable-interface-names.predictable" + "nixos.tests.predictable-interface-names.predictableNetworkd" + "nixos.tests.predictable-interface-names.unpredictable" + "nixos.tests.predictable-interface-names.unpredictableNetworkd" + "nixos.tests.proxy" + "nixos.tests.simple" + "nixpkgs.jdk" + ]) + ]; }; } diff --git a/nixos/release.nix b/nixos/release.nix index 4f27e5dbb21..919aa86a2d6 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -169,13 +169,13 @@ in rec { inherit system; }); - iso_plasma5 = forMatchingSystems [ "x86_64-linux" ] (system: makeIso { + iso_plasma5 = forMatchingSystems supportedSystems (system: makeIso { module = ./modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix; type = "plasma5"; inherit system; }); - iso_gnome = forMatchingSystems [ "x86_64-linux" ] (system: makeIso { + iso_gnome = forMatchingSystems supportedSystems (system: makeIso { module = ./modules/installer/cd-dvd/installation-cd-graphical-calamares-gnome.nix; type = "gnome"; inherit system; diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index d3a436080eb..d540bc6ec31 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -41,6 +41,16 @@ inherit documentRoot; }; + simpleConfig = { + security.acme = { + certs."http.example.test" = { + listenHTTP = ":80"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 ]; + }; + # Base specialisation config for testing general ACME features webserverBasicConfig = { services.nginx.enable = true; @@ -173,6 +183,26 @@ in { services.nginx.logError = "stderr info"; specialisation = { + # Tests HTTP-01 verification using Lego's built-in web server + http01lego.configuration = simpleConfig; + + renew.configuration = lib.mkMerge [ + simpleConfig + { + # Pebble provides 5 year long certs, + # needs to be higher than that to test renewal + security.acme.certs."http.example.test".validMinDays = 9999; + } + ]; + + # Tests that account creds can be safely changed. + accountchange.configuration = lib.mkMerge [ + simpleConfig + { + security.acme.certs."http.example.test".email = "admin@example.test"; + } + ]; + # First derivation used to test general ACME features general.configuration = { ... }: let caDomain = nodes.acme.test-support.acme.caDomain; @@ -446,7 +476,35 @@ in { download_ca_certs(client) - # Perform general tests first + # Perform http-01 w/ lego test first + with subtest("Can request certificate with Lego's built in web server"): + switch_to(webserver, "http01lego") + webserver.wait_for_unit("acme-finished-http.example.test.target") + check_fullchain(webserver, "http.example.test") + check_issuer(webserver, "http.example.test", "pebble") + + # Perform renewal test + with subtest("Can renew certificates when they expire"): + hash = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem") + switch_to(webserver, "renew") + webserver.wait_for_unit("acme-finished-http.example.test.target") + check_fullchain(webserver, "http.example.test") + check_issuer(webserver, "http.example.test", "pebble") + hash_after = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem") + assert hash != hash_after + + # Perform account change test + with subtest("Handles email change correctly"): + hash = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem") + switch_to(webserver, "accountchange") + webserver.wait_for_unit("acme-finished-http.example.test.target") + check_fullchain(webserver, "http.example.test") + check_issuer(webserver, "http.example.test", "pebble") + hash_after = webserver.succeed("sha256sum /var/lib/acme/http.example.test/cert.pem") + # Has to do a full run to register account, which creates new certs. + assert hash != hash_after + + # Perform general tests switch_to(webserver, "general") with subtest("Can request certificate with HTTP-01 challenge"): diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 8ec73cc05c8..3b697139dc8 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -119,7 +119,7 @@ in { certmgr = handleTest ./certmgr.nix {}; cfssl = handleTestOn ["x86_64-linux"] ./cfssl.nix {}; charliecloud = handleTest ./charliecloud.nix {}; - chromium = (handleTestOn ["x86_64-linux"] ./chromium.nix {}).stable or {}; + chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {}; cinnamon = handleTest ./cinnamon.nix {}; cjdns = handleTest ./cjdns.nix {}; clickhouse = handleTest ./clickhouse.nix {}; @@ -180,6 +180,7 @@ in { ejabberd = handleTest ./xmpp/ejabberd.nix {}; elk = handleTestOn ["x86_64-linux"] ./elk.nix {}; emacs-daemon = handleTest ./emacs-daemon.nix {}; + endlessh-go = handleTest ./endlessh-go.nix {}; engelsystem = handleTest ./engelsystem.nix {}; enlightenment = handleTest ./enlightenment.nix {}; env = handleTest ./env.nix {}; @@ -597,6 +598,7 @@ in { systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {}; systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {}; systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {}; + systemd-initrd-modprobe = handleTest ./systemd-initrd-modprobe.nix {}; systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; }; systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {}; systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {}; @@ -625,12 +627,15 @@ in { tinc = handleTest ./tinc {}; tinydns = handleTest ./tinydns.nix {}; tinywl = handleTest ./tinywl.nix {}; + tmate-ssh-server = handleTest ./tmate-ssh-server.nix { }; tomcat = handleTest ./tomcat.nix {}; tor = handleTest ./tor.nix {}; # traefik test relies on docker-containers traefik = handleTestOn ["x86_64-linux"] ./traefik.nix {}; trafficserver = handleTest ./trafficserver.nix {}; transmission = handleTest ./transmission.nix {}; + # tracee requires bpf + tracee = handleTestOn ["x86_64-linux"] ./tracee.nix {}; trezord = handleTest ./trezord.nix {}; trickster = handleTest ./trickster.nix {}; trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {}; diff --git a/nixos/tests/endlessh-go.nix b/nixos/tests/endlessh-go.nix new file mode 100644 index 00000000000..b261dbf1c56 --- /dev/null +++ b/nixos/tests/endlessh-go.nix @@ -0,0 +1,58 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: +{ + name = "endlessh-go"; + meta.maintainers = with lib.maintainers; [ azahi ]; + + nodes = { + server = { ... }: { + services.endlessh-go = { + enable = true; + prometheus.enable = true; + openFirewall = true; + }; + + specialisation = { + unprivileged.configuration = { + services.endlessh-go = { + port = 2222; + prometheus.port = 9229; + }; + }; + + privileged.configuration = { + services.endlessh-go = { + port = 22; + prometheus.port = 92; + }; + }; + }; + }; + + client = { pkgs, ... }: { + environment.systemPackages = with pkgs; [ curl netcat ]; + }; + }; + + testScript = '' + def activate_specialisation(name: str): + server.succeed(f"/run/booted-system/specialisation/{name}/bin/switch-to-configuration test >&2") + + start_all() + + with subtest("Unprivileged"): + activate_specialisation("unprivileged") + server.wait_for_unit("endlessh-go.service") + server.wait_for_open_port(2222) + server.wait_for_open_port(9229) + client.succeed("nc -dvW5 server 2222") + client.succeed("curl -kv server:9229/metrics") + + with subtest("Privileged"): + activate_specialisation("privileged") + server.wait_for_unit("endlessh-go.service") + server.wait_for_open_port(22) + server.wait_for_open_port(92) + client.succeed("nc -dvW5 server 22") + client.succeed("curl -kv server:92/metrics") + ''; +}) diff --git a/nixos/tests/hydra/common.nix b/nixos/tests/hydra/common.nix index fdf2b2c6f6d..2bce03418e1 100644 --- a/nixos/tests/hydra/common.nix +++ b/nixos/tests/hydra/common.nix @@ -16,7 +16,7 @@ createTrivialProject = pkgs.stdenv.mkDerivation { name = "create-trivial-project"; dontUnpack = true; - buildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; installPhase = "install -m755 -D ${./create-trivial-project.sh} $out/bin/create-trivial-project.sh"; postFixup = '' wrapProgram "$out/bin/create-trivial-project.sh" --prefix PATH ":" ${pkgs.lib.makeBinPath [ pkgs.curl ]} --set EXPR_PATH ${trivialJob} diff --git a/nixos/tests/kubernetes/base.nix b/nixos/tests/kubernetes/base.nix index d4410beb937..714ac3098c0 100644 --- a/nixos/tests/kubernetes/base.nix +++ b/nixos/tests/kubernetes/base.nix @@ -18,7 +18,7 @@ let ${master.ip} api.${domain} ${concatMapStringsSep "\n" (machineName: "${machines.${machineName}.ip} ${machineName}.${domain}") (attrNames machines)} ''; - wrapKubectl = with pkgs; runCommand "wrap-kubectl" { buildInputs = [ makeWrapper ]; } '' + wrapKubectl = with pkgs; runCommand "wrap-kubectl" { nativeBuildInputs = [ makeWrapper ]; } '' mkdir -p $out/bin makeWrapper ${pkgs.kubernetes}/bin/kubectl $out/bin/kubectl --set KUBECONFIG "/etc/kubernetes/cluster-admin.kubeconfig" ''; diff --git a/nixos/tests/paperless.nix b/nixos/tests/paperless.nix index 12883cd62c6..b97834835c2 100644 --- a/nixos/tests/paperless.nix +++ b/nixos/tests/paperless.nix @@ -40,5 +40,13 @@ import ./make-test-python.nix ({ lib, ... }: { docs = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/"))['results'] assert "2005-10-16" in docs[0]['created'] assert "2005-10-16" in docs[1]['created'] + + # Detects gunicorn issues, see PR #190888 + with subtest("Document metadata can be accessed"): + metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/1/metadata/")) + assert "original_checksum" in metadata + + metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/2/metadata/")) + assert "original_checksum" in metadata ''; }) diff --git a/nixos/tests/pulseaudio.nix b/nixos/tests/pulseaudio.nix index cfdc61bc6c2..dc8e33ccd55 100644 --- a/nixos/tests/pulseaudio.nix +++ b/nixos/tests/pulseaudio.nix @@ -1,10 +1,10 @@ let - mkTest = { systemWide ? false }: + mkTest = { systemWide ? false , fullVersion ? false }: import ./make-test-python.nix ({ pkgs, lib, ... }: let testFile = pkgs.fetchurl { url = - "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"; + "https://file-examples.com/storage/fe5947fd2362fc197a3c2df/2017/11/file_example_MP3_700KB.mp3"; hash = "sha256-+iggJW8s0/LfA/okfXsB550/55Q0Sq3OoIzuBrzOPJQ="; }; @@ -22,7 +22,7 @@ let testPlay32 = { inherit (pkgs.pkgsi686Linux) sox alsa-utils; }; }; in { - name = "pulseaudio${lib.optionalString systemWide "-systemWide"}"; + name = "pulseaudio${lib.optionalString fullVersion "Full"}${lib.optionalString systemWide "-systemWide"}"; meta = with pkgs.lib.maintainers; { maintainers = [ synthetica ] ++ pkgs.pulseaudio.meta.maintainers; }; @@ -35,12 +35,14 @@ let enable = true; support32Bit = true; inherit systemWide; + } // lib.optionalAttrs fullVersion { + package = pkgs.pulseaudioFull; }; environment.systemPackages = [ testers.testPlay pkgs.pavucontrol ] ++ lib.optional pkgs.stdenv.isx86_64 testers.testPlay32; } // lib.optionalAttrs systemWide { - users.users.alice.extraGroups = [ "audio" ]; + users.users.alice.extraGroups = [ "pulse-access" ]; systemd.services.pulseaudio.wantedBy = [ "multi-user.target" ]; }; @@ -58,14 +60,21 @@ let ''} machine.screenshot("testPlay") + ${lib.optionalString (!systemWide) '' + machine.send_chars("pacmd info && touch /tmp/pacmd_success\n") + machine.wait_for_file("/tmp/pacmd_success") + ''} + # Pavucontrol only loads when Pulseaudio is running. If it isn't, the - # text "Playback" (one of the tabs) will never show. + # text "Dummy Output" (sound device name) will never show. machine.send_chars("pavucontrol\n") - machine.wait_for_text("Playback") + machine.wait_for_text("Dummy Output") machine.screenshot("Pavucontrol") ''; }); in builtins.mapAttrs (key: val: mkTest val) { - user = { systemWide = false; }; - system = { systemWide = true; }; + user = { systemWide = false; fullVersion = false; }; + system = { systemWide = true; fullVersion = false; }; + userFull = { systemWide = false; fullVersion = true; }; + systemFull = { systemWide = true; fullVersion = true; }; } diff --git a/nixos/tests/retroarch.nix b/nixos/tests/retroarch.nix index c506ed02da8..f4bf232ea72 100644 --- a/nixos/tests/retroarch.nix +++ b/nixos/tests/retroarch.nix @@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { name = "retroarch"; - meta = with pkgs.lib.maintainers; { maintainers = [ j0hax ]; }; + meta = with pkgs.lib; { maintainers = teams.libretro.members ++ [ maintainers.j0hax ]; }; nodes.machine = { ... }: @@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, ... }: services.xserver.enable = true; services.xserver.desktopManager.retroarch = { enable = true; - package = pkgs.retroarchFull; + package = pkgs.retroarchBare; }; services.xserver.displayManager = { sddm.enable = true; diff --git a/nixos/tests/seafile.nix b/nixos/tests/seafile.nix index 6eec8b1fbe5..78e735f4fed 100644 --- a/nixos/tests/seafile.nix +++ b/nixos/tests/seafile.nix @@ -79,18 +79,14 @@ import ./make-test-python.nix ({ pkgs, ... }: f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2" ) - client1.sleep(3) - - client1.succeed("seaf-cli status |grep synchronized >&2") + client1.wait_until_succeeds("seaf-cli status |grep synchronized >&2") client1.succeed("ls -la >&2") client1.succeed("ls -la test01 >&2") client1.execute("echo bla > test01/first_file") - client1.sleep(2) - - client1.succeed("seaf-cli status |grep synchronized >&2") + client1.wait_until_succeeds("seaf-cli status |grep synchronized >&2") with subtest("client2 sync"): client2.wait_for_unit("default.target") @@ -110,9 +106,7 @@ import ./make-test-python.nix ({ pkgs, ... }: f"seaf-cli download -l {libid} -s http://server -u admin\@example.com -p seafile_password -d . >&2" ) - client2.sleep(3) - - client2.succeed("seaf-cli status |grep synchronized >&2") + client2.wait_until_succeeds("seaf-cli status |grep synchronized >&2") client2.succeed("ls -la test01 >&2") diff --git a/nixos/tests/spark/default.nix b/nixos/tests/spark/default.nix index 025c5a5222e..462f0d23a40 100644 --- a/nixos/tests/spark/default.nix +++ b/nixos/tests/spark/default.nix @@ -7,6 +7,7 @@ import ../make-test-python.nix ({...}: { enable = true; master = "master:7077"; }; + virtualisation.memorySize = 2048; }; master = { config, pkgs, ... }: { services.spark.master = { diff --git a/nixos/tests/sssd-ldap.nix b/nixos/tests/sssd-ldap.nix index 27dce6ceb98..ff83e96068a 100644 --- a/nixos/tests/sssd-ldap.nix +++ b/nixos/tests/sssd-ldap.nix @@ -91,6 +91,11 @@ in import ./make-test-python.nix ({pkgs, ...}: { machine.start() machine.wait_for_unit("openldap.service") machine.wait_for_unit("sssd.service") - machine.succeed("getent passwd ${testUser}") + result = machine.execute("getent passwd ${testUser}") + if result[0] == 0: + assert "${testUser}" in result[1] + else: + machine.wait_for_console_text("Backend is online") + machine.succeed("getent passwd ${testUser}") ''; }) diff --git a/nixos/tests/systemd-initrd-modprobe.nix b/nixos/tests/systemd-initrd-modprobe.nix new file mode 100644 index 00000000000..bf635a10d0e --- /dev/null +++ b/nixos/tests/systemd-initrd-modprobe.nix @@ -0,0 +1,17 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: { + name = "systemd-initrd-modprobe"; + + nodes.machine = { pkgs, ... }: { + boot.initrd.systemd.enable = true; + boot.initrd.kernelModules = [ "loop" ]; # Load module in initrd. + boot.extraModprobeConfig = '' + options loop max_loop=42 + ''; + }; + + testScript = '' + machine.wait_for_unit("multi-user.target") + max_loop = machine.succeed("cat /sys/module/loop/parameters/max_loop") + assert int(max_loop) == 42, "Parameter should be respected for initrd kernel modules" + ''; +}) diff --git a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix index 37a89fc21e4..bf5049251c7 100644 --- a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix +++ b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix @@ -7,10 +7,10 @@ # - VLAN 1 is the connection between the ISP and the router # - VLAN 2 is the connection between the router and the client -import ./make-test-python.nix ({pkgs, ...}: { +import ./make-test-python.nix ({ pkgs, lib, ... }: { name = "systemd-networkd-ipv6-prefix-delegation"; - meta = with pkgs.lib.maintainers; { - maintainers = [ andir ]; + meta = with lib.maintainers; { + maintainers = [ andir hexa ]; }; nodes = { @@ -22,26 +22,38 @@ import ./make-test-python.nix ({pkgs, ...}: { # # Note: On the ISPs device we don't really care if we are using networkd in # this example. That being said we can't use it (yet) as networkd doesn't - # implement the serving side of DHCPv6. We will use ISC's well aged dhcpd6 - # for that task. + # implement the serving side of DHCPv6. We will use ISC Kea for that task. isp = { lib, pkgs, ... }: { virtualisation.vlans = [ 1 ]; networking = { useDHCP = false; firewall.enable = false; - interfaces.eth1.ipv4.addresses = lib.mkForce []; # no need for legacy IP - interfaces.eth1.ipv6.addresses = lib.mkForce [ - { address = "2001:DB8::1"; prefixLength = 64; } - ]; + interfaces.eth1 = lib.mkForce {}; # Don't use scripted networking + }; + + systemd.network = { + enable = true; + + networks = { + "eth1" = { + matchConfig.Name = "eth1"; + address = [ + "2001:DB8::1/64" + ]; + networkConfig.IPForward = true; + }; + }; }; # Since we want to program the routes that we delegate to the "customer" - # into our routing table we must give dhcpd the required privs. - systemd.services.dhcpd6.serviceConfig.AmbientCapabilities = - [ "CAP_NET_ADMIN" ]; + # into our routing table we must provide kea with the required capability. + systemd.services.kea-dhcp6-server.serviceConfig = { + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; + }; services = { - # Configure the DHCPv6 server + # Configure the DHCPv6 server to hand out both IA_NA and IA_PD. # # We will hand out /48 prefixes from the subnet 2001:DB8:F000::/36. # That gives us ~8k prefixes. That should be enough for this test. @@ -49,31 +61,70 @@ import ./make-test-python.nix ({pkgs, ...}: { # Since (usually) you will not receive a prefix with the router # advertisements we also hand out /128 leases from the range # 2001:DB8:0000:0000:FFFF::/112. - dhcpd6 = { + kea.dhcp6 = { enable = true; - interfaces = [ "eth1" ]; - extraConfig = '' - subnet6 2001:DB8::/36 { - range6 2001:DB8:0000:0000:FFFF:: 2001:DB8:0000:0000:FFFF::FFFF; - prefix6 2001:DB8:F000:: 2001:DB8:FFFF:: /48; - } - - # This is the secret sauce. We have to extract the prefix and the - # next hop when commiting the lease to the database. dhcpd6 - # (rightfully) has not concept of adding routes to the systems - # routing table. It really depends on the setup. + settings = { + interfaces-config.interfaces = [ "eth1" ]; + subnet6 = [ { + interface = "eth1"; + subnet = "2001:DB8:F::/36"; + pd-pools = [ { + prefix = "2001:DB8:F::"; + prefix-len = 36; + delegated-len = 48; + } ]; + pools = [ { + pool = "2001:DB8:0000:0000:FFFF::-2001:DB8:0000:0000:FFFF::FFFF"; + } ]; + } ]; + + # This is the glue between Kea and the Kernel FIB. DHCPv6 + # rightfully has no concept of setting up a route in your + # FIB. This step really depends on your setup. # - # In a production environment your DHCPv6 server is likely not the - # router. You might want to consider BGP, custom NetConf calls, … - # in those cases. - on commit { - set IP = pick-first-value(binary-to-ascii(16, 16, ":", substring(option dhcp6.ia-na, 16, 16)), "n/a"); - set Prefix = pick-first-value(binary-to-ascii(16, 16, ":", suffix(option dhcp6.ia-pd, 16)), "n/a"); - set PrefixLength = pick-first-value(binary-to-ascii(10, 8, ":", substring(suffix(option dhcp6.ia-pd, 17), 0, 1)), "n/a"); - log(concat(IP, " ", Prefix, " ", PrefixLength)); - execute("${pkgs.iproute2}/bin/ip", "-6", "route", "replace", concat(Prefix,"/",PrefixLength), "via", IP); - } - ''; + # In a production environment your DHCPv6 server is likely + # not the router. You might want to consider BGP, NETCONF + # calls, … in those cases. + # + # In this example we use the run script hook, that lets use + # execute anything and passes information via the environment. + # https://kea.readthedocs.io/en/kea-2.2.0/arm/hooks.html#run-script-run-script-support-for-external-hook-scripts + hooks-libraries = [ { + library = "${pkgs.kea}/lib/kea/hooks/libdhcp_run_script.so"; + parameters = { + name = pkgs.writeShellScript "kea-run-hooks" '' + export PATH="${lib.makeBinPath (with pkgs; [ coreutils iproute2 ])}" + + set -euxo pipefail + + leases6_committed() { + for i in $(seq $LEASES6_SIZE); do + idx=$((i-1)) + prefix_var="LEASES6_AT''${idx}_ADDRESS" + plen_var="LEASES6_AT''${idx}_PREFIX_LEN" + + ip -6 route replace ''${!prefix_var}/''${!plen_var} via $QUERY6_REMOTE_ADDR dev $QUERY6_IFACE_NAME + done + } + + unknown_handler() { + echo "Unhandled function call ''${*}" + exit 123 + } + + case "$1" in + "leases6_committed") + leases6_committed + ;; + *) + unknown_handler "''${@}" + ;; + esac + ''; + sync = false; + }; + } ]; + }; }; # Finally we have to set up the router advertisements. While we could be diff --git a/nixos/tests/systemd-oomd.nix b/nixos/tests/systemd-oomd.nix index f0b5a5f8e01..55c4c135000 100644 --- a/nixos/tests/systemd-oomd.nix +++ b/nixos/tests/systemd-oomd.nix @@ -3,35 +3,52 @@ import ./make-test-python.nix ({ pkgs, ... }: { name = "systemd-oomd"; + # This test is a simplified version of systemd's testsuite-55. + # https://github.com/systemd/systemd/blob/v251/test/units/testsuite-55.sh nodes.machine = { pkgs, ... }: { - systemd.oomd.extraConfig.DefaultMemoryPressureDurationSec = "1s"; # makes the test faster - # Kill cgroups when more than 1% pressure is encountered - systemd.slices."-".sliceConfig = { - ManagedOOMMemoryPressure = "kill"; - ManagedOOMMemoryPressureLimit = "1%"; + # Limit VM resource usage. + virtualisation.memorySize = 1024; + systemd.oomd.extraConfig.DefaultMemoryPressureDurationSec = "1s"; + + systemd.slices.workload = { + description = "Test slice for memory pressure kills"; + sliceConfig = { + MemoryAccounting = true; + ManagedOOMMemoryPressure = "kill"; + ManagedOOMMemoryPressureLimit = "10%"; + }; }; - # A service to bring the system under memory pressure - systemd.services.testservice = { - serviceConfig.ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero"; + + systemd.services.testbloat = { + description = "Create a lot of memory pressure"; + serviceConfig = { + Slice = "workload.slice"; + MemoryHigh = "5M"; + ExecStart = "${pkgs.coreutils}/bin/tail /dev/zero"; + }; }; - # Do not kill the backdoor - systemd.services.backdoor.serviceConfig.ManagedOOMMemoryPressure = "auto"; - virtualisation.memorySize = 1024; + systemd.services.testchill = { + description = "No memory pressure"; + serviceConfig = { + Slice = "workload.slice"; + MemoryHigh = "3M"; + ExecStart = "${pkgs.coreutils}/bin/sleep infinity"; + }; + }; }; testScript = '' - # Start the system + # Start the system. machine.wait_for_unit("multi-user.target") machine.succeed("oomctl") - # Bring the system into memory pressure - machine.succeed("echo 0 > /proc/sys/vm/panic_on_oom") # NixOS tests kill the VM when the OOM killer is invoked - override this - machine.succeed("systemctl start testservice") + machine.succeed("systemctl start testchill.service") + with subtest("OOMd should kill the bad service"): + machine.fail("systemctl start --wait testbloat.service") + assert machine.get_unit_info("testbloat.service")["Result"] == "oom-kill" - # Wait for oomd to kill something - # Matches these lines: - # systemd-oomd[508]: Killed /system.slice/systemd-udevd.service due to memory pressure for / being 3.26% > 1.00% for > 1s with reclaim activity - machine.wait_until_succeeds("journalctl -b | grep -q 'due to memory pressure for'") + with subtest("Service without memory pressure should be untouched"): + machine.require_unit_state("testchill.service", "active") ''; }) diff --git a/nixos/tests/tmate-ssh-server.nix b/nixos/tests/tmate-ssh-server.nix new file mode 100644 index 00000000000..e7f94db9bfc --- /dev/null +++ b/nixos/tests/tmate-ssh-server.nix @@ -0,0 +1,73 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: +let + inherit (import ./ssh-keys.nix pkgs) + snakeOilPrivateKey snakeOilPublicKey; + + setUpPrivateKey = name: '' + ${name}.succeed( + "mkdir -p /root/.ssh", + "chown 700 /root/.ssh", + "cat '${snakeOilPrivateKey}' > /root/.ssh/id_snakeoil", + "chown 600 /root/.ssh/id_snakeoil", + ) + ${name}.wait_for_file("/root/.ssh/id_snakeoil") + ''; + + sshOpts = "-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oIdentityFile=/root/.ssh/id_snakeoil"; + +in +{ + name = "tmate-ssh-server"; + nodes = + { + server = { ... }: { + services.tmate-ssh-server = { + enable = true; + port = 2223; + }; + }; + client = { ... }: { + environment.systemPackages = [ pkgs.tmate ]; + services.openssh.enable = true; + users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ]; + }; + client2 = { ... }: { + environment.systemPackages = [ pkgs.openssh ]; + }; + }; + testScript = '' + start_all() + + server.wait_for_unit("tmate-ssh-server.service") + server.wait_for_open_port(2223) + server.wait_for_file("/etc/tmate-ssh-server-keys/ssh_host_ed25519_key.pub") + server.wait_for_file("/etc/tmate-ssh-server-keys/ssh_host_rsa_key.pub") + server.succeed("tmate-client-config > /tmp/tmate.conf") + server.wait_for_file("/tmp/tmate.conf") + + ${setUpPrivateKey "server"} + client.wait_for_unit("sshd.service") + client.wait_for_open_port(22) + server.succeed("scp ${sshOpts} /tmp/tmate.conf client:/tmp/tmate.conf") + + client.wait_for_file("/tmp/tmate.conf") + client.send_chars("root\n") + client.sleep(2) + client.send_chars("tmate -f /tmp/tmate.conf\n") + client.sleep(2) + client.send_chars("q") + client.sleep(2) + client.send_chars("tmate display -p '#{tmate_ssh}' > /tmp/ssh_command\n") + client.wait_for_file("/tmp/ssh_command") + ssh_cmd = client.succeed("cat /tmp/ssh_command") + + client2.succeed("mkdir -p ~/.ssh; ssh-keyscan -p 2223 server > ~/.ssh/known_hosts") + client2.send_chars("root\n") + client2.sleep(2) + client2.send_chars(ssh_cmd.strip() + "\n") + client2.sleep(2) + client2.send_chars("touch /tmp/client_2\n") + + client.wait_for_file("/tmp/client_2") + ''; +}) diff --git a/nixos/tests/tracee.nix b/nixos/tests/tracee.nix new file mode 100644 index 00000000000..26d0ada931b --- /dev/null +++ b/nixos/tests/tracee.nix @@ -0,0 +1,46 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "tracee-integration"; + nodes = { + machine = { config, pkgs, ... }: { + # EventFilters/trace_only_events_from_new_containers requires docker + # podman with docker compat will suffice + virtualisation.podman.enable = true; + virtualisation.podman.dockerCompat = true; + + environment.systemPackages = [ + # build the go integration tests as a binary + (pkgs.tracee.overrideAttrs (oa: { + pname = oa.pname + "-integration"; + patches = oa.patches or [] ++ [ + # change the prefix from /usr/bin to /run to find nix processes + ../../pkgs/tools/security/tracee/test-EventFilters-prefix-nix-friendly.patch + # skip magic_write test that currently fails + ../../pkgs/tools/security/tracee/test-EventFilters-magic_write-skip.patch + ]; + buildPhase = '' + runHook preBuild + # just build the static lib we need for the go test binary + make $makeFlags ''${enableParallelBuilding:+-j$NIX_BUILD_CORES -l$NIX_BUILD_CORES} bpf-core ./dist/btfhub ./dist/libbpf/libbpf.a + # then compile the tests to be ran later + CGO_CFLAGS="-I$PWD/dist/libbpf" CGO_LDFLAGS="-lelf -lz $PWD/dist/libbpf/libbpf.a" go test -tags core,ebpf,integration -p 1 -c -o $GOPATH/tracee-integration ./tests/integration/... + runHook postBuild + ''; + doCheck = false; + installPhase = '' + mkdir -p $out/bin + cp $GOPATH/tracee-integration $out/bin + ''; + doInstallCheck = false; + })) + ]; + }; + }; + + testScript = '' + with subtest("run integration tests"): + # EventFilters/trace_only_events_from_new_containers also requires a container called "alpine" + machine.succeed('tar cv -C ${pkgs.pkgsStatic.busybox} . | podman import - alpine --change ENTRYPOINT=sleep') + + print(machine.succeed('TRC_BIN="${pkgs.tracee}" tracee-integration -test.v')) + ''; +}) |