Skip to content

Commit

Permalink
nixos/tmate-ssh-server: init module (#192270)
Browse files Browse the repository at this point in the history
* nixos/tmate-ssh-server: init module

Co-authored-by: Aaron Andersen <aaron@fosslib.net>
  • Loading branch information
jlesquembre and aanderse committed Oct 5, 2022
1 parent 6c31662 commit 396f4f0
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 9 deletions.
9 changes: 9 additions & 0 deletions nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,15 @@
<link linkend="opt-services.go-autoconfig.enable">services.go-autoconfig</link>.
</para>
</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
Expand Down
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2211.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,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).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
122 changes: 122 additions & 0 deletions nixos/modules/services/networking/tmate-ssh-server.nix
Original file line number Diff line number Diff line change
@@ -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 ];
};

}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ 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
Expand Down
73 changes: 73 additions & 0 deletions nixos/tests/tmate-ssh-server.nix
Original file line number Diff line number Diff line change
@@ -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")
'';
})
33 changes: 24 additions & 9 deletions pkgs/servers/tmate-ssh-server/default.nix
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
{ lib, stdenv, fetchFromGitHub, autoreconfHook, cmake, libtool, pkg-config
, zlib, openssl, libevent, ncurses, ruby, msgpack, libssh }:
{ lib
, stdenv
, fetchFromGitHub
, autoreconfHook
, cmake
, libtool
, pkg-config
, zlib
, openssl
, libevent
, ncurses
, ruby
, msgpack
, libssh
, nixosTests
}:

stdenv.mkDerivation rec {
pname = "tmate-ssh-server";
version = "unstable-2021-10-17";

src = fetchFromGitHub {
owner = "tmate-io";
repo = "tmate-ssh-server";
rev = "1f314123df2bb29cb07427ed8663a81c8d9034fd";
owner = "tmate-io";
repo = "tmate-ssh-server";
rev = "1f314123df2bb29cb07427ed8663a81c8d9034fd";
sha256 = "sha256-9/xlMvtkNWUBRYYnJx20qEgtEcjagH2NtEKZcDOM1BY=";
};

Expand All @@ -17,12 +31,13 @@ stdenv.mkDerivation rec {
buildInputs = [ libtool zlib openssl libevent ncurses ruby msgpack libssh ];
nativeBuildInputs = [ autoreconfHook cmake pkg-config ];

passthru.tests.tmate-ssh-server = nixosTests.tmate-ssh-server;

meta = with lib; {
homepage = "https://tmate.io/";
homepage = "https://tmate.io/";
description = "tmate SSH Server";
license = licenses.mit;
platforms = platforms.unix;
license = licenses.mit;
platforms = platforms.unix;
maintainers = with maintainers; [ ck3d ];
};
}

0 comments on commit 396f4f0

Please sign in to comment.