feat(hosts/ubuntu/electra): wire up ssh server

Mirror the NixOS openssh config on system-manager: no password auth, no
root login, ed25519 host key only, and gabriel's authorized keys. Its
module runs Ubuntu's /usr/sbin/sshd, so PAM keeps working.

Also enable programs.ssh for system-wide known hosts, and teach the NixOS
side about system-manager hosts so they know electra.
This commit is contained in:
Gabriel Fontes
2026-08-18 10:56:49 -03:00
parent f3f1a448df
commit 2768852d7c
6 changed files with 97 additions and 17 deletions
+2 -1
View File
@@ -6,8 +6,9 @@
... ...
}: let }: let
nixosConfigs = builtins.attrNames outputs.nixosConfigurations; nixosConfigs = builtins.attrNames outputs.nixosConfigurations;
systemConfigs = builtins.attrNames outputs.systemConfigs;
homeConfigs = map (n: lib.last (lib.splitString "@" n)) (builtins.attrNames outputs.homeConfigurations); homeConfigs = map (n: lib.last (lib.splitString "@" n)) (builtins.attrNames outputs.homeConfigurations);
hostnames = lib.unique (homeConfigs ++ nixosConfigs); hostnames = lib.unique (homeConfigs ++ nixosConfigs ++ systemConfigs);
in { in {
programs.ssh = { programs.ssh = {
enable = true; enable = true;
+23 -16
View File
@@ -4,7 +4,12 @@
config, config,
... ...
}: let }: let
hosts = lib.attrNames outputs.nixosConfigurations; # Every host we know a key for, mapped to the file holding it.
hostKeyFiles =
lib.genAttrs (lib.attrNames outputs.nixosConfigurations)
(hostname: ../../${hostname}/ssh_host_ed25519_key.pub)
// lib.genAttrs (lib.attrNames outputs.systemConfigs)
(hostname: ../../../ubuntu/${hostname}/ssh_host_ed25519_key.pub);
# Sops needs acess to the keys before the persist dirs are even mounted; so # Sops needs acess to the keys before the persist dirs are even mounted; so
# just persisting the keys won't work, we must point at /persist # just persisting the keys won't work, we must point at /persist
@@ -36,21 +41,23 @@ in {
programs.ssh = { programs.ssh = {
# Each hosts public key # Each hosts public key
knownHosts = lib.genAttrs hosts (hostname: { knownHosts =
publicKeyFile = ../../${hostname}/ssh_host_ed25519_key.pub; lib.mapAttrs (hostname: publicKeyFile: {
extraHostNames = inherit publicKeyFile;
[ extraHostNames =
"${hostname}.m7.rs" [
] "${hostname}.m7.rs"
++ ]
# Alias for localhost if it's the same host ++
(lib.optional (hostname == config.networking.hostName) "localhost") # Alias for localhost if it's the same host
# Alias to m7.rs and git.m7.rs if it's alcyone (lib.optional (hostname == config.networking.hostName) "localhost")
++ (lib.optionals (hostname == "alcyone") [ # Alias to m7.rs and git.m7.rs if it's alcyone
"m7.rs" ++ (lib.optionals (hostname == "alcyone") [
"git.m7.rs" "m7.rs"
]); "git.m7.rs"
}); ]);
})
hostKeyFiles;
}; };
# Passwordless sudo when SSH'ing with keys # Passwordless sudo when SSH'ing with keys
+1
View File
@@ -18,6 +18,7 @@ in {
./greetd.nix ./greetd.nix
./network.nix ./network.nix
./nix.nix ./nix.nix
./openssh.nix
./pam.nix ./pam.nix
./sops.nix ./sops.nix
] ]
+68
View File
@@ -0,0 +1,68 @@
{
outputs,
lib,
systemManagerHostName,
...
}: let
# Every host we know a key for, mapped to the file holding it.
hostKeyFiles =
lib.genAttrs (lib.attrNames outputs.nixosConfigurations)
(hostname: ../../../nixos/${hostname}/ssh_host_ed25519_key.pub)
// lib.genAttrs (lib.attrNames outputs.systemConfigs)
(hostname: ../../${hostname}/ssh_host_ed25519_key.pub);
in {
services.openssh = {
enable = true;
settings = {
# Harden
PasswordAuthentication = false;
PermitRootLogin = "no";
# Automatically remove stale sockets
StreamLocalBindUnlink = "yes";
# Allow forwarding ports to everywhere
GatewayPorts = "clientspecified";
# Let WAYLAND_DISPLAY be forwarded
AcceptEnv = ["WAYLAND_DISPLAY"];
X11Forwarding = true;
};
# Unlike NixOS, nothing generates these: System Manager's openssh module
# runs Ubuntu's /usr/sbin/sshd (so it keeps working with Ubuntu's PAM), and
# openssh-server already created the key at install time. sops reads the
# same file, see ./sops.nix.
hostKeys = [
{
path = "/etc/ssh/ssh_host_ed25519_key";
type = "ed25519";
}
];
};
programs.ssh = {
# Takes over /etc/ssh/ssh_config (Ubuntu's is backed up), which is what
# makes the known hosts below system-wide.
enable = true;
# No default on non-NixOS, and X11Forwarding above asserts on it.
setXAuthLocation = true;
# Each hosts public key
knownHosts =
lib.mapAttrs (hostname: publicKeyFile: {
inherit publicKeyFile;
extraHostNames =
[
"${hostname}.m7.rs"
]
++
# Alias for localhost if it's the same host
(lib.optional (hostname == systemManagerHostName) "localhost")
# Alias to m7.rs and git.m7.rs if it's alcyone
++ (lib.optionals (hostname == "alcyone") [
"m7.rs"
"git.m7.rs"
]);
})
hostKeyFiles;
};
}
@@ -1,5 +1,6 @@
{ {
config, config,
lib,
pkgs, pkgs,
systemManagerHostName, systemManagerHostName,
... ...
@@ -28,6 +29,7 @@ in {
createHome = false; createHome = false;
shell = pkgs.fish; shell = pkgs.fish;
ignoreShellProgramCheck = true; ignoreShellProgramCheck = true;
openssh.authorizedKeys.keys = lib.splitString "\n" (builtins.readFile ../../../../../home/gabriel/ssh.pub);
extraGroups = [ extraGroups = [
"audio" "audio"
"netdev" "netdev"
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFOj95/ELxnTsYKnbaZwHLc9DN4lxZ6TLuOFkdrfHrpn root@electra