nixos/tmate-ssh-server: init module (#192270)

* nixos/tmate-ssh-server: init module

Co-authored-by: Aaron Andersen <aaron@fosslib.net>
This commit is contained in:
José Luis Lafuente 2022-10-05 18:34:30 +02:00 committed by GitHub
parent 6c31662096
commit 396f4f05b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 232 additions and 9 deletions

View file

@ -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

View file

@ -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).

View file

@ -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

View file

@ -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 ];
};
}

View file

@ -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

View file

@ -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")
'';
})

View file

@ -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=";
};
@ -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 ];
};
}