From 99dc9b9c164af3bc6c08ff4a4db4c2b58e368160 Mon Sep 17 00:00:00 2001 From: Azat Bahawi Date: Fri, 23 Sep 2022 23:39:38 +0300 Subject: nixos/endlessh-go: init module --- .../from_md/release-notes/rl-2211.section.xml | 7 ++ nixos/doc/manual/release-notes/rl-2211.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/security/endlessh-go.nix | 138 +++++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/endlessh-go.nix | 58 +++++++++ 6 files changed, 207 insertions(+) create mode 100644 nixos/modules/services/security/endlessh-go.nix create mode 100644 nixos/tests/endlessh-go.nix (limited to 'nixos') 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 0f1dffc798e7..17f0aea9dcee 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 @@ -239,6 +239,13 @@ services.alps. + + + endlessh-go, + an SSH tarpit that exposes Prometheus metrics. Available as + services.endlessh-go. + + netbird, a zero diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index 7214937781d2..7e1a87e89b9e 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -87,6 +87,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). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 699c5c7dead4..45fbe1d1ce1b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1000,6 +1000,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/services/security/endlessh-go.nix b/nixos/modules/services/security/endlessh-go.nix new file mode 100644 index 000000000000..61cca5531739 --- /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/tests/all-tests.nix b/nixos/tests/all-tests.nix index f4ec831caa7e..b856c6823dc6 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -142,6 +142,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 {}; diff --git a/nixos/tests/endlessh-go.nix b/nixos/tests/endlessh-go.nix new file mode 100644 index 000000000000..b261dbf1c560 --- /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") + ''; +}) -- cgit v1.2.3