Compare commits
2 Commits
e2fd47aa58
...
c90d368432
| Author | SHA1 | Date | |
|---|---|---|---|
| c90d368432 | |||
| a787840ce2 |
+5
-5
@@ -47,7 +47,7 @@ Leave upstream `services.*`, `networking.*`, `home.*`, etc. alone.
|
|||||||
|
|
||||||
Aggregates: `nixosModules.system` and `nixosModules.desktop` import their leaves. Host configs import those stacks and set options — they shouldn't reimplement whole subsystems.
|
Aggregates: `nixosModules.system` and `nixosModules.desktop` import their leaves. Host configs import those stacks and set options — they shouldn't reimplement whole subsystems.
|
||||||
|
|
||||||
**Home** — files under `modules/wisdom/`. Baseline is `homeManagerModules.wisdom` (`chiasson.home.enable`, wired via `chiasson.desktop.homeManager.bundleWisdom`). Other `wisdom*` slices auto-wire once per user via `lib.wisdomCatalogExtraModules self` (`modules/lib/wisdom-catalog.nix`); hosts only set matching `chiasson.home.*.enable` toggles — no re-import in `home.nix`.
|
**Home** — files under `modules/wisdom/`. Baseline is `homeManagerModules.wisdom` (`chiasson.home.enable`, wired via `chiasson.desktop.homeManager.bundleWisdom`). Other `wisdom*` slices auto-wire once per user via `lib.wisdomCatalogExtraModules self` (`modules/desktop/options.nix`); hosts only set matching `chiasson.home.*.enable` toggles — no re-import in `home.nix`.
|
||||||
|
|
||||||
User apps / dotfiles → wisdom. Daemons, firewall, kernel → NixOS. Sometimes both (LocalSend: HM installs, `systemLocalsend` opens the firewall).
|
User apps / dotfiles → wisdom. Daemons, firewall, kernel → NixOS. Sometimes both (LocalSend: HM installs, `systemLocalsend` opens the firewall).
|
||||||
|
|
||||||
@@ -76,9 +76,9 @@ SSH authentication has two independent sides:
|
|||||||
| **Client** (connecting from) | identity private keys | "Here's proof I own key K" |
|
| **Client** (connecting from) | identity private keys | "Here's proof I own key K" |
|
||||||
| **Server** (connecting to) | `authorized_keys` | "Do I trust key K?" |
|
| **Server** (connecting to) | `authorized_keys` | "Do I trust key K?" |
|
||||||
|
|
||||||
A key is just a cryptographic identity — it's not bound to a host or a machine account name. The model is **one key per user account**: each catalog account (`olivier`, `server`, `builder`) has its own keypair in `modules/lib/ssh-inventory.nix`, regardless of which machine that account runs on. Concretely: when `olivier@14900k` sshes to `server@r5500`, OpenSSH routes via a `Match user server` block (generated from `chiasson.ssh.outbound.rbw.extraIdentities`) → `IdentityFile ~/.ssh/id_ed25519_server.pub` (written from `users.server.publicKey`) to ask the rbw agent for the `server` private key; r5500's `server` `authorized_keys` holds the matching server pubkey. olivier's catalog default sets `extraIdentities = [ "server" "builder" ]` so `ssh <account>@<host>` Just Works for every catalog role. We also support `from="ip,cidr"` constraints per account to scope which source IPs may authenticate as it.
|
A key is just a cryptographic identity — it's not bound to a host or a machine account name. The model is **one key per user account**: each catalog account (`olivier`, `server`, `builder`) has its own keypair in `modules/ssh/inventory.nix`, regardless of which machine that account runs on. Concretely: when `olivier@14900k` sshes to `server@r5500`, OpenSSH routes via a `Match user server` block (generated from `chiasson.ssh.outbound.rbw.extraIdentities`) → `IdentityFile ~/.ssh/id_ed25519_server.pub` (written from `users.server.publicKey`) to ask the rbw agent for the `server` private key; r5500's `server` `authorized_keys` holds the matching server pubkey. olivier's catalog default sets `extraIdentities = [ "server" "builder" ]` so `ssh <account>@<host>` Just Works for every catalog role. We also support `from="ip,cidr"` constraints per account to scope which source IPs may authenticate as it.
|
||||||
|
|
||||||
This repo enforces "one key per user": every user has one ed25519 keypair, the private key in Bitwarden, the public key inline in `modules/lib/ssh-inventory.nix`. On SSH connect:
|
This repo enforces "one key per user": every user has one ed25519 keypair, the private key in Bitwarden, the public key inline in `modules/ssh/inventory.nix`. On SSH connect:
|
||||||
|
|
||||||
1. `~/.ssh/config` (managed by home-manager) sets `IdentityAgent SSH_AUTH_SOCK` and `IdentityFile ~/.ssh/id_ed25519_<user>.pub` for every host block.
|
1. `~/.ssh/config` (managed by home-manager) sets `IdentityAgent SSH_AUTH_SOCK` and `IdentityFile ~/.ssh/id_ed25519_<user>.pub` for every host block.
|
||||||
2. OpenSSH reads the `.pub` file as a **filter** against the agent (OpenSSH 7.3+ trick — `.pub` as IdentityFile tells the agent "give me the private key matching this pub"), so even with multiple keys loaded, only the matching one is tried. This is why the old "too many auth failures" symptom is gone by construction.
|
2. OpenSSH reads the `.pub` file as a **filter** against the agent (OpenSSH 7.3+ trick — `.pub` as IdentityFile tells the agent "give me the private key matching this pub"), so even with multiple keys loaded, only the matching one is tried. This is why the old "too many auth failures" symptom is gone by construction.
|
||||||
@@ -105,7 +105,7 @@ ssh root@nix-server nixos-rebuild switch --flake .#nix-server
|
|||||||
|
|
||||||
### Adding a host
|
### Adding a host
|
||||||
|
|
||||||
Edit `modules/lib/ssh-inventory.nix` and add:
|
Edit `modules/ssh/inventory.nix` and add:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
hosts."newhost" = {
|
hosts."newhost" = {
|
||||||
@@ -119,7 +119,7 @@ Then add `self.nixosModules.<host>Configuration` to `modules/deploy/navi.nix`.
|
|||||||
### Adding a catalog user
|
### Adding a catalog user
|
||||||
|
|
||||||
1. Generate a keypair: `rbw gen ssh-key <name>`.
|
1. Generate a keypair: `rbw gen ssh-key <name>`.
|
||||||
2. Add a `users.<name> = { publicKey = "ssh-ed25519 …"; };` line under `users` in `modules/lib/ssh-inventory.nix`.
|
2. Add a `users.<name> = { publicKey = "ssh-ed25519 …"; };` line under `users` in `modules/ssh/inventory.nix`.
|
||||||
3. Add a `<name> = { isNormalUser = true; … ssh.inbound.enable = true; ssh.inbound.authorizedHosts = "all"; }` entry under `chiasson.users.catalog` in `modules/system/users.nix`.
|
3. Add a `<name> = { isNormalUser = true; … ssh.inbound.enable = true; ssh.inbound.authorizedHosts = "all"; }` entry under `chiasson.users.catalog` in `modules/system/users.nix`.
|
||||||
4. Enable on every host that needs that user, e.g.:
|
4. Enable on every host that needs that user, e.g.:
|
||||||
|
|
||||||
|
|||||||
+32
-1
@@ -98,9 +98,40 @@ let
|
|||||||
metaNixpkgs = import inputs.nixpkgs {
|
metaNixpkgs = import inputs.nixpkgs {
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
};
|
};
|
||||||
|
# Build a raw Navi hive attrset from host specs + deployment targets.
|
||||||
|
# `inputs.navi.lib.makeHive` turns the result into `flake.naviHive`.
|
||||||
|
mkNaviHiveConfig =
|
||||||
|
{
|
||||||
|
metaNixpkgs,
|
||||||
|
hostSpecs,
|
||||||
|
deployments,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
deployNodes = lib.filterAttrs (name: _: deployments ? ${name}) hostSpecs;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
meta = {
|
||||||
|
nixpkgs = metaNixpkgs;
|
||||||
|
nodeNixpkgs = lib.mapAttrs (
|
||||||
|
name: spec:
|
||||||
|
import inputs.nixpkgs {
|
||||||
|
system = spec.system;
|
||||||
|
}
|
||||||
|
) deployNodes;
|
||||||
|
nodeSpecialArgs = lib.mapAttrs (_: spec: spec.specialArgs) deployNodes;
|
||||||
|
allowApplyAll = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// lib.mapAttrs (
|
||||||
|
name: spec:
|
||||||
|
{
|
||||||
|
imports = spec.modules or [ spec.configuration ];
|
||||||
|
deployment = deployments.${name};
|
||||||
|
}
|
||||||
|
) deployNodes;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.navi = self.lib.mkNaviHiveConfig {
|
flake.navi = mkNaviHiveConfig {
|
||||||
inherit metaNixpkgs hostSpecs deployments;
|
inherit metaNixpkgs hostSpecs deployments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+34
-12
@@ -1,4 +1,19 @@
|
|||||||
{ ... }: {
|
{ lib, ... }: {
|
||||||
|
# Resolve `wisdom*` HM slices for NixOS `extraModules` (`self` is not an HM specialArg).
|
||||||
|
# Slices are gated by `chiasson.home.*.enable`; hosts only flip toggles in `home.nix`.
|
||||||
|
# Lives here (not `modules/lib/`) because `hosts/desktop-home-base.nix` consumes it and
|
||||||
|
# fragment eval order requires the definition to sort before `hosts/`.
|
||||||
|
flake.lib.wisdomCatalogExtraModules =
|
||||||
|
self:
|
||||||
|
let
|
||||||
|
names = lib.sort builtins.lessThan (
|
||||||
|
lib.filter (n: lib.hasPrefix "wisdom" n && n != "wisdom" && n != "wisdomShellBash") (
|
||||||
|
builtins.attrNames self.homeManagerModules
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
map (name: self.homeManagerModules.${name}) names;
|
||||||
|
|
||||||
flake.nixosModules.desktopOptions =
|
flake.nixosModules.desktopOptions =
|
||||||
{ config, options, lib, pkgs, self, inputs, ... }:
|
{ config, options, lib, pkgs, self, inputs, ... }:
|
||||||
let
|
let
|
||||||
@@ -34,11 +49,13 @@
|
|||||||
{
|
{
|
||||||
options.chiasson.desktop = {
|
options.chiasson.desktop = {
|
||||||
defaultSession = lib.mkOption {
|
defaultSession = lib.mkOption {
|
||||||
type = lib.types.nullOr (lib.types.enum [
|
type = lib.types.nullOr (
|
||||||
|
lib.types.enum [
|
||||||
"hyprland"
|
"hyprland"
|
||||||
"niri"
|
"niri"
|
||||||
"plasma"
|
"plasma"
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
example = "niri";
|
example = "niri";
|
||||||
description = ''
|
description = ''
|
||||||
@@ -56,10 +73,12 @@
|
|||||||
|
|
||||||
displayManager = {
|
displayManager = {
|
||||||
variant = lib.mkOption {
|
variant = lib.mkOption {
|
||||||
type = lib.types.nullOr (lib.types.enum [
|
type = lib.types.nullOr (
|
||||||
|
lib.types.enum [
|
||||||
"sddm"
|
"sddm"
|
||||||
"dankgreeter"
|
"dankgreeter"
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
SDDM vs DankGreeter (greetd + DMS — [docs](https://danklinux.com/docs/dankgreeter/nixos-flake)).
|
SDDM vs DankGreeter (greetd + DMS — [docs](https://danklinux.com/docs/dankgreeter/nixos-flake)).
|
||||||
@@ -80,9 +99,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
displayManager.sddm = {
|
displayManager.sddm = {
|
||||||
wayland.enable = lib.mkEnableOption ''
|
wayland.enable =
|
||||||
|
lib.mkEnableOption ''
|
||||||
SDDM greeter on Wayland (nicer on HiDPI; turn off if the greeter glitches on your GPU).
|
SDDM greeter on Wayland (nicer on HiDPI; turn off if the greeter glitches on your GPU).
|
||||||
'' // {
|
''
|
||||||
|
// {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -159,10 +180,12 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
keyring = {
|
keyring = {
|
||||||
enable = lib.mkEnableOption ''
|
enable =
|
||||||
|
lib.mkEnableOption ''
|
||||||
gnome-keyring + pam (login + sddm or greetd) + HM user service + `gcr` + `services.xserver.updateDbusEnvironment`.
|
gnome-keyring + pam (login + sddm or greetd) + HM user service + `gcr` + `services.xserver.updateDbusEnvironment`.
|
||||||
niri/hyprland: `dbus-update-activation-environment` at compositor start so libsecret/Electron see `WAYLAND_DISPLAY`.
|
niri/hyprland: `dbus-update-activation-environment` at compositor start so libsecret/Electron see `WAYLAND_DISPLAY`.
|
||||||
'' // {
|
''
|
||||||
|
// {
|
||||||
default = true;
|
default = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -184,8 +207,7 @@
|
|||||||
message = "chiasson.desktop.defaultSession = \"plasma\" requires chiasson.desktop.plasma.enable = true.";
|
message = "chiasson.desktop.defaultSession = \"plasma\" requires chiasson.desktop.plasma.enable = true.";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion =
|
assertion = cfg.displayManager.variant != "dankgreeter" || cfg.hyprland.enable || cfg.niri.enable;
|
||||||
cfg.displayManager.variant != "dankgreeter" || cfg.hyprland.enable || cfg.niri.enable;
|
|
||||||
message = "chiasson.desktop.displayManager.variant = \"dankgreeter\" requires chiasson.desktop.hyprland or chiasson.desktop.niri.";
|
message = "chiasson.desktop.displayManager.variant = \"dankgreeter\" requires chiasson.desktop.hyprland or chiasson.desktop.niri.";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -210,7 +232,7 @@
|
|||||||
(lib.mkIf (dmsEnabled && hmAvailable) {
|
(lib.mkIf (dmsEnabled && hmAvailable) {
|
||||||
"home-manager".sharedModules = [ self.homeManagerModules.desktopShellDms ];
|
"home-manager".sharedModules = [ self.homeManagerModules.desktopShellDms ];
|
||||||
})
|
})
|
||||||
(lib.mkIf (hmAvailable && (dmsEnabled || cfg.niri.enable)) {
|
(lib.mkIf hmAvailable {
|
||||||
"home-manager".extraSpecialArgs = { inherit inputs; };
|
"home-manager".extraSpecialArgs = { inherit inputs; };
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
spotify.openDiscoveryFirewall = true;
|
spotify.openDiscoveryFirewall = true;
|
||||||
pokeclicker.enable = true;
|
pokeclicker.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,18 +4,5 @@
|
|||||||
{ self, ... }:
|
{ self, ... }:
|
||||||
{
|
{
|
||||||
imports = [ self.nixosModules.desktopHomeBase ];
|
imports = [ self.nixosModules.desktopHomeBase ];
|
||||||
|
|
||||||
# Host-only HM overrides (tablet apps, toggles off from desktop-home-base, …).
|
|
||||||
chiasson.users.extraModules.olivier = [
|
|
||||||
# {
|
|
||||||
# chiasson.home = {
|
|
||||||
# # editors.kate.enable = true;
|
|
||||||
# };
|
|
||||||
# }
|
|
||||||
# (
|
|
||||||
# { pkgs, ... }:
|
|
||||||
# { home.packages = with pkgs; [ ]; }
|
|
||||||
# )
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,7 @@
|
|||||||
chiasson.users.extraModules.olivier = [
|
chiasson.users.extraModules.olivier = [
|
||||||
{
|
{
|
||||||
chiasson.home = {
|
chiasson.home = {
|
||||||
browsers = {
|
browsers.edge.enable = true;
|
||||||
edge.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
apps = {
|
apps = {
|
||||||
discord.enable = true;
|
discord.enable = true;
|
||||||
@@ -19,6 +17,5 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
|
|
||||||
chiasson.users.extraModules.olivier = [
|
chiasson.users.extraModules.olivier = [
|
||||||
{
|
{
|
||||||
chiasson.home = {
|
chiasson.home.hardware.uconsoleGamepad.enable = true;
|
||||||
hardware.uconsoleGamepad.enable = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
# Build a raw Navi hive attrset from host specs + deployment targets.
|
|
||||||
# Call `inputs.navi.lib.makeHive` on the result to produce `flake.naviHive`.
|
|
||||||
{ lib, inputs, ... }: {
|
|
||||||
flake.lib.mkNaviHiveConfig =
|
|
||||||
{
|
|
||||||
metaNixpkgs,
|
|
||||||
hostSpecs,
|
|
||||||
deployments,
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
deployNodes = lib.filterAttrs (name: _: deployments ? ${name}) hostSpecs;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
meta = {
|
|
||||||
nixpkgs = metaNixpkgs;
|
|
||||||
nodeNixpkgs = lib.mapAttrs (
|
|
||||||
name: spec:
|
|
||||||
import inputs.nixpkgs {
|
|
||||||
system = spec.system;
|
|
||||||
}
|
|
||||||
) deployNodes;
|
|
||||||
nodeSpecialArgs = lib.mapAttrs (_: spec: spec.specialArgs) deployNodes;
|
|
||||||
allowApplyAll = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// lib.mapAttrs (
|
|
||||||
name: spec:
|
|
||||||
{
|
|
||||||
imports = spec.modules or [ spec.configuration ];
|
|
||||||
deployment = deployments.${name};
|
|
||||||
}
|
|
||||||
) deployNodes;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{ ... }: {
|
|
||||||
flake.lib.rbwSshSocket =
|
|
||||||
let
|
|
||||||
# Bash/Fish init snippets — used by wisdom/shells/{bash,fish}.nix.
|
|
||||||
bashSnippet = ''
|
|
||||||
if [ -z "''${SSH_AUTH_SOCK:-}" ]; then
|
|
||||||
if [ -n "''${XDG_RUNTIME_DIR:-}" ]; then
|
|
||||||
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/rbw/ssh-agent-socket"
|
|
||||||
else
|
|
||||||
export SSH_AUTH_SOCK="/run/user/$(id -u)/rbw/ssh-agent-socket"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
fishSnippet =
|
|
||||||
pkgs: ''
|
|
||||||
if test -z "$SSH_AUTH_SOCK"
|
|
||||||
if test -n "$XDG_RUNTIME_DIR"
|
|
||||||
set -gx SSH_AUTH_SOCK "$XDG_RUNTIME_DIR/rbw/ssh-agent-socket"
|
|
||||||
else
|
|
||||||
set -l _hm_uid (${pkgs.coreutils}/bin/id -u)
|
|
||||||
set -gx SSH_AUTH_SOCK "/run/user/$_hm_uid/rbw/ssh-agent-socket"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
inherit bashSnippet fishSnippet;
|
|
||||||
# Used by home-manager modules to expose SSH_AUTH_SOCK to GUI apps
|
|
||||||
# and HM-managed shells declaratively (no activation script needed).
|
|
||||||
sessionVariable = "$XDG_RUNTIME_DIR/rbw/ssh-agent-socket";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
# Pure helpers: catalog → NixOS/HM/SSH shapes (`self.lib.usersMerge lib`).
|
|
||||||
{ ... }: {
|
|
||||||
flake.lib.usersMerge =
|
|
||||||
lib:
|
|
||||||
let
|
|
||||||
userHm = user: user.homeManager or { };
|
|
||||||
userSsh = user: user.ssh or { };
|
|
||||||
in
|
|
||||||
rec {
|
|
||||||
resolveHomeManagerModule =
|
|
||||||
moduleSpec:
|
|
||||||
let
|
|
||||||
t = builtins.typeOf moduleSpec;
|
|
||||||
in
|
|
||||||
if t == "path" || t == "string" then import moduleSpec else moduleSpec;
|
|
||||||
|
|
||||||
selectedUsersAttr =
|
|
||||||
{ catalog, enabled, hostOverrides }:
|
|
||||||
lib.listToAttrs (
|
|
||||||
map (name: {
|
|
||||||
inherit name;
|
|
||||||
value = lib.recursiveUpdate catalog.${name} (hostOverrides.${name} or { });
|
|
||||||
}) enabled
|
|
||||||
);
|
|
||||||
|
|
||||||
missingEnabledNames = catalog: enabled: builtins.filter (name: !(builtins.hasAttr name catalog)) enabled;
|
|
||||||
|
|
||||||
strayHomeUserKeys = homeUsers: enabled:
|
|
||||||
builtins.filter (k: !(builtins.elem k enabled)) (builtins.attrNames homeUsers);
|
|
||||||
|
|
||||||
mkNixosUser =
|
|
||||||
name: user:
|
|
||||||
{
|
|
||||||
isNormalUser = user.isNormalUser or true;
|
|
||||||
description = user.description or name;
|
|
||||||
extraGroups = user.extraGroups or [ ];
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (user ? hashedPasswordFile && user.hashedPasswordFile != null) {
|
|
||||||
hashedPasswordFile = user.hashedPasswordFile;
|
|
||||||
};
|
|
||||||
|
|
||||||
hmWiredNames =
|
|
||||||
selectedUsers:
|
|
||||||
lib.attrNames (
|
|
||||||
lib.filterAttrs (_: user:
|
|
||||||
let
|
|
||||||
hm = userHm user;
|
|
||||||
in
|
|
||||||
(hm.enable or false) && (hm.module or null) != null
|
|
||||||
) selectedUsers
|
|
||||||
);
|
|
||||||
|
|
||||||
rbwOutboundSnippet =
|
|
||||||
name: user:
|
|
||||||
let
|
|
||||||
outboundCfg = ((userSsh user).outbound or { }).rbw or { };
|
|
||||||
in
|
|
||||||
lib.mkIf (outboundCfg.enable or false) {
|
|
||||||
chiasson.ssh.outbound.rbw.enable = true;
|
|
||||||
chiasson.ssh.outbound.rbw.user = name;
|
|
||||||
chiasson.ssh.outbound.rbw.hosts =
|
|
||||||
if (outboundCfg.hosts or "all") == "all" then [ "all" ] else outboundCfg.hosts;
|
|
||||||
chiasson.ssh.outbound.rbw.extraIdentities = outboundCfg.extraIdentities or [ ];
|
|
||||||
};
|
|
||||||
|
|
||||||
mkHmUserModule =
|
|
||||||
{ name, user, hostExtraModules }:
|
|
||||||
let
|
|
||||||
hm = userHm user;
|
|
||||||
hmModule = resolveHomeManagerModule hm.module;
|
|
||||||
in
|
|
||||||
lib.mkMerge (
|
|
||||||
[
|
|
||||||
hmModule
|
|
||||||
(rbwOutboundSnippet name user)
|
|
||||||
]
|
|
||||||
++ (hm.extraModules or [ ])
|
|
||||||
++ hostExtraModules
|
|
||||||
);
|
|
||||||
|
|
||||||
inboundAuthorizedOrNull =
|
|
||||||
user:
|
|
||||||
let
|
|
||||||
inboundCfg = (userSsh user).inbound or { };
|
|
||||||
in
|
|
||||||
if !(inboundCfg.enable or false) then
|
|
||||||
null
|
|
||||||
else if (inboundCfg.authorizedHosts or "all") == "all" then
|
|
||||||
"all"
|
|
||||||
else
|
|
||||||
inboundCfg.authorizedHosts;
|
|
||||||
|
|
||||||
inboundHostsAttr =
|
|
||||||
selectedUsers:
|
|
||||||
lib.pipe selectedUsers [
|
|
||||||
(lib.mapAttrs (_: inboundAuthorizedOrNull))
|
|
||||||
(lib.filterAttrs (_: v: v != null))
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Resolve `wisdom*` HM slices for NixOS `extraModules` (`self` is not an HM specialArg).
|
|
||||||
# Slices are gated by `chiasson.home.*.enable`; hosts only flip toggles in `home.nix`.
|
|
||||||
{ lib, ... }: {
|
|
||||||
flake.lib.wisdomCatalogExtraModules =
|
|
||||||
self:
|
|
||||||
let
|
|
||||||
names = lib.sort builtins.lessThan (
|
|
||||||
lib.filter (
|
|
||||||
n:
|
|
||||||
lib.hasPrefix "wisdom" n
|
|
||||||
&& n != "wisdom"
|
|
||||||
&& n != "wisdomShellBash"
|
|
||||||
) (builtins.attrNames self.homeManagerModules)
|
|
||||||
);
|
|
||||||
in
|
|
||||||
map (name: self.homeManagerModules.${name}) names;
|
|
||||||
}
|
|
||||||
@@ -7,10 +7,7 @@
|
|||||||
# Resolve which hosts to emit blocks for, and which user identity to
|
# Resolve which hosts to emit blocks for, and which user identity to
|
||||||
# use as the IdentityFile filter against the rbw agent.
|
# use as the IdentityFile filter against the rbw agent.
|
||||||
selectedHostNames =
|
selectedHostNames =
|
||||||
if cfg.hosts == [ "all" ] then
|
if cfg.hosts == [ "all" ] then builtins.attrNames inventory.activeHosts else cfg.hosts;
|
||||||
builtins.attrNames inventory.activeHosts
|
|
||||||
else
|
|
||||||
cfg.hosts;
|
|
||||||
missingHosts = builtins.filter (name: !(builtins.hasAttr name inventory.hosts)) selectedHostNames;
|
missingHosts = builtins.filter (name: !(builtins.hasAttr name inventory.hosts)) selectedHostNames;
|
||||||
# Resolve to the actual host attrs for the template. The "all" case
|
# Resolve to the actual host attrs for the template. The "all" case
|
||||||
# reuses `activeHosts` directly instead of rebuilding the same attrset.
|
# reuses `activeHosts` directly instead of rebuilding the same attrset.
|
||||||
@@ -18,20 +15,21 @@
|
|||||||
if cfg.hosts == [ "all" ] then
|
if cfg.hosts == [ "all" ] then
|
||||||
inventory.activeHosts
|
inventory.activeHosts
|
||||||
else
|
else
|
||||||
builtins.listToAttrs (map (n: { name = n; value = inventory.hosts.${n}; }) selectedHostNames);
|
builtins.listToAttrs (
|
||||||
|
map (n: {
|
||||||
|
name = n;
|
||||||
|
value = inventory.hosts.${n};
|
||||||
|
}) selectedHostNames
|
||||||
|
);
|
||||||
# All identities this HM user may authenticate AS: cfg.user ∪
|
# All identities this HM user may authenticate AS: cfg.user ∪
|
||||||
# extraIdentities. `cfg.user` can be null (e.g. user not in inventory
|
# extraIdentities. `cfg.user` can be null (e.g. user not in inventory
|
||||||
# yet) — in that case the Host-block IdentityFile line is suppressed
|
# yet) — in that case the Host-block IdentityFile line is suppressed
|
||||||
# and cross-account SSH is wired from extraIdentities alone.
|
# and cross-account SSH is wired from extraIdentities alone.
|
||||||
effectiveIdentities = lib.filter (n: n != null) ([ cfg.user ] ++ cfg.extraIdentities);
|
effectiveIdentities = lib.filter (n: n != null) ([ cfg.user ] ++ cfg.extraIdentities);
|
||||||
defaultUserHasKey =
|
defaultUserHasKey = cfg.user == null || (inventory.users.${cfg.user}.publicKey or "") != "";
|
||||||
cfg.user == null
|
|
||||||
|| (inventory.users.${cfg.user}.publicKey or "") != "";
|
|
||||||
# Each extra identity must have a pubkey in the inventory. Dropping
|
# Each extra identity must have a pubkey in the inventory. Dropping
|
||||||
# it silently would produce a dead Match block — fail the build.
|
# it silently would produce a dead Match block — fail the build.
|
||||||
missingExtraKeys = lib.filter
|
missingExtraKeys = lib.filter (n: (inventory.users.${n}.publicKey or "") == "") cfg.extraIdentities;
|
||||||
(n: (inventory.users.${n}.publicKey or "") == "")
|
|
||||||
cfg.extraIdentities;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.chiasson.ssh.outbound.rbw = {
|
options.chiasson.ssh.outbound.rbw = {
|
||||||
@@ -64,11 +62,14 @@
|
|||||||
extraIdentities = lib.mkOption {
|
extraIdentities = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
example = [ "server" "builder" ];
|
example = [
|
||||||
|
"server"
|
||||||
|
"builder"
|
||||||
|
];
|
||||||
description = ''
|
description = ''
|
||||||
Catalog accounts this HM user may authenticate AS, in addition
|
Catalog accounts this HM user may authenticate AS, in addition
|
||||||
to `cfg.user`. Each entry must have a publicKey pasted into
|
to `cfg.user`. Each entry must have a publicKey pasted into
|
||||||
`modules/lib/ssh-inventory.nix`. Typical for the operator's
|
`modules/ssh/inventory.nix`. Typical for the operator's
|
||||||
primary laptop: `[ "server" "builder" ]` so fleet/ops commands
|
primary laptop: `[ "server" "builder" ]` so fleet/ops commands
|
||||||
like `ssh server@r5500` or `ssh builder@nix-server` work
|
like `ssh server@r5500` or `ssh builder@nix-server` work
|
||||||
without touching `/etc/passwd` on each host.
|
without touching `/etc/passwd` on each host.
|
||||||
@@ -76,7 +77,8 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable (lib.mkMerge [
|
config = lib.mkIf cfg.enable (
|
||||||
|
lib.mkMerge [
|
||||||
{
|
{
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
@@ -85,11 +87,11 @@
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion = defaultUserHasKey;
|
assertion = defaultUserHasKey;
|
||||||
message = "ssh.outbound.rbw: no publicKey for inventory user `${cfg.user}` in `modules/lib/ssh-inventory.nix`.";
|
message = "ssh.outbound.rbw: no publicKey for inventory user `${cfg.user}` in `modules/ssh/inventory.nix`.";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assertion = missingExtraKeys == [ ];
|
assertion = missingExtraKeys == [ ];
|
||||||
message = "ssh.outbound.rbw: extraIdentities has entries with no publicKey in `modules/lib/ssh-inventory.nix`: ${builtins.concatStringsSep ", " missingExtraKeys}";
|
message = "ssh.outbound.rbw: extraIdentities has entries with no publicKey in `modules/ssh/inventory.nix`: ${builtins.concatStringsSep ", " missingExtraKeys}";
|
||||||
}
|
}
|
||||||
# `enable=true` with neither a default user nor any extras gives the
|
# `enable=true` with neither a default user nor any extras gives the
|
||||||
# agent no IdentityFile at all; with IdentitiesOnly yes the user
|
# agent no IdentityFile at all; with IdentitiesOnly yes the user
|
||||||
@@ -102,19 +104,22 @@
|
|||||||
}
|
}
|
||||||
(lib.mkMerge [
|
(lib.mkMerge [
|
||||||
{
|
{
|
||||||
home.packages = with pkgs; [ rbw pinentry-gtk2 ];
|
home.packages = with pkgs; [
|
||||||
|
rbw
|
||||||
|
pinentry-gtk2
|
||||||
|
];
|
||||||
home.sessionVariables.SSH_AUTH_SOCK = self.lib.rbwSshSocket.sessionVariable;
|
home.sessionVariables.SSH_AUTH_SOCK = self.lib.rbwSshSocket.sessionVariable;
|
||||||
# Write a `.pub` file per identity this HM user may act as
|
# Write a `.pub` file per identity this HM user may act as
|
||||||
# (cfg.user ∪ extraIdentities). OpenSSH reads each one via
|
# (cfg.user ∪ extraIdentities). OpenSSH reads each one via
|
||||||
# IdentityFile/Match to filter agent keys — they never hold
|
# IdentityFile/Match to filter agent keys — they never hold
|
||||||
# private key material, so 0644 (HM's default) is fine.
|
# private key material, so 0644 (HM's default) is fine.
|
||||||
# OpenSSH's StrictModes only rejects group/other-writable files.
|
# OpenSSH's StrictModes only rejects group/other-writable files.
|
||||||
home.file = lib.listToAttrs (map
|
home.file = lib.listToAttrs (
|
||||||
(n: {
|
map (n: {
|
||||||
name = inventory.mkIdentityFileName n;
|
name = inventory.mkIdentityFileName n;
|
||||||
value.text = "${inventory.users.${n}.publicKey}\n";
|
value.text = "${inventory.users.${n}.publicKey}\n";
|
||||||
})
|
}) effectiveIdentities
|
||||||
effectiveIdentities);
|
);
|
||||||
programs.ssh.enable = lib.mkIf cfg.manageSshConfig false;
|
programs.ssh.enable = lib.mkIf cfg.manageSshConfig false;
|
||||||
}
|
}
|
||||||
(lib.mkIf cfg.manageSshConfig {
|
(lib.mkIf cfg.manageSshConfig {
|
||||||
@@ -143,6 +148,7 @@
|
|||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
]);
|
]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
{
|
{
|
||||||
assertions = [{
|
assertions = [{
|
||||||
assertion = cfg.enable -> missingKeys == [ ];
|
assertion = cfg.enable -> missingKeys == [ ];
|
||||||
message = "chiasson.ssh.inbound: users enabled but missing public key in `modules/lib/ssh-inventory.nix`: ${lib.concatStringsSep ", " missingKeys}";
|
message = "chiasson.ssh.inbound: users enabled but missing public key in `modules/ssh/inventory.nix`: ${lib.concatStringsSep ", " missingKeys}";
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
(lib.mkIf cfg.enable {
|
(lib.mkIf cfg.enable {
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# rbw (Bitwarden) SSH-agent socket wiring, shared across shells and the
|
||||||
|
# outbound-rbw Home Manager module. Exposed as `flake.lib.rbwSshSocket`.
|
||||||
|
{ ... }: {
|
||||||
|
flake.lib.rbwSshSocket =
|
||||||
|
let
|
||||||
|
socketPath = "$XDG_RUNTIME_DIR/rbw/ssh-agent-socket";
|
||||||
|
|
||||||
|
# Bash init snippet — used by wisdom/shells/bash.nix (profile + interactive).
|
||||||
|
bashSnippet = ''
|
||||||
|
if [ -z "''${SSH_AUTH_SOCK:-}" ]; then
|
||||||
|
if [ -n "''${XDG_RUNTIME_DIR:-}" ]; then
|
||||||
|
export SSH_AUTH_SOCK="${socketPath}"
|
||||||
|
else
|
||||||
|
export SSH_AUTH_SOCK="/run/user/$(id -u)/rbw/ssh-agent-socket"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Fish init snippet — used by wisdom/shells/fish.nix.
|
||||||
|
fishSnippet = pkgs: ''
|
||||||
|
if test -z "$SSH_AUTH_SOCK"
|
||||||
|
if test -n "$XDG_RUNTIME_DIR"
|
||||||
|
set -gx SSH_AUTH_SOCK "${socketPath}"
|
||||||
|
else
|
||||||
|
set -l _hm_uid (${pkgs.coreutils}/bin/id -u)
|
||||||
|
set -gx SSH_AUTH_SOCK "/run/user/$_hm_uid/rbw/ssh-agent-socket"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit bashSnippet fishSnippet;
|
||||||
|
# Used by home-manager modules to expose SSH_AUTH_SOCK to GUI apps
|
||||||
|
# and HM-managed shells declaratively (no activation script needed).
|
||||||
|
sessionVariable = socketPath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+138
-27
@@ -8,18 +8,115 @@
|
|||||||
{ config, options, lib, ... }:
|
{ config, options, lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.chiasson.users;
|
cfg = config.chiasson.users;
|
||||||
usersLib = self.lib.usersMerge lib;
|
usersLib =
|
||||||
|
let
|
||||||
|
userHm = user: user.homeManager or { };
|
||||||
|
userSsh = user: user.ssh or { };
|
||||||
|
in
|
||||||
|
rec {
|
||||||
|
resolveHomeManagerModule =
|
||||||
|
moduleSpec:
|
||||||
|
let
|
||||||
|
t = builtins.typeOf moduleSpec;
|
||||||
|
in
|
||||||
|
if t == "path" || t == "string" then import moduleSpec else moduleSpec;
|
||||||
|
|
||||||
|
selectedUsersAttr =
|
||||||
|
{ catalog, enabled, hostOverrides }:
|
||||||
|
lib.listToAttrs (
|
||||||
|
map (name: {
|
||||||
|
inherit name;
|
||||||
|
value = lib.recursiveUpdate catalog.${name} (hostOverrides.${name} or { });
|
||||||
|
}) enabled
|
||||||
|
);
|
||||||
|
|
||||||
|
missingEnabledNames =
|
||||||
|
catalog: enabled: builtins.filter (name: !(builtins.hasAttr name catalog)) enabled;
|
||||||
|
|
||||||
|
strayHomeUserKeys =
|
||||||
|
homeUsers: enabled: builtins.filter (k: !(builtins.elem k enabled)) (builtins.attrNames homeUsers);
|
||||||
|
|
||||||
|
mkNixosUser =
|
||||||
|
name: user:
|
||||||
|
{
|
||||||
|
isNormalUser = user.isNormalUser or true;
|
||||||
|
description = user.description or name;
|
||||||
|
extraGroups = user.extraGroups or [ ];
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (user ? hashedPasswordFile && user.hashedPasswordFile != null) {
|
||||||
|
hashedPasswordFile = user.hashedPasswordFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
hmWiredNames =
|
||||||
|
selectedUsers:
|
||||||
|
lib.attrNames (
|
||||||
|
lib.filterAttrs (
|
||||||
|
_: user:
|
||||||
|
let
|
||||||
|
hm = userHm user;
|
||||||
|
in
|
||||||
|
(hm.enable or false) && (hm.module or null) != null
|
||||||
|
) selectedUsers
|
||||||
|
);
|
||||||
|
|
||||||
|
rbwOutboundSnippet =
|
||||||
|
name: user:
|
||||||
|
let
|
||||||
|
outboundCfg = ((userSsh user).outbound or { }).rbw or { };
|
||||||
|
in
|
||||||
|
lib.mkIf (outboundCfg.enable or false) {
|
||||||
|
chiasson.ssh.outbound.rbw.enable = true;
|
||||||
|
chiasson.ssh.outbound.rbw.user = name;
|
||||||
|
chiasson.ssh.outbound.rbw.hosts =
|
||||||
|
if (outboundCfg.hosts or "all") == "all" then [ "all" ] else outboundCfg.hosts;
|
||||||
|
chiasson.ssh.outbound.rbw.extraIdentities = outboundCfg.extraIdentities or [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
mkHmUserModule =
|
||||||
|
{ name, user, hostExtraModules }:
|
||||||
|
let
|
||||||
|
hm = userHm user;
|
||||||
|
hmModule = resolveHomeManagerModule hm.module;
|
||||||
|
in
|
||||||
|
lib.mkMerge (
|
||||||
|
[
|
||||||
|
hmModule
|
||||||
|
(rbwOutboundSnippet name user)
|
||||||
|
]
|
||||||
|
++ (hm.extraModules or [ ])
|
||||||
|
++ hostExtraModules
|
||||||
|
);
|
||||||
|
|
||||||
|
inboundAuthorizedOrNull =
|
||||||
|
user:
|
||||||
|
let
|
||||||
|
inboundCfg = (userSsh user).inbound or { };
|
||||||
|
in
|
||||||
|
if !(inboundCfg.enable or false) then
|
||||||
|
null
|
||||||
|
else if (inboundCfg.authorizedHosts or "all") == "all" then
|
||||||
|
"all"
|
||||||
|
else
|
||||||
|
inboundCfg.authorizedHosts;
|
||||||
|
|
||||||
|
inboundHostsAttr =
|
||||||
|
selectedUsers:
|
||||||
|
lib.pipe selectedUsers [
|
||||||
|
(lib.mapAttrs (_: inboundAuthorizedOrNull))
|
||||||
|
(lib.filterAttrs (_: v: v != null))
|
||||||
|
];
|
||||||
|
};
|
||||||
inventory = self.lib.sshInventory;
|
inventory = self.lib.sshInventory;
|
||||||
|
|
||||||
olivierEnabled = lib.elem "olivier" cfg.enabled;
|
olivierEnabled = lib.elem "olivier" cfg.enabled;
|
||||||
|
|
||||||
# Merge catalog + per-host overrides into the final user attrs.
|
# Merge catalog + per-host overrides into the final user attrs.
|
||||||
selectedUsers = lib.listToAttrs (map
|
selectedUsers = lib.listToAttrs (
|
||||||
(name: {
|
map (name: {
|
||||||
inherit name;
|
inherit name;
|
||||||
value = lib.recursiveUpdate cfg.catalog.${name} (cfg.hostOverrides.${name} or { });
|
value = lib.recursiveUpdate cfg.catalog.${name} (cfg.hostOverrides.${name} or { });
|
||||||
})
|
}) cfg.enabled
|
||||||
cfg.enabled);
|
);
|
||||||
|
|
||||||
names = usersLib.hmWiredNames selectedUsers;
|
names = usersLib.hmWiredNames selectedUsers;
|
||||||
missing = usersLib.missingEnabledNames cfg.catalog cfg.enabled;
|
missing = usersLib.missingEnabledNames cfg.catalog cfg.enabled;
|
||||||
@@ -27,26 +124,27 @@
|
|||||||
hmAvailable = lib.hasAttrByPath [ "home-manager" "users" ] options;
|
hmAvailable = lib.hasAttrByPath [ "home-manager" "users" ] options;
|
||||||
inboundUsersAttr = usersLib.inboundHostsAttr selectedUsers;
|
inboundUsersAttr = usersLib.inboundHostsAttr selectedUsers;
|
||||||
|
|
||||||
hmUsersAttr = lib.listToAttrs (map
|
hmUsersAttr = lib.listToAttrs (
|
||||||
(name: {
|
map (name: {
|
||||||
inherit name;
|
inherit name;
|
||||||
value = usersLib.mkHmUserModule {
|
value = usersLib.mkHmUserModule {
|
||||||
inherit name;
|
inherit name;
|
||||||
user = selectedUsers.${name};
|
user = selectedUsers.${name};
|
||||||
hostExtraModules = cfg.extraModules.${name} or [ ];
|
hostExtraModules = cfg.extraModules.${name} or [ ];
|
||||||
};
|
};
|
||||||
})
|
}) names
|
||||||
names);
|
);
|
||||||
|
|
||||||
# Fish shell wiring: HM's fish module declares its package, but
|
# Fish shell wiring: HM's fish module declares its package, but
|
||||||
# /etc/passwd + /etc/shells need updating so login shells work.
|
# /etc/passwd + /etc/shells need updating so login shells work.
|
||||||
# Only fires for HM users that actually enable fish.
|
# Only fires for HM users that actually enable fish.
|
||||||
hmFishUsers =
|
hmFishUsers =
|
||||||
if !hmAvailable then { }
|
if !hmAvailable then
|
||||||
|
{ }
|
||||||
else
|
else
|
||||||
lib.filterAttrs
|
lib.filterAttrs (
|
||||||
(name: hmUser: (hmUser.programs.fish.enable or false) && builtins.elem name names)
|
name: hmUser: (hmUser.programs.fish.enable or false) && builtins.elem name names
|
||||||
config.home-manager.users;
|
) config.home-manager.users;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -108,12 +206,18 @@
|
|||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
description = "Olivier";
|
description = "Olivier";
|
||||||
extraGroups = [
|
extraGroups = [
|
||||||
"networkmanager" "wheel" "docker" "fuse" "uinput" "kvm"
|
"networkmanager"
|
||||||
|
"wheel"
|
||||||
|
"docker"
|
||||||
|
"fuse"
|
||||||
|
"uinput"
|
||||||
|
"kvm"
|
||||||
# `video` lets brightnessctl/light udev rules own /sys/backlight without sudo.
|
# `video` lets brightnessctl/light udev rules own /sys/backlight without sudo.
|
||||||
# Harmless on headless hosts (no devices).
|
# Harmless on headless hosts (no devices).
|
||||||
"video"
|
"video"
|
||||||
# DRI render + input for gamescope / Steam on Wayland, no sudo.
|
# DRI render + input for gamescope / Steam on Wayland, no sudo.
|
||||||
"render" "input"
|
"render"
|
||||||
|
"input"
|
||||||
];
|
];
|
||||||
hashedPasswordFile = lib.mkIf olivierEnabled (
|
hashedPasswordFile = lib.mkIf olivierEnabled (
|
||||||
config.sops.secrets."users/olivier/hashedPassword".path
|
config.sops.secrets."users/olivier/hashedPassword".path
|
||||||
@@ -147,14 +251,20 @@
|
|||||||
# `.pub` filter for each of these and emits a `Match user`
|
# `.pub` filter for each of these and emits a `Match user`
|
||||||
# block, so `ssh server@r5500` / `ssh builder@nix-server`
|
# block, so `ssh server@r5500` / `ssh builder@nix-server`
|
||||||
# route the right private key from the rbw agent.
|
# route the right private key from the rbw agent.
|
||||||
ssh.outbound.rbw.extraIdentities = [ "server" "builder" ];
|
ssh.outbound.rbw.extraIdentities = [
|
||||||
|
"server"
|
||||||
|
"builder"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
server = {
|
server = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
description = "Server user";
|
description = "Server user";
|
||||||
extraGroups = [ "wheel" ];
|
extraGroups = [ "wheel" ];
|
||||||
homeManager = { enable = false; module = null; };
|
homeManager = {
|
||||||
|
enable = false;
|
||||||
|
module = null;
|
||||||
|
};
|
||||||
ssh.inbound.enable = true;
|
ssh.inbound.enable = true;
|
||||||
ssh.inbound.authorizedHosts = "all";
|
ssh.inbound.authorizedHosts = "all";
|
||||||
ssh.outbound.rbw.enable = false;
|
ssh.outbound.rbw.enable = false;
|
||||||
@@ -166,7 +276,10 @@
|
|||||||
description = "Navi fleet deploy (push + activate only)";
|
description = "Navi fleet deploy (push + activate only)";
|
||||||
extraGroups = [ ];
|
extraGroups = [ ];
|
||||||
createHome = false;
|
createHome = false;
|
||||||
homeManager = { enable = false; module = null; };
|
homeManager = {
|
||||||
|
enable = false;
|
||||||
|
module = null;
|
||||||
|
};
|
||||||
ssh.inbound.enable = true;
|
ssh.inbound.enable = true;
|
||||||
ssh.inbound.authorizedHosts = "all";
|
ssh.inbound.authorizedHosts = "all";
|
||||||
};
|
};
|
||||||
@@ -195,9 +308,7 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
# NixOS user accounts (no HM, raw).
|
# NixOS user accounts (no HM, raw).
|
||||||
users.users = lib.mapAttrs
|
users.users = lib.mapAttrs (name: user: usersLib.mkNixosUser name user) selectedUsers;
|
||||||
(name: user: usersLib.mkNixosUser name user)
|
|
||||||
selectedUsers;
|
|
||||||
}
|
}
|
||||||
(lib.optionalAttrs hmAvailable {
|
(lib.optionalAttrs hmAvailable {
|
||||||
"home-manager".useGlobalPkgs = lib.mkIf (cfg.homeManager.autoWire && names != [ ]) true;
|
"home-manager".useGlobalPkgs = lib.mkIf (cfg.homeManager.autoWire && names != [ ]) true;
|
||||||
@@ -216,12 +327,12 @@
|
|||||||
# /etc/shells with `mkForce`. `mkNixosUser` doesn't emit `shell`, so
|
# /etc/shells with `mkForce`. `mkNixosUser` doesn't emit `shell`, so
|
||||||
# the force is uncontested.
|
# the force is uncontested.
|
||||||
(lib.mkIf (hmFishUsers != { }) {
|
(lib.mkIf (hmFishUsers != { }) {
|
||||||
environment.shells = lib.mkAfter (lib.mapAttrsToList
|
environment.shells = lib.mkAfter (
|
||||||
(_: hmUser: lib.getExe hmUser.programs.fish.package)
|
lib.mapAttrsToList (_: hmUser: lib.getExe hmUser.programs.fish.package) hmFishUsers
|
||||||
hmFishUsers);
|
);
|
||||||
users.users = lib.mapAttrs
|
users.users = lib.mapAttrs (name: hmUser: {
|
||||||
(name: hmUser: { shell = lib.mkForce (lib.getExe hmUser.programs.fish.package); })
|
shell = lib.mkForce (lib.getExe hmUser.programs.fish.package);
|
||||||
hmFishUsers;
|
}) hmFishUsers;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user