Merge pull request #112682 from hax404/upterm
commit
3607d087ec
@ -0,0 +1,106 @@ |
|||||||
|
{ config, lib, pkgs, ... }: |
||||||
|
|
||||||
|
with lib; |
||||||
|
|
||||||
|
let |
||||||
|
cfg = config.services.uptermd; |
||||||
|
in |
||||||
|
{ |
||||||
|
options = { |
||||||
|
services.uptermd = { |
||||||
|
enable = mkEnableOption "uptermd"; |
||||||
|
|
||||||
|
openFirewall = mkOption { |
||||||
|
type = types.bool; |
||||||
|
default = false; |
||||||
|
description = '' |
||||||
|
Whether to open the firewall for the port in <option>services.uptermd.port</option>. |
||||||
|
''; |
||||||
|
}; |
||||||
|
|
||||||
|
port = mkOption { |
||||||
|
type = types.port; |
||||||
|
default = 2222; |
||||||
|
description = '' |
||||||
|
Port the server will listen on. |
||||||
|
''; |
||||||
|
}; |
||||||
|
|
||||||
|
listenAddress = mkOption { |
||||||
|
type = types.str; |
||||||
|
default = "[::]"; |
||||||
|
example = "127.0.0.1"; |
||||||
|
description = '' |
||||||
|
Address the server will listen on. |
||||||
|
''; |
||||||
|
}; |
||||||
|
|
||||||
|
hostKey = mkOption { |
||||||
|
type = types.nullOr types.path; |
||||||
|
default = null; |
||||||
|
example = "/run/keys/upterm_host_ed25519_key"; |
||||||
|
description = '' |
||||||
|
Path to SSH host key. If not defined, an ed25519 keypair is generated automatically. |
||||||
|
''; |
||||||
|
}; |
||||||
|
|
||||||
|
extraFlags = mkOption { |
||||||
|
type = types.listOf types.str; |
||||||
|
default = []; |
||||||
|
example = [ "--debug" ]; |
||||||
|
description = '' |
||||||
|
Extra flags passed to the uptermd command. |
||||||
|
''; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
config = mkIf cfg.enable { |
||||||
|
networking.firewall = mkIf cfg.openFirewall { |
||||||
|
allowedTCPPorts = [ cfg.port ]; |
||||||
|
}; |
||||||
|
|
||||||
|
systemd.services.uptermd = { |
||||||
|
description = "Upterm Daemon"; |
||||||
|
wantedBy = [ "multi-user.target" ]; |
||||||
|
after = [ "network.target" ]; |
||||||
|
|
||||||
|
path = [ pkgs.openssh ]; |
||||||
|
|
||||||
|
preStart = mkIf (cfg.hostKey == null) '' |
||||||
|
if ! [ -f ssh_host_ed25519_key ]; then |
||||||
|
ssh-keygen \ |
||||||
|
-t ed25519 \ |
||||||
|
-f ssh_host_ed25519_key \ |
||||||
|
-N "" |
||||||
|
fi |
||||||
|
''; |
||||||
|
|
||||||
|
serviceConfig = { |
||||||
|
StateDirectory = "uptermd"; |
||||||
|
WorkingDirectory = "/var/lib/uptermd"; |
||||||
|
ExecStart = "${pkgs.upterm}/bin/uptermd --ssh-addr ${cfg.listenAddress}:${toString cfg.port} --private-key ${if cfg.hostKey == null then "ssh_host_ed25519_key" else cfg.hostKey} ${concatStringsSep " " cfg.extraFlags}"; |
||||||
|
|
||||||
|
# Hardening |
||||||
|
AmbientCapabilities = mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; |
||||||
|
CapabilityBoundingSet = mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; |
||||||
|
PrivateUsers = cfg.port >= 1024; |
||||||
|
LockPersonality = true; |
||||||
|
MemoryDenyWriteExecute = true; |
||||||
|
PrivateDevices = true; |
||||||
|
ProtectClock = true; |
||||||
|
ProtectControlGroups = true; |
||||||
|
ProtectHome = true; |
||||||
|
ProtectHostname = true; |
||||||
|
ProtectKernelLogs = true; |
||||||
|
ProtectKernelModules = true; |
||||||
|
ProtectKernelTunables = true; |
||||||
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; |
||||||
|
RestrictNamespaces = true; |
||||||
|
RestrictRealtime = true; |
||||||
|
SystemCallArchitectures = "native"; |
||||||
|
SystemCallFilter = "@system-service"; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
import ./make-test-python.nix ({ pkgs, ...}: |
||||||
|
|
||||||
|
let |
||||||
|
client = {pkgs, ...}:{ |
||||||
|
environment.systemPackages = [ pkgs.upterm ]; |
||||||
|
}; |
||||||
|
in |
||||||
|
{ |
||||||
|
name = "uptermd"; |
||||||
|
meta = with pkgs.lib.maintainers; { |
||||||
|
maintainers = [ fleaz ]; |
||||||
|
}; |
||||||
|
|
||||||
|
nodes = { |
||||||
|
server = {config, ...}: { |
||||||
|
services.uptermd = { |
||||||
|
enable = true; |
||||||
|
openFirewall = true; |
||||||
|
port = 1337; |
||||||
|
}; |
||||||
|
}; |
||||||
|
client1 = client; |
||||||
|
client2 = client; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
testScript = '' |
||||||
|
start_all() |
||||||
|
|
||||||
|
server.wait_for_unit("uptermd.service") |
||||||
|
server.wait_for_unit("network-online.target") |
||||||
|
|
||||||
|
# Add SSH hostkeys from the server to both clients |
||||||
|
# uptermd needs an '@cert-authority entry so we need to modify the known_hosts file |
||||||
|
client1.execute("sleep 3; mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls") |
||||||
|
client1.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts") |
||||||
|
client2.execute("sleep 3; mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls") |
||||||
|
client2.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts") |
||||||
|
|
||||||
|
client1.wait_for_unit("multi-user.target") |
||||||
|
client1.wait_until_succeeds("pgrep -f 'agetty.*tty1'") |
||||||
|
client1.wait_until_tty_matches(1, "login: ") |
||||||
|
client1.send_chars("root\n") |
||||||
|
client1.wait_until_succeeds("pgrep -u root bash") |
||||||
|
|
||||||
|
client1.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519") |
||||||
|
client1.send_chars("TERM=xterm upterm host --server ssh://server:1337 --force-command hostname -- bash > /tmp/session-details\n") |
||||||
|
client1.wait_for_file("/tmp/session-details") |
||||||
|
client1.send_key("q") |
||||||
|
|
||||||
|
# uptermd can't connect if we don't have a keypair |
||||||
|
client2.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519") |
||||||
|
|
||||||
|
# Grep the ssh connect command from the output of 'upterm host' |
||||||
|
ssh_command = client1.succeed("grep 'SSH Session' /tmp/session-details | cut -d':' -f2-").strip() |
||||||
|
|
||||||
|
# Connect with client2. Because we used '--force-command hostname' we should get "client1" as the output |
||||||
|
output = client2.succeed(ssh_command) |
||||||
|
|
||||||
|
assert output.strip() == "client1" |
||||||
|
''; |
||||||
|
}) |
Loading…
Reference in new issue