fix(deploy): set up 'colmena' wrapper for hardware-backed SSH keys

This commit is contained in:
2026-06-13 20:42:21 +02:00
parent fc38f49fbf
commit e845834833
7 changed files with 149 additions and 34 deletions
+68
View File
@@ -0,0 +1,68 @@
# `colmena` wrapper script that opens a short-lived SSH master process for
# `colmena` to use so it works with hardware-backed key touch+PIN. assumes
# ControlPath ~/.ssh/socket-%r@%h:%p (see ./default.nix)
selector=""
want_on=0
on_given=0
deploy_cmd=0
nodes=()
on_nodes=()
master_processes=()
# build node list from `--on` value, a comma-separated string (e.g. "host-01,host-02")
for arg in "$@"; do
if ((want_on)); then
selector="$arg"
want_on=0
continue
fi
case "$arg" in
--on=*)
selector="${arg#--on=}"
on_given=1
;;
--on) want_on=1 on_given=1 ;;
apply | exec | upload-keys) deploy_cmd=1 ;;
esac
done
# shellcheck disable=SC2154
if ((deploy_cmd)) && ! ((on_given)); then
on_nodes=("${!_colmena_node_tags[@]}")
else
IFS=',' read -ra nodes <<< "$selector"
for node in "${nodes[@]}"; do
for node_tag in "${!_colmena_node_tags[@]}"; do
if [[ "$node" == @* ]]; then
for tag in ${_colmena_node_tags[$node_tag]}; do
# shellcheck disable=SC2053
[[ "$tag" == ${node#@} ]] && on_nodes+=("$node_tag")
done
else
# shellcheck disable=SC2053
[[ "$node_tag" == $node ]] && on_nodes+=("$node_tag")
fi
done
done
fi
for node in "${on_nodes[@]}"; do
# check if master process is running (see `man ssh`)
ssh -O check "$node" 2>/dev/null && continue
# place ssh client into "master" mode for connection sharing (see `man ssh`)
if ssh -fNM "$node"; then
master_processes+=("$node")
fi
done
rc=0
@colmena@ "$@" || rc=$?
# request master processes to exit (see `man ssh`)
for process in "${master_processes[@]}"; do
ssh -O exit "$process" 2>/dev/null || true
done
exit "$rc"
+70
View File
@@ -0,0 +1,70 @@
{
config,
lib,
pkgs,
inputs,
myUtils,
...
}:
let
cfg = config.deploy;
hostDir = ../../../hosts;
hostNames = myUtils.dirNames hostDir;
hostsWithKeys = lib.filter (
hostname: builtins.pathExists (hostDir + "/${hostname}/ssh_host.pub")
) hostNames;
colmena = inputs.colmena.packages.${pkgs.stdenv.hostPlatform.system}.colmena;
hostTags = hostname: (myUtils.hostMeta (hostDir + "/${hostname}")).tags;
remoteHostsWithKeys = lib.filter (
hostname: !(builtins.elem "local" (hostTags hostname))
) hostsWithKeys;
nodeTagsDecl = ''
declare -A _colmena_node_tags=(
${lib.concatMapStringsSep "\n" (
hostname: " [${hostname}]=${lib.escapeShellArg (lib.concatStringsSep " " (hostTags hostname))}"
) remoteHostsWithKeys}
)
'';
colmenaWrapped = pkgs.writeShellApplication {
name = "colmena";
runtimeInputs = [ pkgs.openssh ];
text =
nodeTagsDecl
+ lib.replaceStrings [ "@colmena@" ] [ "${colmena}/bin/colmena" ] (
builtins.readFile ./colmena-wrapper.bash
);
};
in
{
options.deploy.enable = lib.mkEnableOption "deploy";
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = config.ssh.enable;
message = "'home/modules/deploy' requires 'home/modules/ssh'";
}
];
home.packages = [ colmenaWrapped ];
programs.ssh.settings = lib.genAttrs hostsWithKeys (
hostname:
let
meta = myUtils.hostMeta (hostDir + "/${hostname}");
isLocal = builtins.elem "local" meta.tags;
in
{
User = meta.host.username;
}
// lib.optionalAttrs (!isLocal) {
HostName = hostname;
ControlPath = "~/.ssh/socket-%r@%h:%p";
}
);
};
}
+9 -29
View File
@@ -2,17 +2,11 @@
config,
lib,
pkgs,
myUtils,
...
}:
let
cfg = config.ssh;
hostDir = ../../hosts;
hostNames = myUtils.dirNames hostDir;
hostsWithKeys = lib.filter (
hostname: builtins.pathExists (hostDir + "/${hostname}/ssh_host.pub")
) hostNames;
in
{
options.ssh.enable = lib.mkEnableOption "ssh";
@@ -24,30 +18,16 @@ in
enable = true;
enableDefaultConfig = false;
settings =
lib.genAttrs hostsWithKeys (
hostname:
let
meta = myUtils.hostMeta (hostDir + "/${hostname}");
isLocal = builtins.elem "local" meta.tags;
in
{
User = meta.host.username;
}
// lib.optionalAttrs (!isLocal) {
HostName = hostname;
}
)
// {
"*" = {
AddKeysToAgent = "yes";
ForwardAgent = false;
identityFile = [
"~/.ssh/id_ed25519_sk"
"~/.ssh/id_ed25519_sk_bak"
];
};
settings = {
"*" = {
AddKeysToAgent = "yes";
ForwardAgent = false;
identityFile = [
"~/.ssh/id_ed25519_sk"
"~/.ssh/id_ed25519_sk_bak"
];
};
};
};
};
}