nixos/endlessh: init module

+170 -3
+7
nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
··· 316 316 </listitem> 317 317 <listitem> 318 318 <para> 319 + <link xlink:href="https://github.com/skeeto/endlessh">endlessh</link>, 320 + an SSH tarpit. Available as 321 + <link linkend="opt-services.endlessh.enable">services.endlessh</link>. 322 + </para> 323 + </listitem> 324 + <listitem> 325 + <para> 319 326 <link xlink:href="https://github.com/shizunge/endlessh-go">endlessh-go</link>, 320 327 an SSH tarpit that exposes Prometheus metrics. Available as 321 328 <link linkend="opt-services.endlessh-go.enable">services.endlessh-go</link>.
+2
nixos/doc/manual/release-notes/rl-2211.section.md
··· 114 114 115 115 - [alps](https://git.sr.ht/~migadu/alps), a simple and extensible webmail. Available as [services.alps](#opt-services.alps.enable). 116 116 117 + - [endlessh](https://github.com/skeeto/endlessh), an SSH tarpit. Available as [services.endlessh](#opt-services.endlessh.enable). 118 + 117 119 - [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). 118 120 119 121 - [netbird](https://netbird.io), a zero configuration VPN.
+1
nixos/modules/module-list.nix
··· 1009 1009 ./services/security/certmgr.nix 1010 1010 ./services/security/cfssl.nix 1011 1011 ./services/security/clamav.nix 1012 + ./services/security/endlessh.nix 1012 1013 ./services/security/endlessh-go.nix 1013 1014 ./services/security/fail2ban.nix 1014 1015 ./services/security/fprintd.nix
+99
nixos/modules/services/security/endlessh.nix
··· 1 + { config, lib, pkgs, ... }: 2 + 3 + with lib; 4 + 5 + let 6 + cfg = config.services.endlessh; 7 + in 8 + { 9 + options.services.endlessh = { 10 + enable = mkEnableOption (mdDoc "endlessh service"); 11 + 12 + port = mkOption { 13 + type = types.port; 14 + default = 2222; 15 + example = 22; 16 + description = mdDoc '' 17 + Specifies on which port the endlessh daemon listens for SSH 18 + connections. 19 + 20 + Setting this to `22` may conflict with {option}`services.openssh`. 21 + ''; 22 + }; 23 + 24 + extraOptions = mkOption { 25 + type = with types; listOf str; 26 + default = [ ]; 27 + example = [ "-6" "-d 9000" "-v" ]; 28 + description = mdDoc '' 29 + Additional command line options to pass to the endlessh daemon. 30 + ''; 31 + }; 32 + 33 + openFirewall = mkOption { 34 + type = types.bool; 35 + default = false; 36 + description = lib.mdDoc '' 37 + Whether to open a firewall port for the SSH listener. 38 + ''; 39 + }; 40 + }; 41 + 42 + config = mkIf cfg.enable { 43 + systemd.services.endlessh = { 44 + description = "SSH tarpit"; 45 + requires = [ "network.target" ]; 46 + wantedBy = [ "multi-user.target" ]; 47 + serviceConfig = 48 + let 49 + needsPrivileges = cfg.port < 1024; 50 + capabilities = [ "" ] ++ optionals needsPrivileges [ "CAP_NET_BIND_SERVICE" ]; 51 + rootDirectory = "/run/endlessh"; 52 + in 53 + { 54 + Restart = "always"; 55 + ExecStart = with cfg; concatStringsSep " " ([ 56 + "${pkgs.endlessh}/bin/endlessh" 57 + "-p ${toString port}" 58 + ] ++ extraOptions); 59 + DynamicUser = true; 60 + RootDirectory = rootDirectory; 61 + BindReadOnlyPaths = [ builtins.storeDir ]; 62 + InaccessiblePaths = [ "-+${rootDirectory}" ]; 63 + RuntimeDirectory = baseNameOf rootDirectory; 64 + RuntimeDirectoryMode = "700"; 65 + AmbientCapabilities = capabilities; 66 + CapabilityBoundingSet = capabilities; 67 + UMask = "0077"; 68 + LockPersonality = true; 69 + MemoryDenyWriteExecute = true; 70 + NoNewPrivileges = true; 71 + PrivateDevices = true; 72 + PrivateTmp = true; 73 + PrivateUsers = !needsPrivileges; 74 + ProtectClock = true; 75 + ProtectControlGroups = true; 76 + ProtectHome = true; 77 + ProtectHostname = true; 78 + ProtectKernelLogs = true; 79 + ProtectKernelModules = true; 80 + ProtectKernelTunables = true; 81 + ProtectSystem = "strict"; 82 + ProtectProc = "noaccess"; 83 + ProcSubset = "pid"; 84 + RemoveIPC = true; 85 + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; 86 + RestrictNamespaces = true; 87 + RestrictRealtime = true; 88 + RestrictSUIDSGID = true; 89 + SystemCallArchitectures = "native"; 90 + SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ]; 91 + }; 92 + }; 93 + 94 + networking.firewall.allowedTCPPorts = with cfg; 95 + optionals openFirewall [ port ]; 96 + }; 97 + 98 + meta.maintainers = with maintainers; [ azahi ]; 99 + }
+1
nixos/tests/all-tests.nix
··· 180 180 ejabberd = handleTest ./xmpp/ejabberd.nix {}; 181 181 elk = handleTestOn ["x86_64-linux"] ./elk.nix {}; 182 182 emacs-daemon = handleTest ./emacs-daemon.nix {}; 183 + endlessh = handleTest ./endlessh.nix {}; 183 184 endlessh-go = handleTest ./endlessh-go.nix {}; 184 185 engelsystem = handleTest ./engelsystem.nix {}; 185 186 enlightenment = handleTest ./enlightenment.nix {};
+43
nixos/tests/endlessh.nix
··· 1 + import ./make-test-python.nix ({ lib, pkgs, ... }: 2 + { 3 + name = "endlessh"; 4 + meta.maintainers = with lib.maintainers; [ azahi ]; 5 + 6 + nodes = { 7 + server = { ... }: { 8 + services.endlessh = { 9 + enable = true; 10 + openFirewall = true; 11 + }; 12 + 13 + specialisation = { 14 + unprivileged.configuration.services.endlessh.port = 2222; 15 + 16 + privileged.configuration.services.endlessh.port = 22; 17 + }; 18 + }; 19 + 20 + client = { pkgs, ... }: { 21 + environment.systemPackages = with pkgs; [ curl netcat ]; 22 + }; 23 + }; 24 + 25 + testScript = '' 26 + def activate_specialisation(name: str): 27 + server.succeed(f"/run/booted-system/specialisation/{name}/bin/switch-to-configuration test >&2") 28 + 29 + start_all() 30 + 31 + with subtest("Unprivileged"): 32 + activate_specialisation("unprivileged") 33 + server.wait_for_unit("endlessh.service") 34 + server.wait_for_open_port(2222) 35 + client.succeed("nc -dvW5 server 2222") 36 + 37 + with subtest("Privileged"): 38 + activate_specialisation("privileged") 39 + server.wait_for_unit("endlessh.service") 40 + server.wait_for_open_port(22) 41 + client.succeed("nc -dvW5 server 22") 42 + ''; 43 + })
+17 -3
pkgs/servers/endlessh/default.nix
··· 1 - { lib, stdenv, fetchFromGitHub }: 1 + { lib 2 + , stdenv 3 + , fetchFromGitHub 4 + , testers 5 + , endlessh 6 + , nixosTests 7 + }: 2 8 3 9 stdenv.mkDerivation rec { 4 10 pname = "endlessh"; ··· 8 14 owner = "skeeto"; 9 15 repo = pname; 10 16 rev = version; 11 - sha256 = "0ziwr8j1frsp3dajr8h5glkm1dn5cci404kazz5w1jfrp0736x68"; 17 + hash = "sha256-yHQzDrjZycDL/2oSQCJjxbZQJ30FoixVG1dnFyTKPH4="; 12 18 }; 13 19 14 20 makeFlags = [ "PREFIX=$(out)" ]; 15 21 22 + passthru.tests = { 23 + inherit (nixosTests) endlessh; 24 + version = testers.testVersion { 25 + package = endlessh; 26 + command = "endlessh -V"; 27 + }; 28 + }; 29 + 16 30 meta = with lib; { 17 31 description = "SSH tarpit that slowly sends an endless banner"; 18 32 homepage = "https://github.com/skeeto/endlessh"; 19 33 changelog = "https://github.com/skeeto/endlessh/releases/tag/${version}"; 20 34 license = licenses.unlicense; 21 - maintainers = [ maintainers.marsam ]; 35 + maintainers = with maintainers; [ azahi marsam ]; 22 36 platforms = platforms.unix; 23 37 }; 24 38 }