Compare commits

..

2 Commits

Author SHA1 Message Date
b7ac7ecbd4 feat: automate SSH config ('known_hosts', 'authorized_keys' ...) 2026-01-17 17:37:37 +01:00
d63f525a9c chore(nixfmt): format 2026-01-17 17:35:38 +01:00
19 changed files with 246 additions and 99 deletions

View File

@@ -50,6 +50,7 @@
nvim, nvim,
}@inputs: }@inputs:
let let
inherit (self) outputs;
lib = inputs.nixpkgs.lib; lib = inputs.nixpkgs.lib;
utils = import ./utils { inherit lib; }; utils = import ./utils { inherit lib; };
hostDirNames = utils.dirNames ./hosts; hostDirNames = utils.dirNames ./hosts;
@@ -67,14 +68,18 @@
host: host:
nixpkgs.lib.nixosSystem { nixpkgs.lib.nixosSystem {
modules = [ ./hosts/${host} ]; modules = [ ./hosts/${host} ];
specialArgs = { inherit inputs; }; specialArgs = {
inherit inputs outputs;
};
} }
); );
homeConfigurations = { homeConfigurations = {
work = home-manager.lib.homeManagerConfiguration { work = home-manager.lib.homeManagerConfiguration {
inherit pkgs; inherit pkgs;
modules = [ ./home/hosts/work ]; modules = [ ./home/hosts/work ];
extraSpecialArgs = { inherit inputs; }; extraSpecialArgs = {
inherit inputs outputs;
};
}; };
}; };
}; };

View File

@@ -14,6 +14,7 @@ in
../../modules/desktop/niri ../../modules/desktop/niri
../../modules/git.nix ../../modules/git.nix
../../modules/k9s.nix ../../modules/k9s.nix
../../modules/ssh.nix
../../modules/taskwarrior.nix ../../modules/taskwarrior.nix
../../modules/keepassxc.nix ../../modules/keepassxc.nix
../../modules/anki.nix ../../modules/anki.nix

View File

@@ -14,6 +14,7 @@ in
../../modules/desktop/niri ../../modules/desktop/niri
../../modules/git.nix ../../modules/git.nix
../../modules/k9s.nix ../../modules/k9s.nix
../../modules/ssh.nix
../../modules/taskwarrior.nix ../../modules/taskwarrior.nix
../../modules/keepassxc.nix ../../modules/keepassxc.nix
../../modules/browser ../../modules/browser

View File

