tlshd: add modular service and test

This commit is contained in:
Tom Fitzhenry
2026-04-09 10:08:10 +00:00
parent 4eb3c80253
commit 55efd0620a
5 changed files with 179 additions and 1 deletions

View File

@@ -20,6 +20,7 @@ let
modularServicesModule = {
options = {
"<imports = [ pkgs.ghostunnel.services.default ]>" = fakeSubmodule pkgs.ghostunnel.services.default;
"<imports = [ pkgs.ktls-utils.services.default ]>" = fakeSubmodule pkgs.ktls-utils.services.default;
"<imports = [ pkgs.php.services.default ]>" = fakeSubmodule pkgs.php.services.default;
"<imports = [ pkgs.snid.services.default ]>" = fakeSubmodule pkgs.snid.services.default;
};

View File

@@ -1655,6 +1655,7 @@ in
tinydns = runTest ./tinydns.nix;
tinyproxy = runTest ./tinyproxy.nix;
tinywl = runTest ./tinywl.nix;
tlshd = runTest ./tlshd.nix;
tlsrpt = runTest ./tlsrpt.nix;
tmate-ssh-server = runTest ./tmate-ssh-server.nix;
tomcat = runTest ./tomcat.nix;

93
nixos/tests/tlshd.nix Normal file
View File

@@ -0,0 +1,93 @@
{ lib, pkgs, ... }:
let
runWithOpenSSL =
name: cmd:
pkgs.runCommand name {
buildInputs = [ pkgs.openssl ];
} cmd;
caKey = runWithOpenSSL "ca.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
caCert = runWithOpenSSL "ca.crt" ''
openssl req -new -x509 -sha256 -key ${caKey} -out $out -subj "/CN=Test CA" -days 36500
'';
serverKey = runWithOpenSSL "server.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
serverCert = runWithOpenSSL "server.crt" ''
openssl req -new -sha256 -key ${serverKey} -out server.csr -subj "/CN=server"
openssl x509 -req -in server.csr -CA ${caCert} -CAkey ${caKey} \
-CAcreateserial -out $out -days 36500 -sha256
'';
clientKey = runWithOpenSSL "client.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
clientCert = runWithOpenSSL "client.crt" ''
openssl req -new -sha256 -key ${clientKey} -out client.csr -subj "/CN=client"
openssl x509 -req -in client.csr -CA ${caCert} -CAkey ${caKey} \
-CAcreateserial -out $out -days 36500 -sha256
'';
in
{
_class = "nixosTest";
name = "tlshd";
nodes = {
server =
{ pkgs, ... }:
{
system.services.tlshd = {
imports = [ pkgs.ktls-utils.services.default ];
tlshd.settings = {
"authenticate.server" = {
"x509.certificate" = toString serverCert;
"x509.private_key" = toString serverKey;
"x509.truststore" = toString caCert;
};
};
};
services.nfs.server = {
enable = true;
exports = ''
/export 192.168.1.0/24(rw,no_root_squash,no_subtree_check,xprtsec=mtls)
'';
createMountPoints = true;
};
networking.firewall.enable = false;
};
client =
{ pkgs, ... }:
{
system.services.tlshd = {
imports = [ pkgs.ktls-utils.services.default ];
tlshd.settings = {
"authenticate.client" = {
"x509.certificate" = toString clientCert;
"x509.private_key" = toString clientKey;
"x509.truststore" = toString caCert;
};
};
};
virtualisation.fileSystems."/mnt/nfs" = {
device = "server:/export";
fsType = "nfs";
options = [ "xprtsec=mtls" ];
};
networking.firewall.enable = false;
};
};
testScript = ''
start_all()
server.wait_for_unit("nfs-server.service")
server.wait_for_unit("tlshd.service")
client.wait_for_unit("tlshd.service")
client.wait_for_unit("mnt-nfs.mount")
client.wait_until_succeeds("echo 'hello from client' > /mnt/nfs/test.txt")
server.wait_until_succeeds("grep 'hello from client' /export/test.txt")
'';
meta.maintainers = with lib.maintainers; [ tomfitzhenry ];
}

View File

@@ -11,6 +11,7 @@
systemd,
withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
nix-update-script,
nixosTests,
}:
stdenv.mkDerivation (finalAttrs: {
@@ -47,7 +48,14 @@ stdenv.mkDerivation (finalAttrs: {
doCheck = true;
passthru.updateScript = nix-update-script { };
passthru = {
updateScript = nix-update-script { };
tests.nixos = nixosTests.tlshd;
services.default = {
imports = [ (lib.modules.importApply ./service.nix { }) ];
tlshd.package = finalAttrs.finalPackage;
};
};
meta = {
description = "TLS handshake utilities for in-kernel TLS consumers";

View File

@@ -0,0 +1,75 @@
# Non-module dependencies (`importApply`)
{ }:
# Service module
{
lib,
config,
options,
...
}:
let
inherit (lib)
getExe
mkOption
types
;
cfg = config.tlshd;
configFile = config.configData."tlshd.conf".path;
in
{
# https://nixos.org/manual/nixos/unstable/#modular-services
_class = "service";
options.tlshd = {
package = mkOption {
description = "Package to use for tlshd.";
defaultText = lib.literalMD "The `ktls-utils` package that provided this module.";
type = types.package;
};
settings = mkOption {
description = ''
Configuration for tlshd in INI format.
See {manpage}`tlshd.conf(5)` for available options.
'';
type = types.attrsOf (types.attrsOf types.str);
default = { };
example = lib.literalExpression ''
{
"authenticate.server" = {
"x509.certificate" = "/var/lib/tlshd/cert.pem";
"x509.private_key" = "/var/lib/tlshd/key.pem";
"x509.truststore" = "/var/lib/tlshd/truststore.pem";
};
}
'';
};
};
config = {
configData."tlshd.conf".text = lib.generators.toINI { } cfg.settings;
process.argv = [
(getExe cfg.package)
"--config"
configFile
];
}
// lib.optionalAttrs (options ? systemd) {
systemd.service = {
description = "Handshake service for kernel TLS consumers";
documentation = [ "man:tlshd(8)" ];
unitConfig.DefaultDependencies = false;
before = [ "remote-fs-pre.target" ];
wantedBy = [ "remote-fs.target" ];
serviceConfig = {
Restart = "on-failure";
DynamicUser = true;
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
};
};
};
}