@@ -24,11 +24,11 @@ in
defaultSopsFile = "${inputs.nix-secrets}/secrets.yaml"; defaultSopsFile = "${inputs.nix-secrets}/secrets.yaml";
secrets = { secrets = {
taskwarrior_sync_server_url = {}; taskwarrior_sync_server_url = { };
taskwarrior_sync_server_client_id = {}; taskwarrior_sync_server_client_id = { };
taskwarrior_sync_encryption_secret = {}; taskwarrior_sync_encryption_secret = { };
anki_sync_user = {}; anki_sync_user = { };
anki_sync_key = {}; anki_sync_key = { };
}; };
templates."taskrc.d/sync" = { templates."taskrc.d/sync" = {

View File

@@ -1,4 +1,10 @@
{ config, inputs, lib, pkgs, ... }: {
config,
inputs,
lib,
pkgs,
...
}:
let let
bookmarks = import ./bookmarks.nix; bookmarks = import ./bookmarks.nix;

View File

@@ -1,83 +1,91 @@
{ config, inputs, lib, pkgs, ... }: {
config,
inputs,
lib,
pkgs,
...
}:
let let
bookmarks = import ./bookmarks.nix; bookmarks = import ./bookmarks.nix;
in in
{ {
config = lib.mkIf (config.browser.primary == "librewolf" || config.browser.secondary == "librewolf") { config =
programs.librewolf = { lib.mkIf (config.browser.primary == "librewolf" || config.browser.secondary == "librewolf")
enable = true; {
nativeMessagingHosts = with pkgs; [ programs.librewolf = {
tridactyl-native enable = true;
]; nativeMessagingHosts = with pkgs; [
profiles = { tridactyl-native
default = { ];
settings = { profiles = {
"signon.rememberSignons" = false; default = {
"findbar.highlightAll" = true; settings = {
"extensions.autoDisableScopes" = 0; "signon.rememberSignons" = false;
}; "findbar.highlightAll" = true;
extensions = { "extensions.autoDisableScopes" = 0;
packages = with inputs.firefox-addons.packages.${pkgs.system}; [ };
duckduckgo-privacy-essentials extensions = {
istilldontcareaboutcookies packages = with inputs.firefox-addons.packages.${pkgs.system}; [
libredirect duckduckgo-privacy-essentials
keepassxc-browser istilldontcareaboutcookies
react-devtools libredirect
sponsorblock keepassxc-browser
tridactyl react-devtools
ublock-origin sponsorblock
]; tridactyl
}; ublock-origin
bookmarks = {
force = true;
settings = [
{
toolbar = true;
bookmarks = [
bookmarks.nixos
]; ];
} };
]; bookmarks = {
force = true;
settings = [
{
toolbar = true;
bookmarks = [
bookmarks.nixos
];
}
];
};
};
};
policies = {
DefaultDownloadDirectory = "\${home}/dl";
ExtensionSettings = {
"jid1-ZAdIEUB7XOzOJw@jetpack" = {
default_area = "navbar";
private_browsing = true;
};
"idcac-pub@guus.ninja" = {
default_area = "navbar";
private_browsing = true;
};
"7esoorv3@alefvanoon.anonaddy.me" = {
default_area = "navbar";
};
"keepassxc-browser@keepassxc.org" = {
default_area = "navbar";
private_browsing = true;
};
"@react-devtools" = {
default_area = "navbar";
private_browsing = true;
};
"sponsorBlocker@ajay.app" = {
default_area = "navbar";
private_browsing = true;
};
"tridactyl.vim@cmcaine.co.uk".settings = {
private_browsing = true;
};
"uBlock0@raymondhill.net".settings = {
default_area = "navbar";
private_browsing = true;
};
};
}; };
}; };
}; };
policies = {
DefaultDownloadDirectory = "\${home}/dl";
ExtensionSettings = {
"jid1-ZAdIEUB7XOzOJw@jetpack" = {
default_area = "navbar";
private_browsing = true;
};
"idcac-pub@guus.ninja" = {
default_area = "navbar";
private_browsing = true;
};
"7esoorv3@alefvanoon.anonaddy.me" = {
default_area = "navbar";
};
"keepassxc-browser@keepassxc.org" = {
default_area = "navbar";
private_browsing = true;
};
"@react-devtools" = {
default_area = "navbar";
private_browsing = true;
};
"sponsorBlocker@ajay.app" = {
default_area = "navbar";
private_browsing = true;
};
"tridactyl.vim@cmcaine.co.uk".settings = {
private_browsing = true;
};
"uBlock0@raymondhill.net".settings = {
default_area = "navbar";
private_browsing = true;
};
};
};
};
};
} }

View File

@@ -59,17 +59,16 @@ in
''; '';
}; };
home.file = home.file = {
{ ".inputrc".source = dotsPath + "/.inputrc";
".inputrc".source = dotsPath + "/.inputrc"; ".bashrc.d/prompt".source = dotsPath + "/.bashrc.d/prompt";
".bashrc.d/prompt".source = dotsPath + "/.bashrc.d/prompt"; ".bashrc.d/editor".source = dotsPath + "/.bashrc.d/editor";
".bashrc.d/editor".source = dotsPath + "/.bashrc.d/editor"; }
} // lib.optionalAttrs cfg.aliases.all {
// lib.optionalAttrs cfg.aliases.all { ".bash_aliases/all".source = dotsPath + "/.bash_aliases/all";
".bash_aliases/all".source = dotsPath + "/.bash_aliases/all"; }
} // lib.optionalAttrs cfg.aliases.lang-js {
// lib.optionalAttrs cfg.aliases.lang-js { ".bash_aliases/lang-js".source = dotsPath + "/.bash_aliases/lang-js";
".bash_aliases/lang-js".source = dotsPath + "/.bash_aliases/lang-js"; };
};
}; };
} }

25
home/modules/ssh.nix Normal file
View File

@@ -0,0 +1,25 @@
{
outputs,
lib,
...
}:
let
nixosConfigs = builtins.attrNames outputs.nixosConfigurations;
homeConfigs = map (n: lib.last (lib.splitString "@" n)) (
builtins.attrNames outputs.homeConfigurations
);
allHosts = lib.unique (homeConfigs ++ nixosConfigs);
hostsWithKeys = lib.filter (
hostname: builtins.pathExists ../../hosts/${hostname}/ssh_host.pub
) allHosts;
in
{
programs.ssh = {
enable = true;
enableDefaultConfig = false;
matchBlocks = lib.genAttrs hostsWithKeys (hostname: {
host = hostname;
});
};
}

1
home/ssh.pub Normal file
View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzP1PjIDb1tN9nhPOK88HYDtTNk9SN9ZpEem2id49Fa h@astyanax

View File

@@ -1,6 +1,7 @@
{ {
lib, lib,
inputs, inputs,
outputs,
config, config,
pkgs, pkgs,
... ...
@@ -81,7 +82,9 @@ in
home-manager = { home-manager = {
useGlobalPkgs = true; useGlobalPkgs = true;
useUserPackages = true; useUserPackages = true;
extraSpecialArgs = { inherit inputs; }; extraSpecialArgs = {
inherit inputs outputs;
};
users.${username} = import ../../home/hosts/andromache { users.${username} = import ../../home/hosts/andromache {
inherit lib; inherit lib;
inherit inputs; inherit inputs;
@@ -90,6 +93,8 @@ in
}; };
}; };
ssh.authorizedHosts = [ "astyanax" ];
services.xserver = { services.xserver = {
videoDrivers = [ "nvidia" ]; videoDrivers = [ "nvidia" ];
}; };

View File

@@ -1,6 +1,7 @@
{ {
lib, lib,
inputs, inputs,
outputs,
config, config,
pkgs, pkgs,
... ...
@@ -75,7 +76,9 @@ in
home-manager = { home-manager = {
useGlobalPkgs = true; useGlobalPkgs = true;
useUserPackages = true; useUserPackages = true;
extraSpecialArgs = { inherit inputs; }; extraSpecialArgs = {
inherit inputs outputs;
};
users.${username} = import ../../home/hosts/astyanax { users.${username} = import ../../home/hosts/astyanax {
inherit inputs; inherit inputs;
inherit config; inherit config;
@@ -88,6 +91,8 @@ in
hostId = "80eef97e"; hostId = "80eef97e";
}; };
ssh.authorizedHosts = [ "andromache" ];
services = { services = {
fwupd.enable = true; fwupd.enable = true;
openssh = { openssh = {

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO8+UOyZbvQeHfFfYox3SQi42KJ0S3RZj79iswSsZeFy root@nixos

View File

@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzP1PjIDb1tN9nhPOK88HYDtTNk9SN9ZpEem2id49Fa h@astyanax

View File

@@ -1,4 +1,11 @@
{ pkgs, ... }: {
lib,
inputs,
outputs,
config,
pkgs,
...
}:
# Also see <https://wiki.nixos.org/wiki/Install_NixOS_on_Hetzner_Cloud> # Also see <https://wiki.nixos.org/wiki/Install_NixOS_on_Hetzner_Cloud>
@@ -31,12 +38,14 @@
username = { username = {
isNormalUser = true; isNormalUser = true;
extraGroups = [ "wheel" ]; extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOOXPEhdKOVnb6mkeLLUcFGt+mnUR5pMie17JtjrxwgO h@andromache"
];
}; };
}; };
ssh = {
username = "username";
authorizedHosts = [ "andromache" ];
};
security.sudo.wheelNeedsPassword = false; security.sudo.wheelNeedsPassword = false;
networking = { networking = {
@@ -57,4 +66,6 @@
enable = true; enable = true;
harden = true; harden = true;
}; };
networking.hostName = "hecuba";
} }

View File

@@ -1,6 +1,7 @@
{ {
lib, lib,
inputs, inputs,
outputs,
config, config,
pkgs, pkgs,
... ...
@@ -58,7 +59,9 @@ in
home-manager = { home-manager = {
useGlobalPkgs = true; useGlobalPkgs = true;
useUserPackages = true; useUserPackages = true;
extraSpecialArgs = { inherit inputs; }; extraSpecialArgs = {
inherit inputs outputs;
};
users.${username} = import ../../home/hosts/vm { users.${username} = import ../../home/hosts/vm {
inherit inputs; inherit inputs;
inherit config; inherit config;

View File

@@ -0,0 +1,24 @@
{ lib, config, ... }:
{
options.ssh = {
authorizedHosts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
username = lib.mkOption {
type = lib.types.str;
default = "h";
};
};
# auto generate authorized_keys from `authorizedHosts`
config.users.users.${config.ssh.username}.openssh.authorizedKeys.keys = lib.flatten (
map (
hostname:
let
keyFile = ../../hosts/${hostname}/ssh_user.pub;
in
lib.optionals (builtins.pathExists keyFile) (lib.splitString "\n" (builtins.readFile keyFile))
) config.ssh.authorizedHosts
);
}

View File

@@ -0,0 +1,24 @@
{ lib, config, ... }:
let
username = config.ssh.username;
in
{
# auto extract SSH keys
system.activationScripts.extractSshKeys = lib.stringAfter [ "etc" ] ''
HOST_KEY="/etc/ssh/ssh_host_ed25519_key.pub"
HOST_DIR="/home/${username}/nix/hosts/${config.networking.hostName}"
if [ -f "$HOST_KEY" ] && [ -d "$HOST_DIR" ]; then
cp "$HOST_KEY" "$HOST_DIR/ssh_host.pub"
chown ${username}:users "$HOST_DIR/ssh_host.pub"
chmod 644 "$HOST_DIR/ssh_host.pub"
fi
USER_KEY="/home/${username}/.ssh/id_ed25519.pub"
if [ -f "$USER_KEY" ] && [ -d "$HOST_DIR" ]; then
cp "$USER_KEY" "$HOST_DIR/ssh_user.pub"
chown ${username}:users "$HOST_DIR/ssh_user.pub"
chmod 644 "$HOST_DIR/ssh_user.pub"
fi
'';
}

View File

@@ -4,9 +4,17 @@ let
cfg = config.services.openssh; cfg = config.services.openssh;
in in
{ {
imports = [
./known-hosts.nix
./authorized-keys.nix
./extract-keys.nix
];
options.services.openssh.harden = mkEnableOption "harden ssh server configuration"; options.services.openssh.harden = mkEnableOption "harden ssh server configuration";
config = { config = {
networking.firewall.allowedTCPPorts = [ 22 ]; networking.firewall.allowedTCPPorts = [ 22 ];
services.openssh.settings = optionalAttrs cfg.harden { services.openssh.settings = optionalAttrs cfg.harden {
PermitRootLogin = "no"; PermitRootLogin = "no";
PasswordAuthentication = false; PasswordAuthentication = false;

View File

@@ -0,0 +1,19 @@
{
lib,
config,
outputs,
...
}:
let
hosts = lib.attrNames outputs.nixosConfigurations;
hostsWithKeys = lib.filter (
hostname: builtins.pathExists ../../hosts/${hostname}/ssh_host.pub
) hosts;
in
{
# auto generate known_hosts for all hosts in flake
programs.ssh.knownHosts = lib.genAttrs hostsWithKeys (hostname: {
publicKeyFile = ../../hosts/${hostname}/ssh_host.pub;
extraHostNames = lib.optional (hostname == config.networking.hostName) "localhost";
});
}