This commit is contained in:
Patrick 2024-07-26 22:12:48 +02:00
parent 857140bbd2
commit 44d265ecdb
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
144 changed files with 3479 additions and 2930 deletions

View file

@ -3,7 +3,8 @@
lib,
pkgs,
...
}: {
}:
{
boot = lib.mkIf (!config.boot.isContainer) {
initrd.systemd = {
enable = true;
@ -14,7 +15,18 @@
storePaths = [ "${pkgs.bashInteractive}/bin/bash" ];
};
initrd.availableKernelModules = ["xhci_pci" "nvme" "r8169" "usb_storage" "usbhid" "sd_mod" "rtsx_pci_sdmmc" "ahci" "uas" "tpm_crb"];
initrd.availableKernelModules = [
"xhci_pci"
"nvme"
"r8169"
"usb_storage"
"usbhid"
"sd_mod"
"rtsx_pci_sdmmc"
"ahci"
"uas"
"tpm_crb"
];
supportedFilesystems = [ "ntfs" ];
kernelModules = [ "kvm-intel" ];
kernelParams = [

View file

@ -1,8 +1,5 @@
{ inputs, lib, ... }:
{
inputs,
lib,
...
}: {
imports = [
./boot.nix
./home-manager.nix

View file

@ -4,7 +4,8 @@
pkgs,
nodes,
...
}: {
}:
{
imports = [
../../modules-hm/impermanence.nix
../../modules-hm/images.nix
@ -18,9 +19,7 @@
spicePkgs = inputs.spicetify-nix.legacyPackages.${pkgs.system};
};
sharedModules = [
{
home.stateVersion = stateVersion;
}
{ home.stateVersion = stateVersion; }
inputs.nix-index-database.hmModules.nix-index
inputs.nixos-extra-modules.homeManagerModules.default
inputs.nixvim.homeManagerModules.nixvim

View file

@ -3,35 +3,23 @@
lib,
pkgs,
...
}: let
onlyHost =
lib.mkIf (!config.boot.isContainer);
prune = folder:
}:
let
onlyHost = lib.mkIf (!config.boot.isContainer);
prune =
folder:
pkgs.writers.writePython3Bin "impermanence-prune" { } ''
import os
import sys
mounts = [${
lib.concatStringsSep ", "
((map (x:
"\""
+ (
if x.home != null
then x.home + "/"
else ""
lib.concatStringsSep ", " (
(map (
x: "\"" + (if x.home != null then x.home + "/" else "") + x.directory + "\""
) config.environment.persistence.${folder}.directories)
++ (map (
x: "\"" + (if x.home != null then x.home + "/" else "") + x.file + "\""
) config.environment.persistence.${folder}.files)
)
+ x.directory
+ "\"")
config.environment.persistence.${folder}.directories)
++ (map (x:
"\""
+ (
if x.home != null
then x.home + "/"
else ""
)
+ x.file
+ "\"")
config.environment.persistence.${folder}.files))
}] # noqa: E501
mounts = [os.path.normpath(x) for x in mounts]
mounts.sort()
@ -53,11 +41,10 @@
file=sys.stderr)
print("\n".join(erg))
'';
in {
in
{
# to allow all users to access hm managed persistent folders
lib.scripts.impermanence.pruneScripts =
lib.mapAttrs (k: _: prune k)
config.environment.persistence;
lib.scripts.impermanence.pruneScripts = lib.mapAttrs (k: _: prune k) config.environment.persistence;
programs.fuse.userAllowOther = true;
services.openssh.hostKeys = lib.mkForce [
{
@ -68,15 +55,10 @@ in {
environment.persistence."/state" = {
hideMounts = true;
files =
[
files = [
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
]
++ lib.lists.optionals (!config.boot.isContainer)
[
"/etc/machine-id"
];
] ++ lib.lists.optionals (!config.boot.isContainer) [ "/etc/machine-id" ];
directories = [
"/var/log"
"/var/lib/systemd"
@ -99,9 +81,7 @@ in {
fileSystems."/state".neededForBoot = true;
# After importing the rpool, rollback the root system to be empty.
boot.initrd.systemd.services.impermanence-root =
onlyHost
{
boot.initrd.systemd.services.impermanence-root = onlyHost {
wantedBy = [ "initrd.target" ];
after = [ "zfs-import-rpool.service" ];
before = [ "sysroot.mount" ];

View file

@ -1,8 +1,5 @@
{ lib, config, ... }:
{
lib,
config,
...
}: {
networking = {
useNetworkd = true;
dhcpcd.enable = false;
@ -10,8 +7,7 @@
# allow mdns port
firewall.allowedUDPPorts = [ 5353 ];
renameInterfacesByMac = lib.mkIf (!config.boot.isContainer) (
lib.mapAttrs (_: v: v.mac)
(config.secrets.secrets.local.networking.interfaces or {})
lib.mapAttrs (_: v: v.mac) (config.secrets.secrets.local.networking.interfaces or { })
);
};
systemd.network = {

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
networking.nftables = {
stopRuleset = lib.mkDefault ''
table inet filter {
@ -36,8 +33,23 @@
nnf-ssh.enable = true;
nnf-icmp = {
enable = true;
ipv6Types = ["echo-request" "destination-unreachable" "packet-too-big" "time-exceeded" "parameter-problem" "nd-router-advert" "nd-neighbor-solicit" "nd-neighbor-advert"];
ipv4Types = ["echo-request" "destination-unreachable" "router-advertisement" "time-exceeded" "parameter-problem"];
ipv6Types = [
"echo-request"
"destination-unreachable"
"packet-too-big"
"time-exceeded"
"parameter-problem"
"nd-router-advert"
"nd-neighbor-solicit"
"nd-neighbor-advert"
];
ipv4Types = [
"echo-request"
"destination-unreachable"
"router-advertisement"
"time-exceeded"
"parameter-problem"
];
};
};
@ -45,11 +57,7 @@
from = [ "untrusted" ];
to = [ "local" ];
inherit
(config.networking.firewall)
allowedTCPPorts
allowedUDPPorts
;
inherit (config.networking.firewall) allowedTCPPorts allowedUDPPorts;
};
};
};

View file

@ -1,14 +1,15 @@
{ inputs, stateVersion, ... }:
{
inputs,
stateVersion,
...
}: {
nix = {
settings = {
auto-optimise-store = true;
allowed-users = [ "@wheel" ];
trusted-users = [ "root" ];
system-features = ["recursive-nix" "repl-flake" "big-parallel"];
system-features = [
"recursive-nix"
"repl-flake"
"big-parallel"
];
substituters = [
"https://nix-community.cachix.org"
"https://cache.nixos.org"

View file

@ -1,4 +1,5 @@
{lib, ...}: {
{ lib, ... }:
{
# Enable the OpenSSH daemon.
services.openssh = {
enable = true;

View file

@ -5,24 +5,24 @@
pkgs,
config,
...
}: {
}:
{
system.stateVersion = stateVersion;
age.rekey = {
inherit
(inputs.self.secretsConfig)
masterIdentities
extraEncryptionPubkeys
;
inherit (inputs.self.secretsConfig) masterIdentities extraEncryptionPubkeys;
storageMode = "derivation";
forceRekeyOnSystem = builtins.extraBuiltins.unsafeCurrentSystem;
hostPubkey = let
hostPubkey =
let
pubkeyPath = config.node.secretsDir + "/host.pub";
in
lib.mkIf (lib.pathExists pubkeyPath || lib.trace "Missing pubkey for ${config.node.name}: ${toString pubkeyPath} not found, using dummy replacement key for now." false)
pubkeyPath;
lib.mkIf (
lib.pathExists pubkeyPath
|| lib.trace "Missing pubkey for ${config.node.name}: ${toString pubkeyPath} not found, using dummy replacement key for now." false
) pubkeyPath;
generatedSecretsDir = config.node.secretsDir + "/generated/";
cacheDir = "/var/tmp/agenix-rekey/\"$UID\"";
};
@ -71,7 +71,8 @@
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
secrets.secretFiles = let
secrets.secretFiles =
let
local = config.node.secretsDir + "/secrets.nix.age";
in
{

View file

@ -1,11 +1,13 @@
{
users.mutableUsers = false;
users.deterministicIds = let
users.deterministicIds =
let
uidGid = id: {
uid = id;
gid = id;
};
in {
in
{
nscd = uidGid 201;
sshd = uidGid 202;
tss = uidGid 203;

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ bluetuith ];
hardware.bluetooth = {
@ -24,7 +25,5 @@
'';
extraModules = with pkgs; [ pulseaudio-modules-bt ];
};
environment.persistence."/state".directories = [
"/var/lib/bluetooth"
];
environment.persistence."/state".directories = [ "/var/lib/bluetooth" ];
}

View file

@ -1,3 +1 @@
{
services.joycond.enable = true;
}
{ services.joycond.enable = true; }

View file

@ -1,5 +1,6 @@
# Configuration for actual physical machines
{config, ...}: {
{ config, ... }:
{
hardware = {
enableRedistributableFirmware = true;
enableAllFirmware = true;

View file

@ -13,7 +13,10 @@ lib.optionalAttrs (!minimal) {
# packages = pkgs.linuxPackages_6_6_rt;
# };
#};
environment.systemPackages = with pkgs; [pulseaudio pulsemixer];
environment.systemPackages = with pkgs; [
pulseaudio
pulsemixer
];
hardware.pulseaudio.enable = lib.mkForce false;
security.rtkit.enable = true;

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
yubikey-personalization
yubikey-manager
@ -7,5 +8,8 @@
services.pcscd.enable = true;
services.udev.packages = with pkgs; [yubikey-personalization libu2f-host];
services.udev.packages = with pkgs; [
yubikey-personalization
libu2f-host
];
}

View file

@ -4,13 +4,11 @@
pkgs,
lib,
...
}: let
inherit
(lib)
mkOption
types
;
in {
}:
let
inherit (lib) mkOption types;
in
{
options.hidpi = mkOption {
default = false;
type = types.bool;
@ -18,14 +16,10 @@ in {
};
# stylix acceses stylix options on import meaning you can only import this module when you're actually setting stylix options
imports = [
inputs.stylix.nixosModules.stylix
];
imports = [ inputs.stylix.nixosModules.stylix ];
config = {
environment.systemPackages = with pkgs; [
xdg-utils
];
environment.systemPackages = with pkgs; [ xdg-utils ];
xdg.portal = {
xdgOpenUsePortal = true;
enable = true;
@ -38,9 +32,7 @@ in {
"gtk"
"hyprland"
];
sway.default = [
"wlr"
];
sway.default = [ "wlr" ];
};
};
# needed for gnome pinentry
@ -160,20 +152,19 @@ in {
};
home-manager.sharedModules = [
({
(
{
pkgs,
config,
nixosConfig,
...
}: {
}:
{
stylix = {
cursor = {
package = pkgs.openzone-cursors;
name = "OpenZone_White_Slim";
size =
if nixosConfig.hidpi
then 48
else 18;
size = if nixosConfig.hidpi then 48 else 18;
};
inherit (nixosConfig.stylix) polarity;
targets = {
@ -194,7 +185,8 @@ in {
"Xft.rgba" = "rgb";
};
gtk = let
gtk =
let
gtk34extraConfig = {
gtk-application-prefer-dark-theme = 1;
gtk-cursor-theme-size = 18;
@ -205,7 +197,8 @@ in {
gtk-xft-hintstyle = "hintfull";
gtk-xft-rgba = "rgb";
};
in {
in
{
enable = true;
iconTheme = {
name = "Vimix-Doder";
@ -224,7 +217,8 @@ in {
platformTheme.name = "adwaita";
style.name = "Adwaita-Dark";
};
})
}
)
];
};
}

View file

@ -1,8 +1,5 @@
{ config, pkgs, ... }:
{
config,
pkgs,
...
}: {
age.secrets.initrd_host_ed25519_key.generator.script = "ssh-ed25519";
boot.initrd.network.enable = true;
@ -30,7 +27,10 @@
${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f "${config.age.secrets.initrd_host_ed25519_key.path}"
fi
'';
deps = ["agenixInstall" "users"];
deps = [
"agenixInstall"
"users"
];
};
system.activationScripts.agenixChown.deps = [ "agenixEnsureInitrdHostkey" ];
}

View file

@ -1,7 +1,11 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
services.printing = {
enable = true;
drivers = [pkgs.hplipWithPlugin pkgs.hplip];
drivers = [
pkgs.hplipWithPlugin
pkgs.hplip
];
};
environment.persistence."/state".directories = [
{

View file

@ -8,10 +8,7 @@
lib.optionalAttrs (!minimal) {
environment.systemPackages = [
# For debugging and troubleshooting Secure Boot.
(pkgs.sbctl.override
{
databasePath = "/run/secureboot";
})
(pkgs.sbctl.override { databasePath = "/run/secureboot"; })
];
age.secrets.secureboot.rekeyFile = ../../hosts/${config.node.name}/secrets/secureboot.tar.age;
system.activationScripts.securebootuntar = {

View file

@ -8,8 +8,8 @@ lib.optionalAttrs (!minimal) {
programs.steam = {
enable = true;
package = pkgs.steam.override {
extraPkgs = pkgs:
with pkgs; [
extraPkgs =
pkgs: with pkgs; [
# vampir überlebende braucht diese pkgs
libgdiplus
cups

View file

@ -28,10 +28,9 @@ lib.optionalAttrs (!minimal) {
disableWhileTyping = true;
};
};
services.udev.extraRules = let
exe =
pkgs.writeShellScript "set-key-repeat"
''
services.udev.extraRules =
let
exe = pkgs.writeShellScript "set-key-repeat" ''
if [ -d "/tmp/.X11-unix" ]; then
for D in /tmp/.X11-unix/*; do
file=$(${pkgs.coreutils}/bin/basename $D)
@ -43,7 +42,8 @@ lib.optionalAttrs (!minimal) {
done
fi
'';
in ''
in
''
ACTION=="add", SUBSYSTEM=="input", ATTRS{bInterfaceClass}=="03", RUN+="${exe}"
'';
}

View file

@ -3,7 +3,8 @@
config,
lib,
...
}: {
}:
{
boot.supportedFilesystems = [ "zfs" ];
boot.kernelPackages = lib.mkDefault config.boot.zfs.package.latestCompatibleLinuxPackages;

View file

@ -8,9 +8,5 @@
enable = true;
settings.port = 3000;
};
environment.persistence."/persist".directories = [
{
directory = "/var/lib/private/actual";
}
];
environment.persistence."/persist".directories = [ { directory = "/var/lib/private/actual"; } ];
}

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ config.services.adguardhome.port ];
@ -16,8 +13,12 @@
settings = {
dns = {
bind_hosts = [
(lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name} config.secrets.secrets.global.net.privateSubnetv4)
(lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name} config.secrets.secrets.global.net.privateSubnetv6)
(lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name}
config.secrets.secrets.global.net.privateSubnetv4
)
(lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name}
config.secrets.secrets.global.net.privateSubnetv6
)
];
anonymize_client_ip = false;
upstream_dns = [

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
age.secrets.cloudflare_token_dns = {
rekeyFile = config.node.secretsDir + "/cloudflare_api_token.age";
mode = "440";

View file

@ -1,8 +1,5 @@
{ config, nodes, ... }:
{
config,
nodes,
...
}: {
i18n.supportedLocales = [ "all" ];
wireguard.elisabeth = {
client.via = "elisabeth";

View file

@ -4,9 +4,11 @@
pkgs,
lib,
...
}: let
}:
let
forgejoDomain = "forge.${config.secrets.secrets.global.domains.web}";
in {
in
{
age.secrets.resticpasswd = {
generator.script = "alnum";
};
@ -52,7 +54,9 @@ in {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [config.services.forgejo.settings.server.HTTP_PORT];
firewallRuleForNode.elisabeth.allowedTCPPorts = [
config.services.forgejo.settings.server.HTTP_PORT
];
};
networking.firewall.allowedTCPPorts = [ config.services.forgejo.settings.server.SSH_PORT ];
@ -145,7 +149,8 @@ in {
# see https://github.com/go-gitea/gitea/issues/21376.
systemd.services.forgejo = {
serviceConfig.RestartSec = "60"; # Retry every minute
preStart = let
preStart =
let
exe = lib.getExe config.services.forgejo.package;
providerName = "kanidm";
clientId = "forgejo";

View file

@ -4,7 +4,8 @@
nodes,
config,
...
}: let
}:
let
version = "v1.106.4";
immichDomain = "immich.${config.secrets.secrets.global.domains.web}";
@ -136,21 +137,14 @@
serviceConfig = {
Restart = "always";
};
after = [
"podman-network-immich-default.service"
];
requires = [
"podman-network-immich-default.service"
];
partOf = [
"podman-compose-immich-root.target"
];
wantedBy = [
"podman-compose-immich-root.target"
];
after = [ "podman-network-immich-default.service" ];
requires = [ "podman-network-immich-default.service" ];
partOf = [ "podman-compose-immich-root.target" ];
wantedBy = [ "podman-compose-immich-root.target" ];
};
processedConfigFile = "/run/agenix/immich.config.json";
in {
in
{
age.secrets.resticpasswd = {
generator.script = "alnum";
};
@ -313,9 +307,7 @@ in {
"${upload_folder}:/usr/src/app/upload:rw"
"${environment.DB_PASSWORD_FILE}:${environment.DB_PASSWORD_FILE}:ro"
];
ports = [
"3000:3001/tcp"
];
ports = [ "3000:3001/tcp" ];
dependsOn = [
"immich_postgres"
"immich_redis"
@ -327,9 +319,7 @@ in {
"--ip=${ipImmichServer}"
];
};
systemd.services."podman-immich_server" =
serviceConfig
// {
systemd.services."podman-immich_server" = serviceConfig // {
unitConfig.UpheldBy = [
"podman-immich_postgres.service"
"podman-immich_redis.service"

View file

@ -1,6 +1,8 @@
{config, ...}: let
{ config, ... }:
let
kanidmdomain = "auth.${config.secrets.secrets.global.domains.web}";
in {
in
{
imports = [ ../../modules/kanidm.nix ];
wireguard.elisabeth = {
client.via = "elisabeth";
@ -84,7 +86,11 @@ in {
displayName = "paperless";
originUrl = "https://ppl.${config.secrets.secrets.global.domains.web}/";
basicSecretFile = config.age.secrets.oauth2-paperless.path;
scopeMaps."paperless.access" = ["openid" "email" "profile"];
scopeMaps."paperless.access" = [
"openid"
"email"
"profile"
];
preferShortUsername = true;
};
@ -100,7 +106,11 @@ in {
originUrl = "https://nc.${config.secrets.secrets.global.domains.web}/";
basicSecretFile = config.age.secrets.oauth2-nextcloud.path;
allowInsecureClientDisablePkce = true;
scopeMaps."nextcloud.access" = ["openid" "email" "profile"];
scopeMaps."nextcloud.access" = [
"openid"
"email"
"profile"
];
preferShortUsername = true;
};
@ -117,7 +127,11 @@ in {
basicSecretFile = config.age.secrets.oauth2-immich.path;
allowInsecureClientDisablePkce = true;
enableLegacyCrypto = true;
scopeMaps."immich.access" = ["openid" "email" "profile"];
scopeMaps."immich.access" = [
"openid"
"email"
"profile"
];
preferShortUsername = true;
};
@ -131,11 +145,31 @@ in {
displayName = "Oauth2-Proxy";
originUrl = "https://oauth2.${config.secrets.secrets.global.domains.web}/";
basicSecretFile = config.age.secrets.oauth2-proxy.path;
scopeMaps."adguardhome.access" = ["openid" "email" "profile"];
scopeMaps."rss.access" = ["openid" "email" "profile"];
scopeMaps."firefly.access" = ["openid" "email" "profile"];
scopeMaps."ollama.access" = ["openid" "email" "profile"];
scopeMaps."octoprint.access" = ["openid" "email" "profile"];
scopeMaps."adguardhome.access" = [
"openid"
"email"
"profile"
];
scopeMaps."rss.access" = [
"openid"
"email"
"profile"
];
scopeMaps."firefly.access" = [
"openid"
"email"
"profile"
];
scopeMaps."ollama.access" = [
"openid"
"email"
"profile"
];
scopeMaps."octoprint.access" = [
"openid"
"email"
"profile"
];
preferShortUsername = true;
claimMaps.groups = {
joinType = "array";
@ -157,7 +191,11 @@ in {
displayName = "Forgejo";
originUrl = "https://forge.${config.secrets.secrets.global.domains.web}/";
basicSecretFile = config.age.secrets.oauth2-forgejo.path;
scopeMaps."forgejo.access" = ["openid" "email" "profile"];
scopeMaps."forgejo.access" = [
"openid"
"email"
"profile"
];
allowInsecureClientDisablePkce = true;
preferShortUsername = true;
claimMaps.groups = {
@ -166,8 +204,7 @@ in {
};
};
groups."netbird.access" = {
};
groups."netbird.access" = { };
systems.oauth2.netbird = {
public = true;
displayName = "Netbird";
@ -175,7 +212,11 @@ in {
preferShortUsername = true;
enableLocalhostRedirects = true;
enableLegacyCrypto = true;
scopeMaps."netbird.access" = ["openid" "email" "profile"];
scopeMaps."netbird.access" = [
"openid"
"email"
"profile"
];
};
};
};

View file

@ -5,12 +5,17 @@
pkgs,
lib,
...
}: let
}:
let
priv_domain = config.secrets.secrets.global.domains.mail_private;
domain = config.secrets.secrets.global.domains.mail_public;
mailDomains = [priv_domain domain];
mailDomains = [
priv_domain
domain
];
maddyBackupDir = "/var/cache/backups/maddy";
in {
in
{
systemd.tmpfiles.settings = {
"10-maddy".${maddyBackupDir}.d = {
inherit (config.services.maddy) user group;
@ -40,7 +45,10 @@ in {
inherit (config.secrets.secrets.global.hetzner.users.maddy) subUid path;
sshAgeSecret = "maddyHetznerSsh";
};
paths = ["/var/lib/maddy/messages" maddyBackupDir];
paths = [
"/var/lib/maddy/messages"
maddyBackupDir
];
pruneOpts = [
"--keep-daily 10"
"--keep-weekly 7"
@ -49,14 +57,13 @@ in {
];
};
};
systemd.services.maddy-backup = let
systemd.services.maddy-backup =
let
cfg = config.systemd.services.maddy;
in {
description = "Maddy db backup";
serviceConfig =
lib.recursiveUpdate
cfg.serviceConfig
in
{
description = "Maddy db backup";
serviceConfig = lib.recursiveUpdate cfg.serviceConfig {
ExecStart = "${pkgs.sqlite}/bin/sqlite3 /var/lib/maddy/imapsql.db \".backup '${maddyBackupDir}/imapsql.sqlite3'\"";
Restart = "no";
Type = "oneshot";
@ -73,7 +80,10 @@ in {
};
# Opening ports for additional TLS listeners. This is not yet
# implemented in the module.
networking.firewall.allowedTCPPorts = [993 465];
networking.firewall.allowedTCPPorts = [
993
465
];
services.maddy = {
enable = true;
hostname = "mx1." + domain;
@ -91,9 +101,7 @@ in {
ensureCredentials = {
"patrick@${domain}".passwordFile = config.age.secrets.patrickPasswd.path;
};
ensureAccounts = [
"patrick@${domain}"
];
ensureAccounts = [ "patrick@${domain}" ];
openFirewall = true;
config = ''
## Maddy Mail Server - default configuration file (2022-06-18)
@ -288,9 +296,7 @@ in {
useACMEWildcardHost = true;
locations."=/mail/config-v1.1.xml".alias =
pkgs.writeText "autoconfig.${domain}.xml"
/*
xml
*/
# xml
''
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
networking.firewall.allowedUDPPorts = [ config.services.teamspeak3.defaultVoicePort ];
services.teamspeak3 = {
enable = true;

View file

@ -1,11 +1,12 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [80 3000 3001];
firewallRuleForNode.elisabeth.allowedTCPPorts = [
80
3000
3001
];
};
age.secrets.coturnPassword = {
@ -19,13 +20,19 @@
};
age.secrets.dataEnc = {
generator.script = {pkgs, ...}: ''
generator.script =
{ pkgs, ... }:
''
${lib.getExe pkgs.openssl} rand -base64 32
'';
group = "netbird";
};
networking.firewall.allowedTCPPorts = [80 3000 3001];
networking.firewall.allowedTCPPorts = [
80
3000
3001
];
networking.firewall.allowedUDPPorts = [ 3478 ];
services.netbird = {
server = {

View file

@ -4,9 +4,11 @@
config,
nodes,
...
}: let
}:
let
hostName = "nc.${config.secrets.secrets.global.domains.web}";
in {
in
{
age.secrets.maddyPasswd = {
generator.script = "alnum";
mode = "440";
@ -20,7 +22,8 @@ in {
mode = "640";
};
services.maddy.ensureCredentials = {
"nextcloud@${config.secrets.secrets.global.domains.mail_public}".passwordFile = nodes.maddy.config.age.secrets.nextcloudPasswd.path;
"nextcloud@${config.secrets.secrets.global.domains.mail_public}".passwordFile =
nodes.maddy.config.age.secrets.nextcloudPasswd.path;
};
};
environment.persistence."/persist".directories = [
@ -54,7 +57,15 @@ in {
config.adminpassFile = config.age.secrets.ncpasswd.path; # Kinda ok just remember to instanly change after first setup
config.adminuser = "admin";
extraApps = with config.services.nextcloud.package.packages.apps; {
inherit contacts calendar tasks notes maps phonetrack user_oidc;
inherit
contacts
calendar
tasks
notes
maps
phonetrack
user_oidc
;
};
maxUploadSize = "4G";
extraAppsEnable = true;
@ -93,14 +104,16 @@ in {
dbtype = "pgsql";
};
};
systemd.tmpfiles.rules = let
systemd.tmpfiles.rules =
let
mailer-passwd-conf = pkgs.writeText "nextcloud-config.php" ''
<?php
$CONFIG = [
'mail_smtppassword' => trim(file_get_contents('${config.age.secrets.maddyPasswd.path}')),
];
'';
in [
in
[
"L+ ${config.services.nextcloud.datadir}/config/mailer.config.php - - - - ${mailer-passwd-conf}"
];

View file

@ -1,8 +1,5 @@
{ config, nodes, ... }:
{
config,
nodes,
...
}: {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ 3000 ];
@ -72,15 +69,15 @@
# it includes the newline terminating the file which
# makes kanidm reject the secret
age.secrets.oauth2-client-secret-env = {
generator.dependencies = [
nodes.elisabeth-kanidm.config.age.secrets.oauth2-proxy
];
generator.script = {
generator.dependencies = [ nodes.elisabeth-kanidm.config.age.secrets.oauth2-proxy ];
generator.script =
{
lib,
decrypt,
deps,
...
}: ''
}:
''
echo -n "OAUTH2_PROXY_CLIENT_SECRET="
${decrypt} ${lib.escapeShellArg (lib.head deps).file}
'';

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ config.services.octoprint.port ];

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ config.services.open-webui.port ];

View file

@ -4,10 +4,12 @@
config,
lib,
...
}: let
}:
let
paperlessdomain = "ppl.${config.secrets.secrets.global.domains.web}";
paperlessBackupDir = "/var/cache/backups/paperless";
in {
in
{
systemd.tmpfiles.settings = {
"10-paperless".${paperlessBackupDir}.d = {
inherit (config.services.paperless) user;
@ -45,14 +47,13 @@ in {
];
};
};
systemd.services.paperless-backup = let
systemd.services.paperless-backup =
let
cfg = config.systemd.services.paperless-consumer;
in {
description = "Paperless document backup";
serviceConfig =
lib.recursiveUpdate
cfg.serviceConfig
in
{
description = "Paperless document backup";
serviceConfig = lib.recursiveUpdate cfg.serviceConfig {
ExecStart = "${config.services.paperless.package}/bin/paperless-ngx document_exporter -na -nt -f -d ${paperlessBackupDir}";
ReadWritePaths = cfg.serviceConfig.ReadWritePaths ++ [ paperlessBackupDir ];
Restart = "no";

View file

@ -4,13 +4,15 @@
lib,
pkgs,
...
}: let
}:
let
prestart = pkgs.writeShellScript "pr-tracker-pre" ''
if [ ! -d ./nixpkgs ]; then
${lib.getExe pkgs.git} clone https://github.com/NixOS/nixpkgs.git
fi
'';
in {
in
{
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ 3000 ];
@ -43,7 +45,8 @@ in {
mode = "640";
};
services.maddy.ensureCredentials = {
"pr-tracker@${config.secrets.secrets.global.domains.mail_public}".passwordFile = nodes.maddy.config.age.secrets.pr-trackerPasswd.path;
"pr-tracker@${config.secrets.secrets.global.domains.mail_public}".passwordFile =
nodes.maddy.config.age.secrets.pr-trackerPasswd.path;
};
};
systemd.sockets.pr-tracker = {

View file

@ -4,10 +4,16 @@
config,
pkgs, # not unused needed for the usage of attrs later to contains pkgs
...
} @ attrs: let
}@attrs:
let
hostName = "radicale.${config.secrets.secrets.global.domains.mail}";
in {
imports = [./containers.nix ./ddclient.nix ./acme.nix];
in
{
imports = [
./containers.nix
./ddclient.nix
./acme.nix
];
services.nginx = {
enable = true;
upstreams.radicale = {
@ -54,7 +60,10 @@ in {
enable = true;
setting = {
server = {
hosts = ["0.0.0.0:8000" "[::]:8000"];
hosts = [
"0.0.0.0:8000"
"[::]:8000"
];
auth = {
type = "htpasswd";
htpasswd_filename = "/etc/radicale/users";
@ -106,4 +115,3 @@ in {
#kanidm
#remote backups
#immich

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
services.samba-wsdd = {
enable = true; # make shares visible for windows 10 clients
openFirewall = true;
@ -55,11 +52,17 @@
wireguard.samba-patrick.server = {
host = config.secrets.secrets.global.domains.web;
port = 51830;
reservedAddresses = ["10.43.0.0/20" "fd00:1765::/112"];
reservedAddresses = [
"10.43.0.0/20"
"fd00:1765::/112"
];
openFirewall = true;
};
networking.nftables.firewall.zones.untrusted.interfaces = ["samba-patrick" "netbird-samba"];
networking.nftables.firewall.zones.untrusted.interfaces = [
"samba-patrick"
"netbird-samba"
];
services.samba = {
enable = true;
@ -106,17 +109,20 @@
"disable spoolss = yes"
"show add printer wizard = no"
];
shares = let
mkShare = {
shares =
let
mkShare =
{
name,
user ? "smb",
group ? "smb",
hasBunker ? false,
hasPaperless ? false,
persistRoot ? "/panzer",
}: cfg: let
config =
{
}:
cfg:
let
config = {
"#persistRoot" = persistRoot;
"#user" = user;
"#group" = group;
@ -131,28 +137,21 @@
"force directory mode" = "0770";
# Might be necessary for windows user to be able to open thing in smb
"acl allow execute always" = "no";
}
// cfg;
} // cfg;
in
{
"${name}" =
config
// {"path" = "/media/smb/${name}";};
"${name}" = config // {
"path" = "/media/smb/${name}";
};
}
// lib.optionalAttrs hasBunker
{
"${name}-important" =
config
// {
// lib.optionalAttrs hasBunker {
"${name}-important" = config // {
"path" = "/media/smb/${name}-important";
"#persistRoot" = "/bunker";
};
}
// lib.optionalAttrs hasPaperless
{
"${name}-paperless" =
config
// {
// lib.optionalAttrs hasPaperless {
"${name}-paperless" = config // {
"path" = "/media/smb/${name}-paperless";
"#paperless" = true;
"force user" = "paperless";
@ -199,7 +198,8 @@
user = "family";
group = "family";
} { })
(mkShare {
(mkShare
{
name = "media";
user = "family";
group = "family";
@ -208,7 +208,8 @@
{
"read only" = "yes";
"write list" = "@family";
})
}
)
];
};
# to get this file start a smbd, add users using 'smbpasswd -a <user>'
@ -216,11 +217,16 @@
age.secrets.smbpassdb = {
rekeyFile = config.node.secretsDir + "/smbpassdb.tdb.age";
};
users = let
users =
let
users = lib.unique (lib.mapAttrsToList (_: val: val."force user") config.services.samba.shares);
groups = lib.unique (users ++ (lib.mapAttrsToList (_: val: val."force group") config.services.samba.shares));
in {
users = lib.mkMerge ((lib.flip map users (user: {
groups = lib.unique (
users ++ (lib.mapAttrsToList (_: val: val."force group") config.services.samba.shares)
);
in
{
users = lib.mkMerge (
(lib.flip map users (user: {
${user} = {
isNormalUser = true;
home = "/var/empty";
@ -230,22 +236,34 @@
group = "${user}";
};
}))
++ [
{paperless.isNormalUser = lib.mkForce false;}
]);
groups = lib.mkMerge ((lib.flip map groups (group: {
${group} = {
};
++ [ { paperless.isNormalUser = lib.mkForce false; } ]
);
groups = lib.mkMerge (
(lib.flip map groups (group: {
${group} = { };
}))
++ [
{
family.members = ["patrick" "david" "helen" "ggr"];
printer.members = ["patrick" "david" "helen" "ggr"];
family.members = [
"patrick"
"david"
"helen"
"ggr"
];
printer.members = [
"patrick"
"david"
"helen"
"ggr"
];
}
]);
]
);
};
fileSystems = lib.mkMerge (lib.flip lib.mapAttrsToList config.services.samba.shares (_: v:
fileSystems = lib.mkMerge (
lib.flip lib.mapAttrsToList config.services.samba.shares (
_: v:
lib.optionalAttrs ((v ? "#paperless") && v."#paperless") {
"${v.path}/consume" = {
fsType = "none";
@ -254,17 +272,27 @@
};
"${v.path}/media/archive" = {
fsType = "none ";
options = ["bind" "ro"];
options = [
"bind"
"ro"
];
device = "/paperless/media/documents/archive/${v."#user"}";
};
"${v.path}/media/originals" = {
fsType = "none ";
options = ["bind" "ro"];
options = [
"bind"
"ro"
];
device = "/paperless/media/documents/originals/${v."#user"}";
};
}));
}
)
);
systemd.tmpfiles.settings = lib.mkMerge (lib.flip lib.mapAttrsToList config.services.samba.shares (_: v:
systemd.tmpfiles.settings = lib.mkMerge (
lib.flip lib.mapAttrsToList config.services.samba.shares (
_: v:
lib.optionalAttrs ((v ? "#paperless") && v."#paperless") {
"10-smb-paperless"."/paperless/consume/".d = {
user = "paperless";
@ -317,9 +345,13 @@
group = "paperless";
mode = "0660";
};
}));
environment.persistence = lib.mkMerge (lib.flatten [
(lib.flip lib.mapAttrsToList config.services.samba.shares (_: v:
}
)
);
environment.persistence = lib.mkMerge (
lib.flatten [
(lib.flip lib.mapAttrsToList config.services.samba.shares (
_: v:
lib.optionalAttrs ((v ? "#persistRoot") && (v."#persistRoot" != "")) {
${v."#persistRoot"}.directories = [
{
@ -329,7 +361,8 @@
mode = "0770";
}
];
}))
}
))
(lib.flip lib.mapAttrsToList config.services.netbird.tunnels (
_: v: {
"/state".directories = [
@ -340,5 +373,6 @@
];
}
))
]);
]
);
}

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [ 80 ];

View file

@ -3,9 +3,11 @@
lib,
nodes,
...
}: let
}:
let
vaultwardenDomain = "pw.${config.secrets.secrets.global.domains.web}";
in {
in
{
age.secrets.vaultwarden-env = {
rekeyFile = config.node.secretsDir + "/vaultwarden-env.age";
mode = "440";
@ -64,7 +66,8 @@ in {
mode = "640";
};
services.maddy.ensureCredentials = {
"vaultwarden@${config.secrets.secrets.global.domains.mail_public}".passwordFile = nodes.maddy.config.age.secrets.vaultwardenPasswd.path;
"vaultwarden@${config.secrets.secrets.global.domains.mail_public}".passwordFile =
nodes.maddy.config.age.secrets.vaultwardenPasswd.path;
};
};
system.activationScripts.systemd_env_smtp_passwd = {

View file

@ -1,11 +1,11 @@
{ config, pkgs, ... }:
{
config,
pkgs,
...
}: {
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [3000 80];
firewallRuleForNode.elisabeth.allowedTCPPorts = [
3000
80
];
};
age.secrets.spotifySecret = {
owner = "root";

View file

@ -101,7 +101,8 @@
};
};
outputs = {
outputs =
{
self,
nixpkgs,
flake-utils,
@ -113,7 +114,8 @@
nixos-extra-modules,
nix-topology,
...
} @ inputs: let
}@inputs:
let
inherit (nixpkgs) lib;
stateVersion = "23.05";
in
@ -129,8 +131,7 @@
};
inherit stateVersion;
inherit
(import ./nix/hosts.nix inputs)
inherit (import ./nix/hosts.nix inputs)
hosts
nixosConfigurations
minimalConfigurations
@ -139,15 +140,16 @@
nodes = self.nixosConfigurations // self.guestConfigurations;
inherit
(lib.foldl' lib.recursiveUpdate {}
(lib.mapAttrsToList
(import ./nix/generate-installer-package.nix inputs)
self.minimalConfigurations))
(lib.foldl' lib.recursiveUpdate { } (
lib.mapAttrsToList (import ./nix/generate-installer-package.nix inputs) self.minimalConfigurations
))
packages
;
}
// flake-utils.lib.eachDefaultSystem (system: rec {
apps.setupHetznerStorageBoxes = import (nixos-extra-modules + "/apps/setup-hetzner-storage-boxes.nix") {
apps.setupHetznerStorageBoxes =
import (nixos-extra-modules + "/apps/setup-hetzner-storage-boxes.nix")
{
inherit pkgs;
nixosConfigurations = self.nodes;
decryptIdentity = builtins.head self.secretsConfig.masterIdentities;
@ -191,9 +193,7 @@
.${system};
};
checks.pre-commit-check =
pre-commit-hooks.lib.${system}.run
{
checks.pre-commit-check = pre-commit-hooks.lib.${system}.run {
src = lib.cleanSource ./.;
hooks = {
nixfmt = {

View file

@ -1,8 +1,5 @@
{ inputs, lib, ... }:
{
inputs,
lib,
...
}: {
imports = [
inputs.nixos-hardware.nixosModules.common-gpu-nvidia-nonprime
inputs.nixos-hardware.nixosModules.common-cpu-intel-cpu-only
@ -51,9 +48,23 @@
device = "/dev/input/event15";
};
boot.binfmt.emulatedSystems = ["aarch64-linux" "riscv64-linux"];
nix.settings.system-features = ["kvm" "nixos-test"];
boot.kernelParams = lib.mkForce ["rd.luks.options=timeout=0" "rootflags=x-systemd.device-timeout=0" "nohibernate" "root=fstab" "loglevel=4" "nvidia-drm.modeset=1" "nvidia.NVreg_PreserveVideoMemoryAllocations=1"];
boot.binfmt.emulatedSystems = [
"aarch64-linux"
"riscv64-linux"
];
nix.settings.system-features = [
"kvm"
"nixos-test"
];
boot.kernelParams = lib.mkForce [
"rd.luks.options=timeout=0"
"rootflags=x-systemd.device-timeout=0"
"nohibernate"
"root=fstab"
"loglevel=4"
"nvidia-drm.modeset=1"
"nvidia.NVreg_PreserveVideoMemoryAllocations=1"
];
services.netbird.enable = true;
# Do not cleanup nix store to prevent having to rebuild packages onca a month

View file

@ -3,7 +3,8 @@
nodes,
lib,
...
}: {
}:
{
disko.devices = {
disk = {
m2-ssd = rec {
@ -12,9 +13,15 @@
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
boot = (partEfi "2GiB") // {device = "${device}-part1";};
swap = (partSwap "16G") // {device = "${device}-part2";};
rpool = (partLuksZfs "m2-ssd" "rpool" "100%") // {device = "${device}-part3";};
boot = (partEfi "2GiB") // {
device = "${device}-part1";
};
swap = (partSwap "16G") // {
device = "${device}-part2";
};
rpool = (partLuksZfs "m2-ssd" "rpool" "100%") // {
device = "${device}-part3";
};
};
};
};
@ -24,7 +31,9 @@
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
panzer = (partLuksZfs "sata-hdd" "panzer" "100%") // {device = "${device}-part1";};
panzer = (partLuksZfs "sata-hdd" "panzer" "100%") // {
device = "${device}-part1";
};
};
};
};

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
networking = {
inherit (config.secrets.secrets.local.networking) hostId;
};

View file

@ -3,9 +3,9 @@
minimal,
lib,
...
}: {
imports =
[
}:
{
imports = [
inputs.nixos-hardware.nixosModules.common-pc
inputs.nixos-hardware.nixosModules.common-pc-ssd
inputs.nixos-hardware.nixosModules.common-cpu-amd
@ -22,10 +22,7 @@
./blog.nix
./net.nix
./fs.nix
]
++ lib.lists.optionals (!minimal) [
./guests.nix
];
] ++ lib.lists.optionals (!minimal) [ ./guests.nix ];
services.xserver = {
xkb = {
layout = "de";

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
disko.devices = {
disk = {
internal-ssd = rec {
@ -11,8 +8,12 @@
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
boot = (partEfi "1GiB") // {device = "${device}-part1";};
rpool = (partLuksZfs "ssd" "rpool" "100%") // {device = "${device}-part2";};
boot = (partEfi "1GiB") // {
device = "${device}-part1";
};
rpool = (partLuksZfs "ssd" "rpool" "100%") // {
device = "${device}-part2";
};
};
};
};
@ -128,7 +129,10 @@
wireguard.scrtiny-patrick.server = {
host = config.secrets.secrets.global.domains.web;
port = 51831;
reservedAddresses = ["10.44.0.0/16" "fd00:1766::/112"];
reservedAddresses = [
"10.44.0.0/16"
"fd00:1766::/112"
];
openFirewall = true;
};
networking.nftables.firewall.zones.untrusted.interfaces = [ "scrtiny-patrick" ];

View file

@ -6,8 +6,11 @@
minimal,
nodes,
...
}: let
domainOf = hostName: let
}:
let
domainOf =
hostName:
let
domains = {
adguardhome = "adguardhome";
forgejo = "forge";
@ -28,21 +31,29 @@
octoprint = "print";
pr-tracker = "tracker";
};
in "${domains.${hostName}}.${config.secrets.secrets.global.domains.web}";
in
"${domains.${hostName}}.${config.secrets.secrets.global.domains.web}";
# TODO hard coded elisabeth nicht so schön
ipOf = hostName:
if nodes ? ${hostName}
then nodes.${hostName}.config.wireguard.elisabeth.ipv4
else nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4;
in {
services.nginx = let
blockOf = hostName: {
ipOf =
hostName:
if nodes ? ${hostName} then
nodes.${hostName}.config.wireguard.elisabeth.ipv4
else
nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4;
in
{
services.nginx =
let
blockOf =
hostName:
{
virtualHostExtraConfig ? "",
maxBodySize ? "500M",
port ? 3000,
upstream ? hostName,
protocol ? "http",
}: {
}:
{
upstreams.${hostName} = {
servers."${ipOf upstream}:${toString port}" = { };
extraConfig = ''
@ -65,7 +76,8 @@ in {
+ virtualHostExtraConfig;
};
};
proxyProtect = hostName: cfg: allowedGroup:
proxyProtect =
hostName: cfg: allowedGroup:
lib.mkMerge [
(blockOf hostName cfg)
{
@ -95,7 +107,9 @@ in {
};
locations."= /oauth2/auth" = {
proxyPass = "http://oauth2-proxy/oauth2/auth" + lib.optionalString allowedGroup "?allowed_groups=${hostName}_access";
proxyPass =
"http://oauth2-proxy/oauth2/auth"
+ lib.optionalString allowedGroup "?allowed_groups=${hostName}_access";
extraConfig = ''
internal;
@ -187,8 +201,7 @@ in {
maxBodySize = "5G";
port = 80;
})
(blockOf "kanidm"
{
(blockOf "kanidm" {
protocol = "https";
virtualHostExtraConfig = ''
proxy_ssl_verify off ;
@ -196,14 +209,18 @@ in {
})
];
guests = let
mkGuest = guestName: {
guests =
let
mkGuest =
guestName:
{
enablePanzer ? false,
enableRenaultFT ? false,
enableBunker ? false,
enableSharedPaperless ? false,
...
}: {
}:
{
autostart = true;
zfs."/state" = {
pool = "rpool";
@ -235,12 +252,16 @@ in {
../../config/services/${guestName}.nix
{
node.secretsDir = config.node.secretsDir + "/${guestName}";
networking.nftables.firewall.zones.untrusted.interfaces = [config.guests.${guestName}.networking.mainLinkName];
networking.nftables.firewall.zones.untrusted.interfaces = [
config.guests.${guestName}.networking.mainLinkName
];
systemd.network.networks."10-${config.guests.${guestName}.networking.mainLinkName}" = {
DHCP = lib.mkForce "no";
address = [
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName}" config.secrets.secrets.global.net.privateSubnetv4)
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName}" config.secrets.secrets.global.net.privateSubnetv6)
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName
}" config.secrets.secrets.global.net.privateSubnetv4)
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName
}" config.secrets.secrets.global.net.privateSubnetv6)
];
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
};
@ -249,9 +270,7 @@ in {
};
mkMicrovm = guestName: cfg: {
${guestName} =
mkGuest guestName cfg
// {
${guestName} = mkGuest guestName cfg // {
backend = "microvm";
microvm = {
system = "x86_64-linux";
@ -267,13 +286,17 @@ in {
};
mkContainer = guestName: cfg: {
${guestName} =
mkGuest guestName cfg
// {
${guestName} = mkGuest guestName cfg // {
backend = "container";
container.macvlan = "lan";
extraSpecialArgs = {
inherit lib nodes inputs minimal stateVersion;
inherit
lib
nodes
inputs
minimal
stateVersion
;
};
};
};
@ -292,18 +315,10 @@ in {
// mkContainer "yourspotify" { }
// mkContainer "netbird" { }
// mkContainer "kanidm" { }
// mkContainer "nextcloud" {
enablePanzer = true;
}
// mkContainer "paperless" {
enableSharedPaperless = true;
}
// mkContainer "forgejo" {
enablePanzer = true;
}
// mkMicrovm "immich" {
enablePanzer = true;
}
// mkContainer "nextcloud" { enablePanzer = true; }
// mkContainer "paperless" { enableSharedPaperless = true; }
// mkContainer "forgejo" { enablePanzer = true; }
// mkMicrovm "immich" { enablePanzer = true; }
// mkContainer "samba" {
enablePanzer = true;
enableRenaultFT = true;

View file

@ -1,14 +1,15 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
networking = {
inherit (config.secrets.secrets.local.networking) hostId;
};
systemd.network.networks = {
"10-lan01" = {
address = [(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name} config.secrets.secrets.global.net.privateSubnetv4)];
address = [
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name}
config.secrets.secrets.global.net.privateSubnetv4
)
];
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
#matchConfig.MACAddress = config.secrets.secrets.local.networking.interfaces.lan01.mac;
matchConfig.Name = "lan";
@ -33,7 +34,11 @@
networks = {
# redo the network cause the livesystem has macvlans
"10-lan01" = {
address = [(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name} config.secrets.secrets.global.net.privateSubnetv4)];
address = [
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name}
config.secrets.secrets.global.net.privateSubnetv4
)
];
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
matchConfig.MACAddress = config.secrets.secrets.local.networking.interfaces.lan01.mac;
dhcpV6Config.UseDNS = false;
@ -49,8 +54,13 @@
networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" ];
wireguard.elisabeth.server = {
host = lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name} config.secrets.secrets.global.net.privateSubnetv4;
reservedAddresses = ["10.42.0.0/20" "fd00:1764::/112"];
host =
lib.net.cidr.host config.secrets.secrets.global.net.ips.${config.node.name}
config.secrets.secrets.global.net.privateSubnetv4;
reservedAddresses = [
"10.42.0.0/20"
"fd00:1764::/112"
];
openFirewall = true;
};
# To be able to ping containers from the host, it is necessary

View file

@ -9,6 +9,11 @@
./fs.nix
];
boot.mode = "bios";
boot.initrd.availableKernelModules = ["virtio_pci" "virtio_net" "virtio_scsi" "virtio_blk"];
boot.initrd.availableKernelModules = [
"virtio_pci"
"virtio_net"
"virtio_scsi"
"virtio_blk"
];
nixpkgs.hostPlatform = "x86_64-linux";
}

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
disko.devices = {
disk = {
drive = rec {
@ -11,9 +8,15 @@
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
grub = partGrub // {device = "${device}-part1";};
bios = (partEfi "512MiB") // {device = "${device}-part2";};
rpool = (partLuksZfs "rpool" "rpool" "100%") // {device = "${device}-part3";};
grub = partGrub // {
device = "${device}-part1";
};
bios = (partEfi "512MiB") // {
device = "${device}-part2";
};
rpool = (partLuksZfs "rpool" "rpool" "100%") // {
device = "${device}-part3";
};
#(lib.attrsets.recursiveUpdate (partLuksZfs "rpool" "rpool" "17GiB" "100%") {content.extraFormatArgs = ["--pbkdf pbkdf2"];})
};
};
@ -27,7 +30,5 @@
fileSystems."/state".neededForBoot = true;
fileSystems."/persist".neededForBoot = true;
boot.loader.grub.devices = [
"/dev/disk/by-id/${config.secrets.secrets.local.disko.drive}"
];
boot.loader.grub.devices = [ "/dev/disk/by-id/${config.secrets.secrets.local.disko.drive}" ];
}

View file

@ -1,20 +1,21 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
networking.hostId = config.secrets.secrets.local.networking.hostId;
networking.domain = config.secrets.secrets.global.domains.mail_public;
boot.initrd.systemd.network = {
enable = true;
networks = {inherit (config.systemd.network.networks) "lan01";};
networks = {
inherit (config.systemd.network.networks) "lan01";
};
};
systemd.network.networks = {
"lan01" = let
"lan01" =
let
icfg = config.secrets.secrets.local.networking.interfaces.lan01;
in {
in
{
address = [
icfg.hostCidrv4
(lib.net.cidr.hostCidr 1 icfg.hostCidrv6)

View file

@ -1,8 +1,5 @@
{ inputs, lib, ... }:
{
inputs,
lib,
...
}: {
imports = [
../../config/basic
../../config/services/octoprint.nix

View file

@ -1,4 +1,5 @@
{lib, ...}: {
{ lib, ... }:
{
fileSystems = lib.mkForce {
"/" = {
device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888";

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
networking = {
inherit (config.secrets.secrets.local.networking) hostId;
wireless.iwd = {

View file

@ -1,8 +1,5 @@
{ inputs, lib, ... }:
{
inputs,
lib,
...
}: {
imports = [
inputs.nixos-hardware.nixosModules.common-cpu-intel
# for some reasons the cpu-intel includes the gpu as well
@ -45,11 +42,12 @@
layout = "de";
};
libinput = {
touchpad = lib.mkForce {
accelSpeed = "0.5";
};
touchpad = lib.mkForce { accelSpeed = "0.5"; };
};
};
nixpkgs.hostPlatform = "x86_64-linux";
nix.settings.system-features = ["kvm" "nixos-test"];
nix.settings.system-features = [
"kvm"
"nixos-test"
];
}

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
disko.devices = {
disk = {
m2-ssd = rec {
@ -11,9 +8,15 @@
content = with lib.disko.gpt; {
type = "gpt";
partitions = {
boot = (partEfi "1GiB") // {device = "${device}-part1";};
swap = (partSwap "16GiB") // {device = "${device}-part2";};
rpool = (partLuksZfs "rpool" "rpool" "100%") // {device = "${device}-part3";};
boot = (partEfi "1GiB") // {
device = "${device}-part1";
};
swap = (partSwap "16GiB") // {
device = "${device}-part2";
};
rpool = (partLuksZfs "rpool" "rpool" "100%") // {
device = "${device}-part3";
};
};
};
};

View file

@ -1,4 +1,5 @@
{config, ...}: {
{ config, ... }:
{
age.secrets.eduroam = {
rekeyFile = ./secrets/iwd/eduroam.8021x.age;
path = "/var/lib/iwd/eduroam.8021x";
@ -10,7 +11,11 @@
devoloog-sae20.rekeyFile = ./secrets/iwd/devoloog-sae20.age;
};
wireguard.samba-patrick.client.via = "elisabeth-samba";
networking.nftables.firewall.zones.untrusted.interfaces = ["lan01" "lan02" "wlan01"];
networking.nftables.firewall.zones.untrusted.interfaces = [
"lan01"
"lan02"
"wlan01"
];
networking = {
inherit (config.secrets.secrets.local.networking) hostId;
wireless.iwd = {

View file

@ -1,3 +1 @@
inputs: [
(import ./misc.nix inputs)
]
inputs: [ (import ./misc.nix inputs) ]

View file

@ -1,11 +1,9 @@
_inputs: _self: super: let
_inputs: _self: super:
let
writeText = text: (super.writeText (builtins.hashString "sha256" "${text}") "${text}");
in {
lib =
super.lib
// {
inherit
writeText
;
in
{
lib = super.lib // {
inherit writeText;
};
}

View file

@ -1,10 +1,6 @@
{
lib,
config,
...
}: let
inherit
(lib)
{ lib, config, ... }:
let
inherit (lib)
mkEnableOption
mkMerge
attrNames
@ -18,7 +14,8 @@
mapAttrs'
listToAttrs
;
in {
in
{
home-manager.sharedModules = [
{
options.images = {
@ -39,16 +36,15 @@ in {
imports = [
(
{config, ...}: {
{ config, ... }:
{
age.secrets = mkMerge (
flip map
(attrNames config.home-manager.users)
(
flip map (attrNames config.home-manager.users) (
user:
mkIf config.home-manager.users.${user}.images.enable (
listToAttrs (flip map (attrNames (filterAttrs (_: type: type == "regular") (builtins.readDir ../secrets/img)))
(
file: {
listToAttrs (
flip map (attrNames (filterAttrs (_: type: type == "regular") (builtins.readDir ../secrets/img)))
(file: {
name = "images-${user}-${file}";
value = {
name = removeSuffix ".age" file;
@ -56,8 +52,8 @@ in {
owner = user;
group = user;
};
}
))
})
)
)
)
);

View file

@ -1,10 +1,6 @@
{
config,
lib,
...
}: let
inherit
(lib)
{ config, lib, ... }:
let
inherit (lib)
flip
mapAttrs
attrNames
@ -13,7 +9,8 @@
mkMerge
isAttrs
;
in {
in
{
# Expose a home manager module for each user that allows extending
# environment.persistence.${sourceDir}.users.${userName} simply by
# specifying home.persistence.${sourceDir} in home manager.
@ -22,7 +19,8 @@ in {
options.home.persistence = mkOption {
description = "Additional persistence config for the given source path";
default = { };
type = types.attrsOf (types.submodule {
type = types.attrsOf (
types.submodule {
options = {
files = mkOption {
description = "Additional files to persist via NixOS impermanence.";
@ -36,39 +34,31 @@ in {
default = [ ];
};
};
});
}
);
};
}
];
# For each user that has a home-manager config, merge the locally defined
# persistence options that we defined above.
imports = let
mkUserFiles = map (x:
{parentDirectory.mode = "700";}
// (
if isAttrs x
then x
else {file = x;}
));
mkUserDirs = map (x:
{mode = "700";}
// (
if isAttrs x
then x
else {directory = x;}
));
in [
imports =
let
mkUserFiles = map (
x: { parentDirectory.mode = "700"; } // (if isAttrs x then x else { file = x; })
);
mkUserDirs = map (x: { mode = "700"; } // (if isAttrs x then x else { directory = x; }));
in
[
{
environment.persistence = mkMerge (
flip map
(attrNames config.home-manager.users)
(
user: let
flip map (attrNames config.home-manager.users) (
user:
let
hmUserCfg = config.home-manager.users.${user};
in
flip mapAttrs hmUserCfg.home.persistence
(_: sourceCfg: {
flip mapAttrs hmUserCfg.home.persistence (
_: sourceCfg: {
users.${user} = {
# This needs to be set for allo users with non
# standart home (not /home/<userName>
@ -77,16 +67,12 @@ in {
# as there will be infinite recursion
# If this setting is forgotten there
# are assertions in place warning you
home =
{
root = "/root";
}
.${user}
or "/home/${user}";
home = { root = "/root"; }.${user} or "/home/${user}";
files = mkUserFiles sourceCfg.files;
directories = mkUserDirs sourceCfg.directories;
};
})
}
)
)
);
}

View file

@ -1,10 +1,6 @@
{
lib,
pkgs,
...
}: let
inherit
(lib)
{ lib, pkgs, ... }:
let
inherit (lib)
types
mkEnableOption
mkPackageOption
@ -12,9 +8,12 @@
mkIf
;
settingsFormat = pkgs.formats.json { };
in {
in
{
home-manager.sharedModules = [
({config, ...}: let
(
{ config, ... }:
let
cfg = settingsFormat.generate "config.json" {
streamdeck_ui_version = 2;
state = config.programs.streamdeck-ui.settings;
@ -22,7 +21,8 @@ in {
preStart = pkgs.writeShellScript "streamdeck-setup-config" ''
${pkgs.coreutils}/bin/cp "${cfg}" "$XDG_RUNTIME_DIR/streamdeck/config.json"
'';
in {
in
{
options.programs.streamdeck-ui = {
enable = mkEnableOption "streamdeck-ui";
package = mkPackageOption pkgs "streamdeck-ui" { };
@ -53,6 +53,7 @@ in {
};
};
};
})
}
)
];
}

View file

@ -3,9 +3,9 @@
pkgs,
config,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
types
mkEnableOption
mkPackageOption
@ -16,7 +16,8 @@
configFile = formatType.generate "config.json" cfg.settings;
formatType = pkgs.formats.json { };
in {
in
{
options.services.actual = {
enable = mkEnableOption "actual, a privacy focused app for managing your finances";
package = mkPackageOption pkgs "actual" { };

View file

@ -1,10 +1,6 @@
{
lib,
config,
...
}: let
inherit
(lib)
{ lib, config, ... }:
let
inherit (lib)
concatLists
flip
mapAttrsToList
@ -16,7 +12,8 @@
;
cfg = config.users.deterministicIds;
in {
in
{
options = {
users.deterministicIds = mkOption {
default = { };
@ -25,7 +22,8 @@ in {
used on the system without specifying a uid/gid, this module will assign the
corresponding ids defined here, or show an error if the definition is missing.
'';
type = types.attrsOf (types.submodule {
type = types.attrsOf (
types.submodule {
options = {
uid = mkOption {
type = types.nullOr types.int;
@ -38,31 +36,46 @@ in {
description = mdDoc "The gid to assign if it is missing in `users.groups.<name>`.";
};
};
});
}
);
};
users.users = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
config.uid = let
type = types.attrsOf (
types.submodule (
{ name, ... }:
{
config.uid =
let
deterministicUid = cfg.${name}.uid or null;
in
mkIf (deterministicUid != null) (mkDefault deterministicUid);
}));
}
)
);
};
users.groups = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
config.gid = let
type = types.attrsOf (
types.submodule (
{ name, ... }:
{
config.gid =
let
deterministicGid = cfg.${name}.gid or null;
in
mkIf (deterministicGid != null) (mkDefault deterministicGid);
}));
}
)
);
};
};
config = {
assertions =
concatLists (flip mapAttrsToList config.users.users (name: user: [
concatLists (
flip mapAttrsToList config.users.users (
name: user: [
{
assertion = user.uid != null;
message = "non-deterministic uid detected for '${name}', please assign one via `users.deterministicIds`";
@ -71,10 +84,14 @@ in {
assertion = !user.autoSubUidGidRange;
message = "non-deterministic subUids/subGids detected for: ${name}";
}
]))
++ flip mapAttrsToList config.users.groups (name: group: {
]
)
)
++ flip mapAttrsToList config.users.groups (
name: group: {
assertion = group.gid != null;
message = "non-deterministic gid detected for '${name}', please assign one via `users.deterministicIds`";
});
}
);
};
}

View file

@ -3,9 +3,9 @@
lib,
nodes,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
attrNames
concatMap
concatStringsSep
@ -21,16 +21,20 @@
;
nodeName = config.node.name;
mkForwardedOption = path:
mkForwardedOption =
path:
mkOption {
type = mkOptionType {
name = "Same type that the receiving option `${concatStringsSep "." path}` normally accepts.";
merge = _loc: defs:
builtins.filter
(x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty"))
(map (x: x.value) defs);
merge =
_loc: defs:
builtins.filter (x: builtins.isAttrs x -> ((x._type or "") != "__distributed_config_empty")) (
map (x: x.value) defs
);
};
default = {
_type = "__distributed_config_empty";
};
default = {_type = "__distributed_config_empty";};
description = ''
Anything specified here will be forwarded to `${concatStringsSep "." path}`
on the given node. Forwarding happens as-is to the raw values,
@ -39,23 +43,34 @@
};
forwardedOptions = [
["age" "secrets"]
["services" "maddy" "ensureCredentials"]
[
"age"
"secrets"
]
[
"services"
"maddy"
"ensureCredentials"
]
];
attrsForEachOption = f: (foldl' (acc: path: recursiveUpdate acc (setAttrByPath path (f path))) {} forwardedOptions);
in {
attrsForEachOption =
f: (foldl' (acc: path: recursiveUpdate acc (setAttrByPath path (f path))) { } forwardedOptions);
in
{
options.nodes = mkOption {
description = "Options forwareded to the given node.";
default = { };
type = types.attrsOf (types.submodule {
options = attrsForEachOption mkForwardedOption;
});
type = types.attrsOf (types.submodule { options = attrsForEachOption mkForwardedOption; });
};
config = let
mergeConfigFromOthers = let
getConfig = path: otherNode: let
config =
let
mergeConfigFromOthers =
let
getConfig =
path: otherNode:
let
cfg = nodes.${otherNode}.config.nodes.${nodeName} or null;
in
optionals (cfg != null) (getAttrFromPath path cfg);

View file

@ -3,17 +3,18 @@
config,
pkgs,
...
}: let
}:
let
cfg = config.services.homebox;
inherit
(lib)
inherit (lib)
mkEnableOption
mkPackageOption
mkDefault
types
mkIf
;
in {
in
{
options.services.homebox = {
enable = mkEnableOption "homebox";
package = mkPackageOption pkgs "homebox" { };

View file

@ -3,16 +3,18 @@
pkgs,
config,
...
}: {
options.networking.wireless.iwd = let
inherit
(lib)
}:
{
options.networking.wireless.iwd =
let
inherit (lib)
mkOption
literalExample
types
hasAttrByPath
;
in {
in
{
networks = mkOption {
default = { };
example = literalExample ''
@ -32,21 +34,41 @@
<citerefentry><refentrytitle>iwctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
'';
type = types.attrsOf (types.submodule ({config, ...}: {
type = types.attrsOf (
types.submodule (
{ config, ... }:
{
config.kind =
if (hasAttrByPath ["Security" "Passphrase"] config.settings)
then "psk"
else if !(hasAttrByPath ["Security"] config.settings)
then "open"
else "8021x";
if
(hasAttrByPath [
"Security"
"Passphrase"
] config.settings)
then
"psk"
else if !(hasAttrByPath [ "Security" ] config.settings) then
"open"
else
"8021x";
options = {
kind = mkOption {
type = types.enum ["open" "psk" "8021x"];
type = types.enum [
"open"
"psk"
"8021x"
];
description = "The type of network. This will determine the file ending. The module will try to determine this automatically so this should only be set when the heuristics fail.";
};
settings = mkOption {
type = with types; (attrsOf (attrsOf (oneOf [str path])));
type =
with types;
(attrsOf (
attrsOf (oneOf [
str
path
])
));
description = ''
Contents of the iwd config file for this network
The lowest level values should be files, that will be read into the config files
@ -54,13 +76,15 @@
default = { };
};
};
}));
}
)
);
};
};
config = let
inherit
(lib)
config =
let
inherit (lib)
mkIf
flip
mapAttrsToList
@ -83,22 +107,36 @@
mkIf cfg.enable {
systemd.services.iwd = mkIf (cfg.networks != { }) {
path = [ encoder ];
preStart = let
preStart =
let
dataDir = "/var/lib/iwd";
in ''
in
''
# Create config files for declaratively defined networks in the NixOS config.
${concatStringsSep "\n" (flip mapAttrsToList cfg.networks (network: config: ''
${concatStringsSep "\n" (
flip mapAttrsToList cfg.networks (
network: config: ''
filename=${dataDir}/"$(encoder '${network}.${config.kind}')"
touch "$filename"
cat >$filename <<EOF
${concatStringsSep "\n" (flip mapAttrsToList config.settings (toplevel: config: ''
${concatStringsSep "\n" (
flip mapAttrsToList config.settings (
toplevel: config: ''
[${toplevel}]
${concatStringsSep "\n" (flip mapAttrsToList config (name: value: ''
${concatStringsSep "\n" (
flip mapAttrsToList config (
name: value: ''
${name}=$(<${value})
''))}
''))}
''
)
)}
''
)
)}
EOF
''))}
''
)
)}
'';
};
};

View file

@ -4,9 +4,9 @@
options,
pkgs,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
any
attrNames
attrValues
@ -46,19 +46,26 @@
serverConfigFile = settingsFormat.generate "server.toml" (filterConfig cfg.serverSettings);
clientConfigFile = settingsFormat.generate "kanidm-config.toml" (filterConfig cfg.clientSettings);
unixConfigFile = settingsFormat.generate "kanidm-unixd.toml" (filterConfig cfg.unixSettings);
certPaths = builtins.map builtins.dirOf [cfg.serverSettings.tls_chain cfg.serverSettings.tls_key];
certPaths = builtins.map builtins.dirOf [
cfg.serverSettings.tls_chain
cfg.serverSettings.tls_key
];
# Merge bind mount paths and remove paths where a prefix is already mounted.
# This makes sure that if e.g. the tls_chain is in the nix store and /nix/store is already in the mount
# paths, no new bind mount is added. Adding subpaths caused problems on ofborg.
hasPrefixInList = list: newPath: any (path: hasPrefix (builtins.toString path) (builtins.toString newPath)) list;
mergePaths = foldl' (merged: newPath: let
hasPrefixInList =
list: newPath: any (path: hasPrefix (builtins.toString path) (builtins.toString newPath)) list;
mergePaths = foldl' (
merged: newPath:
let
# If the new path is a prefix to some existing path, we need to filter it out
filteredPaths = filter (p: !hasPrefix (builtins.toString newPath) (builtins.toString p)) merged;
# If a prefix of the new path is already in the list, do not add it
filteredNew = optional (!hasPrefixInList filteredPaths newPath) newPath;
in
filteredPaths ++ filteredNew) [];
filteredPaths ++ filteredNew
) [ ];
defaultServiceConfig = {
BindReadOnlyPaths = [
@ -97,12 +104,16 @@
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = ["@system-service" "~@privileged @resources @setuid @keyring"];
SystemCallFilter = [
"@system-service"
"~@privileged @resources @setuid @keyring"
];
# Does not work well with the temporary root
#UMask = "0066";
};
mkPresentOption = what:
mkPresentOption =
what:
mkOption {
description = mdDoc "Whether to ensure that this ${what} is present or absent.";
type = types.bool;
@ -111,20 +122,21 @@
filterPresent = filterAttrs (_: v: v.present);
provisionStateJson = pkgs.writeText "provision-state.json" (builtins.toJSON {
inherit (cfg.provision) groups persons systems;
});
provisionStateJson = pkgs.writeText "provision-state.json" (
builtins.toJSON { inherit (cfg.provision) groups persons systems; }
);
serverPort =
# ipv6:
if hasInfix "]:" cfg.serverSettings.bindaddress
then last (splitString "]:" cfg.serverSettings.bindaddress)
if hasInfix "]:" cfg.serverSettings.bindaddress then
last (splitString "]:" cfg.serverSettings.bindaddress)
else
# ipv4:
if hasInfix "." cfg.serverSettings.bindaddress
then last (splitString ":" cfg.serverSettings.bindaddress)
if hasInfix "." cfg.serverSettings.bindaddress then
last (splitString ":" cfg.serverSettings.bindaddress)
# default is 8443
else "8443";
else
"8443";
# Only recover the admin account if a password should explicitly be provisioned
# for the account. Otherwise it is not needed for provisioning.
@ -141,8 +153,8 @@
# for the account we set it, otherwise we generate a new one because it is required
# for provisioning.
recoverIdmAdmin =
if cfg.provision.idmAdminPasswordFile != null
then ''
if cfg.provision.idmAdminPasswordFile != null then
''
KANIDM_IDM_ADMIN_PASSWORD=$(< ${cfg.provision.idmAdminPasswordFile})
# We always reset the idm_admin account password if a desired password was specified.
if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_IDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} idm_admin --from-environment >/dev/null; then
@ -150,7 +162,8 @@
exit 1
fi
''
else ''
else
''
# Recover idm_admin account
if ! recover_out=$(${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} idm_admin -o json); then
echo "$recover_out" >&2
@ -191,7 +204,8 @@
KANIDM_PROVISION_IDM_ADMIN_TOKEN=$KANIDM_IDM_ADMIN_PASSWORD \
${getExe pkgs.kanidm-provision} --url "${cfg.provision.instanceUrl}" --state ${provisionStateJson} ${optionalString cfg.provision.acceptInvalidCerts "--accept-invalid-certs"}
'';
in {
in
{
options.services.kanidm = {
enableClient = mkEnableOption (mdDoc "the Kanidm client");
enableServer = mkEnableOption (mdDoc "the Kanidm server");
@ -253,12 +267,20 @@ in {
log_level = mkOption {
description = mdDoc "Log level of the server.";
default = "info";
type = types.enum ["info" "debug" "trace"];
type = types.enum [
"info"
"debug"
"trace"
];
};
role = mkOption {
description = mdDoc "The role of this server. This affects the replication relationship and thereby available features.";
default = "WriteReplica";
type = types.enum ["WriteReplica" "WriteReplicaNoUI" "ReadOnlyReplica"];
type = types.enum [
"WriteReplica"
"WriteReplicaNoUI"
"ReadOnlyReplica"
];
};
online_backup = {
path = mkOption {
@ -388,7 +410,8 @@ in {
groups = mkOption {
description = "Provisioning of kanidm groups";
default = { };
type = types.attrsOf (types.submodule (groupSubmod: {
type = types.attrsOf (
types.submodule (groupSubmod: {
options = {
present = mkPresentOption "group";
@ -399,17 +422,23 @@ in {
default = [ ];
};
};
config.members = concatLists (flip mapAttrsToList cfg.provision.persons (
config.members = concatLists (
flip mapAttrsToList cfg.provision.persons (
person: personCfg:
optional (personCfg.present && builtins.elem groupSubmod.config._module.args.name personCfg.groups) person
));
}));
optional (
personCfg.present && builtins.elem groupSubmod.config._module.args.name personCfg.groups
) person
)
);
})
);
};
persons = mkOption {
description = "Provisioning of kanidm persons";
default = { };
type = types.attrsOf (types.submodule {
type = types.attrsOf (
types.submodule {
options = {
present = mkPresentOption "person";
@ -440,13 +469,15 @@ in {
default = [ ];
};
};
});
}
);
};
systems.oauth2 = mkOption {
description = "Provisioning of oauth2 resource servers";
default = { };
type = types.attrsOf (types.submodule {
type = types.attrsOf (
types.submodule {
options = {
present = mkPresentOption "oauth2 resource server";
@ -543,14 +574,19 @@ in {
See [Claim Maps](https://kanidm.github.io/kanidm/master/integrations/oauth2.html#custom-claim-maps) for more information.
'';
default = { };
type = types.attrsOf (types.submodule {
type = types.attrsOf (
types.submodule {
options = {
joinType = mkOption {
description = ''
Determines how multiple values are joined to create the claim value.
See [Claim Maps](https://kanidm.github.io/kanidm/master/integrations/oauth2.html#custom-claim-maps) for more information.
'';
type = types.enum ["array" "csv" "ssv"];
type = types.enum [
"array"
"csv"
"ssv"
];
default = "array";
};
@ -560,54 +596,58 @@ in {
type = types.attrsOf (types.listOf types.str);
};
};
});
}
);
};
};
});
}
);
};
};
};
config = mkIf (cfg.enableClient || cfg.enableServer || cfg.enablePam) {
assertions = let
entityList = type: attrs: flip mapAttrsToList (filterPresent attrs) (name: _: {inherit type name;});
assertions =
let
entityList =
type: attrs: flip mapAttrsToList (filterPresent attrs) (name: _: { inherit type name; });
entities =
entityList "group" cfg.provision.groups
++ entityList "person" cfg.provision.persons
++ entityList "oauth2" cfg.provision.systems.oauth2;
# Accumulate entities by name. Track corresponding entity types for later duplicate check.
entitiesByName =
foldl' (
acc: {
type,
name,
}:
acc
// {
${name} = (acc.${name} or []) ++ [type];
}
) {}
entities;
entitiesByName = foldl' (
acc: { type, name }: acc // { ${name} = (acc.${name} or [ ]) ++ [ type ]; }
) { } entities;
assertGroupsKnown = opt: groups: let
assertGroupsKnown =
opt: groups:
let
knownGroups = attrNames (filterPresent cfg.provision.groups);
unknownGroups = subtractLists knownGroups groups;
in {
in
{
assertion = (cfg.enableServer && cfg.provision.enable) -> unknownGroups == [ ];
message = "${opt} refers to unknown groups: ${toString unknownGroups}";
};
assertEntitiesKnown = opt: entities: let
assertEntitiesKnown =
opt: entities:
let
unknownEntities = subtractLists (attrNames entitiesByName) entities;
in {
in
{
assertion = (cfg.enableServer && cfg.provision.enable) -> unknownEntities == [ ];
message = "${opt} refers to unknown entities: ${toString unknownEntities}";
};
in
[
{
assertion = !cfg.enableServer || ((cfg.serverSettings.tls_chain or null) == null) || (!isStorePath cfg.serverSettings.tls_chain);
assertion =
!cfg.enableServer
|| ((cfg.serverSettings.tls_chain or null) == null)
|| (!isStorePath cfg.serverSettings.tls_chain);
message = ''
<option>services.kanidm.serverSettings.tls_chain</option> points to
a file in the Nix store. You should use a quoted absolute path to
@ -615,7 +655,10 @@ in {
'';
}
{
assertion = !cfg.enableServer || ((cfg.serverSettings.tls_key or null) == null) || (!isStorePath cfg.serverSettings.tls_key);
assertion =
!cfg.enableServer
|| ((cfg.serverSettings.tls_key or null) == null)
|| (!isStorePath cfg.serverSettings.tls_key);
message = ''
<option>services.kanidm.serverSettings.tls_key</option> points to
a file in the Nix store. You should use a quoted absolute path to
@ -639,9 +682,10 @@ in {
{
assertion =
!cfg.enableServer
|| (cfg.serverSettings.domain
== null
-> cfg.serverSettings.role == "WriteReplica" || cfg.serverSettings.role == "WriteReplicaNoUI");
|| (
cfg.serverSettings.domain == null
-> cfg.serverSettings.role == "WriteReplica" || cfg.serverSettings.role == "WriteReplicaNoUI"
);
message = ''
<option>services.kanidm.serverSettings.domain</option> can only be set if this instance
is not a ReadOnlyReplica. Otherwise the db would inherit it from
@ -655,13 +699,14 @@ in {
# If any secret is provisioned, the kanidm package must have some required patches applied to it
{
assertion =
(cfg.provision.enable
(
cfg.provision.enable
&& (
cfg.provision.adminPasswordFile
!= null
cfg.provision.adminPasswordFile != null
|| cfg.provision.idmAdminPasswordFile != null
|| any (x: x.basicSecretFile != null) (attrValues (filterPresent cfg.provision.systems.oauth2))
))
)
)
-> cfg.package.enableSecretProvisioning;
message = ''
Specifying an admin account password or oauth2 basicSecretFile requires kanidm to be built with the secret provisioning patches.
@ -669,15 +714,20 @@ in {
'';
}
# Entity names must be globally unique:
(let
(
let
# Filter all names that occurred in more than one entity type.
duplicateNames = filterAttrs (_: v: builtins.length v > 1) entitiesByName;
in {
in
{
assertion = cfg.provision.enable -> duplicateNames == { };
message = ''
services.kanidm.provision requires all entity names (group, person, oauth2, ...) to be unique!
${concatLines (mapAttrsToList (name: xs: " - '${name}' used as: ${toString xs}") duplicateNames)}'';
})
${concatLines (
mapAttrsToList (name: xs: " - '${name}' used as: ${toString xs}") duplicateNames
)}'';
}
)
]
++ flip mapAttrsToList (filterPresent cfg.provision.persons) (
person: personCfg:
@ -687,36 +737,55 @@ in {
group: groupCfg:
assertEntitiesKnown "services.kanidm.provision.groups.${group}.members" groupCfg.members
)
++ concatLists (flip mapAttrsToList (filterPresent cfg.provision.systems.oauth2) (
++ concatLists (
flip mapAttrsToList (filterPresent cfg.provision.systems.oauth2) (
oauth2: oauth2Cfg:
[
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.scopeMaps" (attrNames oauth2Cfg.scopeMaps))
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.supplementaryScopeMaps" (attrNames oauth2Cfg.supplementaryScopeMaps))
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.scopeMaps" (
attrNames oauth2Cfg.scopeMaps
))
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.supplementaryScopeMaps" (
attrNames oauth2Cfg.supplementaryScopeMaps
))
]
++ concatLists (flip mapAttrsToList oauth2Cfg.claimMaps (claim: claimCfg: [
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.claimMaps.${claim}.valuesByGroup" (attrNames claimCfg.valuesByGroup))
++ concatLists (
flip mapAttrsToList oauth2Cfg.claimMaps (
claim: claimCfg: [
(assertGroupsKnown "services.kanidm.provision.systems.oauth2.${oauth2}.claimMaps.${claim}.valuesByGroup" (
attrNames claimCfg.valuesByGroup
))
# At least one group must map to a value in each claim map
{
assertion = (cfg.provision.enable && cfg.enableServer) -> any (xs: xs != []) (attrValues claimCfg.valuesByGroup);
assertion =
(cfg.provision.enable && cfg.enableServer)
-> any (xs: xs != [ ]) (attrValues claimCfg.valuesByGroup);
message = "services.kanidm.provision.systems.oauth2.${oauth2}.claimMaps.${claim} does not specify any values for any group";
}
# Public clients cannot define a basic secret
{
assertion = (cfg.provision.enable && cfg.enableServer && oauth2Cfg.public) -> oauth2Cfg.basicSecretFile == null;
assertion =
(cfg.provision.enable && cfg.enableServer && oauth2Cfg.public) -> oauth2Cfg.basicSecretFile == null;
message = "services.kanidm.provision.systems.oauth2.${oauth2} is a public client and thus cannot specify a basic secret";
}
# Public clients cannot disable PKCE
{
assertion = (cfg.provision.enable && cfg.enableServer && oauth2Cfg.public) -> !oauth2Cfg.allowInsecureClientDisablePkce;
assertion =
(cfg.provision.enable && cfg.enableServer && oauth2Cfg.public)
-> !oauth2Cfg.allowInsecureClientDisablePkce;
message = "services.kanidm.provision.systems.oauth2.${oauth2} is a public client and thus cannot disable PKCE";
}
# Non-public clients cannot enable localhost redirects
{
assertion = (cfg.provision.enable && cfg.enableServer && !oauth2Cfg.public) -> !oauth2Cfg.enableLocalhostRedirects;
assertion =
(cfg.provision.enable && cfg.enableServer && !oauth2Cfg.public)
-> !oauth2Cfg.enableLocalhostRedirects;
message = "services.kanidm.provision.systems.oauth2.${oauth2} is a non-public client and thus cannot enable localhost redirects";
}
]))
));
]
)
)
)
);
environment.systemPackages = mkIf cfg.enableClient [ cfg.package ];
@ -734,10 +803,12 @@ in {
after = [ "network.target" ];
serviceConfig = mkMerge [
# Merge paths and ignore existing prefixes needs to sidestep mkMerge
(defaultServiceConfig
(
defaultServiceConfig
// {
BindReadOnlyPaths = mergePaths (defaultServiceConfig.BindReadOnlyPaths ++ certPaths);
})
}
)
{
StateDirectory = "kanidm";
StateDirectoryMode = "0700";
@ -760,7 +831,11 @@ in {
PrivateUsers = mkForce false;
# Port needs to be exposed to the host network
PrivateNetwork = mkForce false;
RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"];
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
TemporaryFileSystem = "/:ro";
}
];
@ -771,7 +846,10 @@ in {
description = "Kanidm PAM daemon";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
restartTriggers = [unixConfigFile clientConfigFile];
restartTriggers = [
unixConfigFile
clientConfigFile
];
serviceConfig = mkMerge [
defaultServiceConfig
{
@ -796,7 +874,11 @@ in {
];
# Needs to connect to kanidmd
PrivateNetwork = mkForce false;
RestrictAddressFamilies = ["AF_INET" "AF_INET6" "AF_UNIX"];
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
TemporaryFileSystem = "/:ro";
}
];
@ -806,9 +888,15 @@ in {
systemd.services.kanidm-unixd-tasks = mkIf cfg.enablePam {
description = "Kanidm PAM home management daemon";
wantedBy = [ "multi-user.target" ];
after = ["network.target" "kanidm-unixd.service"];
after = [
"network.target"
"kanidm-unixd.service"
];
partOf = [ "kanidm-unixd.service" ];
restartTriggers = [unixConfigFile clientConfigFile];
restartTriggers = [
unixConfigFile
clientConfigFile
];
serviceConfig = {
ExecStart = "${cfg.package}/bin/kanidm_unixd_tasks";
@ -828,7 +916,12 @@ in {
"/run/kanidm-unixd:/var/run/kanidm-unixd"
];
# CAP_DAC_OVERRIDE is needed to ignore ownership of unixd socket
CapabilityBoundingSet = ["CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_DAC_READ_SEARCH"];
CapabilityBoundingSet = [
"CAP_CHOWN"
"CAP_FOWNER"
"CAP_DAC_OVERRIDE"
"CAP_DAC_READ_SEARCH"
];
IPAddressDeny = "any";
# Need access to users
PrivateUsers = false;
@ -843,15 +936,11 @@ in {
# These paths are hardcoded
environment.etc = mkMerge [
(mkIf cfg.enableServer {
"kanidm/server.toml".source = serverConfigFile;
})
(mkIf cfg.enableServer { "kanidm/server.toml".source = serverConfigFile; })
(mkIf options.services.kanidm.clientSettings.isDefined {
"kanidm/config".source = clientConfigFile;
})
(mkIf cfg.enablePam {
"kanidm/unixd".source = unixConfigFile;
})
(mkIf cfg.enablePam { "kanidm/unixd".source = unixConfigFile; })
];
system.nssModules = mkIf cfg.enablePam [ cfg.package ];
@ -860,12 +949,8 @@ in {
system.nssDatabases.passwd = optional cfg.enablePam "kanidm";
users.groups = mkMerge [
(mkIf cfg.enableServer {
kanidm = {};
})
(mkIf cfg.enablePam {
kanidm-unixd = {};
})
(mkIf cfg.enableServer { kanidm = { }; })
(mkIf cfg.enablePam { kanidm-unixd = { }; })
];
users.users = mkMerge [
(mkIf cfg.enableServer {
@ -886,6 +971,10 @@ in {
];
};
meta.maintainers = with lib.maintainers; [erictapen Flakebi oddlama];
meta.maintainers = with lib.maintainers; [
erictapen
Flakebi
oddlama
];
meta.buildDocsInSandbox = false;
}

View file

@ -1,10 +1,8 @@
{lib, ...}: let
inherit
(lib)
mkOption
types
;
in {
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.node = {
secretsDir = mkOption {
description = "Path to the secrets directory for this node.";

View file

@ -3,9 +3,9 @@
lib,
pkgs,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
attrNames
getExe
literalExpression
@ -22,8 +22,7 @@
versionOlder
;
inherit
(lib.types)
inherit (lib.types)
attrsOf
port
str
@ -36,7 +35,8 @@
kernel = config.boot.kernelPackages;
cfg = config.services.netbird;
in {
in
{
meta.maintainers = with maintainers; [
misuzu
thubrecht
@ -51,11 +51,8 @@ in {
tunnels = mkOption {
type = attrsOf (
submodule (
{ name, config, ... }:
{
name,
config,
...
}: {
options = {
port = mkOption {
type = port;
@ -132,8 +129,7 @@ in {
networking.dhcpcd.denyInterfaces = attrNames cfg.tunnels;
systemd.network.networks = mkIf config.networking.useNetworkd (
mapAttrs'
(
mapAttrs' (
name: _:
nameValuePair "50-netbird-${name}" {
matchConfig = {
@ -144,14 +140,12 @@ in {
ActivationPolicy = "manual";
};
}
)
cfg.tunnels
) cfg.tunnels
);
systemd.services =
mapAttrs'
(
name: {
systemd.services = mapAttrs' (
name:
{
environment,
stateDir,
environmentFile,
@ -178,10 +172,7 @@ in {
StateDirectory = stateDir;
StateDirectoryMode = "0700";
WorkingDirectory = "/var/lib/${stateDir}";
RuntimeDirectoryMode =
if userAccess
then "0755"
else "0750";
RuntimeDirectoryMode = if userAccess then "0755" else "0750";
# hardening
LockPersonality = true;
@ -222,8 +213,7 @@ in {
stopIfChanged = false;
}
)
cfg.tunnels;
) cfg.tunnels;
})
];
}

View file

@ -3,9 +3,9 @@
inputs,
config,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
mapAttrs
assertMsg
types
@ -16,22 +16,25 @@
# If the given expression is a bare set, it will be wrapped in a function,
# so that the imported file can always be applied to the inputs, similar to
# how modules can be functions or sets.
constSet = x:
if builtins.isAttrs x
then (_: x)
else x;
constSet = x: if builtins.isAttrs x then (_: x) else x;
rageImportEncrypted = assert assertMsg (builtins ? extraBuiltins.rageImportEncrypted) "The rageImportEncrypted extra plugin is not loaded";
rageImportEncrypted =
assert assertMsg (
builtins ? extraBuiltins.rageImportEncrypted
) "The rageImportEncrypted extra plugin is not loaded";
builtins.extraBuiltins.rageImportEncrypted;
# This "imports" an encrypted .nix.age file
importEncrypted = path:
importEncrypted =
path:
constSet (
if builtins.pathExists path
then rageImportEncrypted inputs.self.secretsConfig.masterIdentities path
else {}
if builtins.pathExists path then
rageImportEncrypted inputs.self.secretsConfig.masterIdentities path
else
{ }
);
cfg = config.secrets;
in {
in
{
options.secrets = {
defineRageBuiltins = mkOption {
default = true;
@ -56,15 +59,16 @@ in {
secrets = mkOption {
readOnly = true;
default =
mapAttrs (_: x: importEncrypted x inputs) cfg.secretFiles;
default = mapAttrs (_: x: importEncrypted x inputs) cfg.secretFiles;
description = mdDoc ''
the secrets decrypted from the secretFiles
'';
};
};
config.home-manager.sharedModules = [
({config, ...}: {
(
{ config, ... }:
{
options = {
userSecretsFile = mkOption {
default = ../users/${config._module.args.name}/secrets.nix.age;
@ -78,6 +82,7 @@ in {
description = "User secrets";
};
};
})
}
)
];
}

View file

@ -3,9 +3,9 @@
config,
lib,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
mkOption
types
flip
@ -19,14 +19,18 @@
"x-systemd.device-timeout=5s"
"x-systemd.mount-timeout=5s"
];
in {
in
{
# Give users the ability to add their own smb shares
home-manager.sharedModules = [
{
options.home.smb = mkOption {
description = "Samba shares to be mountable under $HOME/smb";
default = [ ];
type = types.listOf (types.submodule ({config, ...}: {
type = types.listOf (
types.submodule (
{ config, ... }:
{
options = {
localPath = mkOption {
description = "The path under which the share will be mounted. Defaults to the remotePath";
@ -53,7 +57,9 @@ in {
type = types.bool;
};
};
}));
}
)
);
};
}
];
@ -61,22 +67,18 @@ in {
imports = [
{
environment.systemPackages = [ pkgs.cifs-utils ];
fileSystems =
mkMerge
(
flip
concatMap
(attrNames config.home-manager.users)
(
user: let
fileSystems = mkMerge (
flip concatMap (attrNames config.home-manager.users) (
user:
let
parentPath = "/home/${user}/smb";
cfg = config.home-manager.users.${user}.home.smb;
inherit (config.users.users.${user}) uid;
inherit (config.users.groups.${user}) gid;
in
flip map cfg (
cfg: {
"${parentPath}/${cfg.localPath}" = let
flip map cfg (cfg: {
"${parentPath}/${cfg.localPath}" =
let
options =
baseOptions
++ [
@ -87,13 +89,13 @@ in {
"credentials=${cfg.credentials}"
]
++ (optional (!cfg.automatic) "noauto");
in {
in
{
inherit options;
device = "//${cfg.address}/${cfg.remotePath}";
fsType = "cifs";
};
}
)
})
)
);
}

View file

@ -1,7 +1,6 @@
{
self,
...
}: system: let
{ self, ... }:
system:
let
pkgs = self.pkgs.${system};
in
pkgs.devshell.mkShell {

View file

@ -14,21 +14,40 @@
# '';
# }
# ```
{exec, ...}: let
{ exec, ... }:
let
assertMsg = pred: msg: pred || builtins.throw msg;
hasSuffix = suffix: content: let
hasSuffix =
suffix: content:
let
lenContent = builtins.stringLength content;
lenSuffix = builtins.stringLength suffix;
in
lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix;
in {
in
{
# Instead of calling rage directly here, we call a wrapper script that will cache the output
# in a predictable path in /tmp, which allows us to only require the password for each encrypted
# file once.
rageImportEncrypted = identities: nixFile:
assert assertMsg (builtins.isPath nixFile) "The file to decrypt must be given as a path to prevent impurity.";
assert assertMsg (hasSuffix ".nix.age" nixFile) "The content of the decrypted file must be a nix expression and should therefore end in .nix.age";
exec ([./rage-decrypt-and-cache.sh nixFile] ++ identities);
rageImportEncrypted =
identities: nixFile:
assert assertMsg (builtins.isPath nixFile)
"The file to decrypt must be given as a path to prevent impurity.";
assert assertMsg (hasSuffix ".nix.age" nixFile)
"The content of the decrypted file must be a nix expression and should therefore end in .nix.age";
exec (
[
./rage-decrypt-and-cache.sh
nixFile
]
++ identities
);
# currentSystem
unsafeCurrentSystem = exec ["nix" "eval" "--impure" "--expr" "builtins.currentSystem"];
unsafeCurrentSystem = exec [
"nix"
"eval"
"--impure"
"--expr"
"builtins.currentSystem"
];
}

View file

@ -1,11 +1,15 @@
{self, ...}: nodeName: nodeAttrs: let
{ self, ... }:
nodeName: nodeAttrs:
let
#FIXME inherit nodeAttrs. system;
system = "x86_64-linux";
pkgs = self.pkgs.${system};
disko-script = pkgs.writeShellScriptBin "disko-script" "${nodeAttrs.config.system.build.diskoScript}";
disko-script = pkgs.writeShellScriptBin "disko-script" "${nodeAttrs.config.system.build.diskoScript
}";
disko-mount = pkgs.writeShellScriptBin "disko-mount" "${nodeAttrs.config.system.build.mountScript}";
disko-format = pkgs.writeShellScriptBin "disko-format" "${nodeAttrs.config.system.build.formatScript}";
disko-format = pkgs.writeShellScriptBin "disko-format" "${nodeAttrs.config.system.build.formatScript
}";
install-system = pkgs.writeShellScriptBin "install-system" ''
set -euo pipefail
@ -28,7 +32,8 @@
install-system
];
};
in {
in
{
# Everything required for the installer as a single package,
# so it can be used from an existing live system by copying the derivation.
packages.${system}.installer-package.${nodeName} = installer-package;

View file

@ -1,7 +1,7 @@
inputs: let
inputs:
let
inherit (inputs) self;
inherit
(inputs.nixpkgs.lib)
inherit (inputs.nixpkgs.lib)
concatMapAttrs
filterAttrs
flip
@ -12,7 +12,10 @@ inputs: let
;
# Creates a new nixosSystem with the correct specialArgs, pkgs and name definition
mkHost = {minimal}: name: let
mkHost =
{ minimal }:
name:
let
pkgs = self.pkgs.x86_64-linux;
in
nixosSystem {
@ -42,22 +45,30 @@ inputs: let
# to instanciate hosts correctly.
hosts = builtins.attrNames (filterAttrs (_: type: type == "directory") (builtins.readDir ../hosts));
# Process each nixosHosts declaration and generatea nixosSystem definitions
nixosConfigurations = genAttrs hosts (mkHost {minimal = false;});
minimalConfigurations = genAttrs hosts (mkHost {minimal = true;});
nixosConfigurations = genAttrs hosts (mkHost {
minimal = false;
});
minimalConfigurations = genAttrs hosts (mkHost {
minimal = true;
});
# True NixOS nodes can define additional guest nodes that are built
# together with it. We collect all defined guests from each node here
# to allow accessing any node via the unified attribute `nodes`.
guestConfigurations = flip concatMapAttrs self.nixosConfigurations (_: node:
guestConfigurations = flip concatMapAttrs self.nixosConfigurations (
_: node:
flip mapAttrs' (node.config.guests or { }) (
guestName: guestDef:
nameValuePair guestDef.nodeName (
if guestDef.backend == "microvm"
then node.config.microvm.vms.${guestName}.config
else node.config.containers.${guestName}.nixosConfiguration
if guestDef.backend == "microvm" then
node.config.microvm.vms.${guestName}.config
else
node.config.containers.${guestName}.nixosConfiguration
)
));
in {
)
);
in
{
inherit
hosts
nixosConfigurations

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
nix.extraOptions = ''
experimental-features = nix-command flakes recursive-nix
'';

View file

@ -1,7 +1,5 @@
{
pkgs,
fetchurl,
}: let
{ pkgs, fetchurl }:
let
name = "awakened-poe-trade";
version = "3.22.10003";
description = "Path of Exile trading app for price checking";

View file

@ -9,31 +9,35 @@
deploy = super.callPackage ./deploy.nix { };
mongodb-bin = super.callPackage ./mongodb-bin.nix { };
awakened-poe-trade = super.callPackage ./awakened-poe-trade.nix { };
neovim-clean = super.neovim-unwrapped.overrideAttrs (_neovimFinal: neovimPrev: {
neovim-clean = super.neovim-unwrapped.overrideAttrs (
_neovimFinal: neovimPrev: {
nativeBuildInputs = (neovimPrev.nativeBuildInputs or [ ]) ++ [ super.makeWrapper ];
postInstall =
(neovimPrev.postInstall or "")
+ ''
wrapProgram $out/bin/nvim --add-flags "--clean"
'';
});
kanidm = super.kanidm.overrideAttrs (old: let
}
);
kanidm = super.kanidm.overrideAttrs (
old:
let
provisionSrc = super.fetchFromGitHub {
owner = "oddlama";
repo = "kanidm-provision";
rev = "v1.1.0";
hash = "sha256-pFOFFKh3la/sZGXj+pAM8x4SMeffvvbOvTjPeHS1XPU=";
};
in {
patches =
old.patches
++ [
in
{
patches = old.patches ++ [
"${provisionSrc}/patches/1.2.0-oauth2-basic-secret-modify.patch"
"${provisionSrc}/patches/1.2.0-recover-account.patch"
];
passthru.enableSecretProvisioning = true;
doCheck = false;
});
}
);
kanidm-provision = super.callPackage ./kanidm-provision.nix { };
})
]

View file

@ -3,7 +3,8 @@
writeShellApplication,
nvd,
nix-output-monitor,
}: let
}:
let
deploy = writeShellApplication {
name = "deploy";
text = ''
@ -168,5 +169,8 @@
in
symlinkJoin {
name = "deploy and build";
paths = [deploy build];
paths = [
deploy
build
];
}

View file

@ -7,7 +7,8 @@
lib,
buildGoModule,
fetchFromGitHub,
}: let
}:
let
pname = "homebox";
version = "0.10.3";
src = "${fetchFromGitHub {

View file

@ -19,7 +19,10 @@ rustPlatform.buildRustPackage rec {
meta = with lib; {
description = "A small utility to help with kanidm provisioning";
homepage = "https://github.com/oddlama/kanidm-provision";
license = with licenses; [asl20 mit];
license = with licenses; [
asl20
mit
];
maintainers = with maintainers; [ oddlama ];
mainProgram = "kanidm-provision";
};

View file

@ -11,27 +11,26 @@ stdenv.mkDerivation {
pname = "mongodb-bin";
version = "1.0.0";
srcs = [
(
fetchurl {
(fetchurl {
url = "https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu2204-6.0.14.tgz";
hash = "sha256-1MW3pVIffdxq63gY64ozM1erWM2ou2L8T+MTfG+ZPLg=";
}
)
(
fetchurl {
})
(fetchurl {
url = "https://downloads.mongodb.com/compass/mongosh-2.1.5-linux-x64.tgz";
hash = "sha256-R1GGB0ZGqmpJtMUNF2+EJK6iNiChHuoHyOf2vKDcOKA=";
}
)
})
];
sourceRoot = ".";
nativeBuildInputs = [
autoPatchelfHook
];
nativeBuildInputs = [ autoPatchelfHook ];
buildPhase = ''
mkdir -p $out/bin
cp mongosh-2.1.5-linux-x64/bin/mongosh $out/bin/mongo
cp mongodb-linux-x86_64-ubuntu2204-6.0.14/bin/mongod $out/bin/mongod
'';
buildInputs = [openssl curl xz libgcc];
buildInputs = [
openssl
curl
xz
libgcc
];
}

View file

@ -19,7 +19,10 @@ rustPlatform.buildRustPackage {
cargoHash = "sha256-9bhKtg2g5H4zGn7yVCjTazeXfeoKjtAKAlzkLkCraiw=";
nativeBuildInputs = [ pkg-config ];
buildInputs = [openssl systemd];
buildInputs = [
openssl
systemd
];
meta = with lib; {
description = "Nixpkgs pull request channel tracker";

View file

@ -7,7 +7,12 @@
}:
writeShellApplication {
name = "clone-term";
runtimeInputs = [ps procps xdotool jq];
runtimeInputs = [
ps
procps
xdotool
jq
];
text = ''
if [[ ''${XDG_CURRENT_DESKTOP-} == sway ]]; then

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
home.packages = [
pkgs.xclip
pkgs.xdragon

View file

@ -79,13 +79,15 @@ MOD: TAGS: pkgs:
"${MOD}-m " = "spawn ${pkgs.thunderbird}/bin/thunderbird";
"Menu" = "spawn rofi -show drun";
}
// builtins.listToAttrs (map (x: {
// builtins.listToAttrs (
map (x: {
name = "${MOD}-${x}";
value = "use_index ${x}";
})
TAGS)
// builtins.listToAttrs (map (x: {
}) TAGS
)
// builtins.listToAttrs (
map (x: {
name = "${MOD}-Shift-${x}";
value = "move_index ${x}";
})
TAGS)
}) TAGS
)

View file

@ -1,18 +1,14 @@
{
pkgs,
lib,
...
}: let
{ pkgs, lib, ... }:
let
# set the modifier key to WIN
MOD = "Super";
#set the default resize step for herbstluft
TAGS = map toString (lib.lists.range 1 9);
in {
in
{
xsession.windowManager.herbstluftwm = {
enable = true;
package = pkgs.herbstluftwm.overrideAttrs (_finalAttrs: _previousAttrs: {
doCheck = false;
});
package = pkgs.herbstluftwm.overrideAttrs (_finalAttrs: _previousAttrs: { doCheck = false; });
extraConfig = ''
herbstclient set auto_detect_monitors 1
killall polybar

View file

@ -3,7 +3,8 @@
pkgs,
lib,
...
}: {
}:
{
# import shared sway config
imports = [ ../sway3.nix ];
systemd.user.services = {
@ -16,13 +17,17 @@
enableSystemdTarget = true;
config = {
startup = [
{command = "${pkgs.xorg.xrandr}/bin/xrandr --output DVI-D-0 --mode 1920x1080 --pos 0x0 --rate 60.00 --output DP-4 --mode 2560x1440 --pos 1920x720 --primary --rate 144 --output HDMI-0 --pos 0x1080 --rate 60.00";}
{
command = "${pkgs.xorg.xrandr}/bin/xrandr --output DVI-D-0 --mode 1920x1080 --pos 0x0 --rate 60.00 --output DP-4 --mode 2560x1440 --pos 1920x720 --primary --rate 144 --output HDMI-0 --pos 0x1080 --rate 60.00";
}
];
menu = "rofi -show drun";
keybindings = let
keybindings =
let
cfg = config.xsession.windowManager.i3.config;
maim = "${pkgs.maim}/bin/maim -qs -b 1 --hidecursor";
in {
in
{
"Menu" = "exec ${cfg.menu}";
"Ctrl+F9" = "exec ${config.xsession.wallpapers.script}";
"${cfg.modifier}+F12" =
@ -40,7 +45,8 @@
${maim} | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png
''
);
"${cfg.modifier}+F10" = let
"${cfg.modifier}+F10" =
let
nsend = ''
${pkgs.libnotify}/bin/notify-send \
-h string:category:Screenshot\

View file

@ -13,7 +13,8 @@
pkgs,
nixosConfig,
...
}: let
}:
let
color = {
shade1 = "#311B92";
shade2 = "#4527A0";
@ -58,7 +59,8 @@
};
fontsize = "9";
in {
in
{
services.polybar = {
enable = true;
@ -89,9 +91,24 @@ in {
};
modules = with lib; {
left = concatStringsSep " " ["left1" "title" "left2"];
left = concatStringsSep " " [
"left1"
"title"
"left2"
];
center = concatStringsSep " " [ "workspaces" ];
right = concatStringsSep " " ["right5" "alsa" "right4" "battery" "right3" "network" "right2" "date" "right1" "keyboardswitcher"];
right = concatStringsSep " " [
"right5"
"alsa"
"right4"
"battery"
"right3"
"network"
"right2"
"date"
"right1"
"keyboardswitcher"
];
};
tray = {
@ -108,9 +125,22 @@ in {
dpi = 96;
height = 22;
modules = with lib; {
left = concatStringsSep " " ["left1" "title" "left2"];
left = concatStringsSep " " [
"left1"
"title"
"left2"
];
center = concatStringsSep " " [ "workspaces" ];
right = concatStringsSep " " ["right5" "alsa" "right3" "network" "right2" "date" "right1" "keyboardswitcher"];
right = concatStringsSep " " [
"right5"
"alsa"
"right3"
"network"
"right2"
"date"
"right1"
"keyboardswitcher"
];
};
};
patricknix = {
@ -120,14 +150,28 @@ in {
dpi = 144;
height = 33;
modules = with lib; {
left = concatStringsSep " " ["left1" "title" "left2"];
left = concatStringsSep " " [
"left1"
"title"
"left2"
];
center = concatStringsSep " " [ "workspaces" ];
right = concatStringsSep " " ["right5" "alsa" "right4" "battery" "right3" "network" "right2" "date" "right1" "keyboardswitcher"];
right = concatStringsSep " " [
"right5"
"alsa"
"right4"
"battery"
"right3"
"network"
"right2"
"date"
"right1"
"keyboardswitcher"
];
};
};
}
.${nixosConfig.node.name}
or {};
.${nixosConfig.node.name} or { };
# Functional MODULES
@ -296,8 +340,7 @@ in {
interface = "wlan0";
};
}
.${nixosConfig.node.name}
or {};
.${nixosConfig.node.name} or { };
"module/keyboardswitcher" = {
type = "custom/menu";

View file

@ -1,8 +1,5 @@
{ pkgs, config, ... }:
{
pkgs,
config,
...
}: {
home = {
packages = with pkgs; [
zathura

View file

@ -32,63 +32,108 @@ let
trayOutput = "primary";
}
];
floating.criteria = [
{class = "Pavucontrol";}
];
floating.criteria = [ { class = "Pavucontrol"; } ];
assigns = {
"2:d" = [
{class = "^firefox$";}
];
"2:2" = [
{class = "^spotify$";}
];
"3:u" = [
{class = "^thunderbird$";}
];
"2:d" = [ { class = "^firefox$"; } ];
"2:2" = [ { class = "^spotify$"; } ];
"3:u" = [ { class = "^thunderbird$"; } ];
"4:a" = [
{ class = "^bottles$"; }
{ class = "^steam$"; }
{ class = "^prismlauncher$"; }
];
"1:F1" = [
{class = "^discord$";}
];
"1:F1" = [ { class = "^discord$"; } ];
"2:F2" = [
{ class = "^Signal$"; }
{ class = "^TelegramDesktop$"; }
];
};
workspaceOutputAssign = let
output = out:
lib.lists.imap1 (i: x: {
workspaceOutputAssign =
let
output =
out:
lib.lists.imap1 (
i: x: {
workspace = "${toString i}:${x}";
output = out;
});
}
);
in
{
"desktopnix" =
output "HDMI-0" ["1" "2" "3" "4" "5" "6" "7" "8" "9"]
++ output "DP-4" ["j" "d" "u" "a" "x" "p"]
++ output "DVI-D-0" ["F1" "F2" "F3" "F4"];
output "HDMI-0" [
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"8"
"9"
]
++ output "DP-4" [
"j"
"d"
"u"
"a"
"x"
"p"
]
++ output "DVI-D-0" [
"F1"
"F2"
"F3"
"F4"
];
"patricknix" =
output "eDP-1" ["1" "2" "3" "4" "5" "6" "7" "8" "9"]
++ output "DP-1" ["j" "d" "u" "a" "x" "p"];
"gojo" =
output "eDP-1" ["1" "2" "3" "4" "5" "6"];
output "eDP-1" [
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"8"
"9"
]
++ output "DP-1" [
"j"
"d"
"u"
"a"
"x"
"p"
];
"gojo" = output "eDP-1" [
"1"
"2"
"3"
"4"
"5"
"6"
];
}
.${nixosConfig.node.name}
or [];
.${nixosConfig.node.name} or [ ];
keybindings =
(lib.attrsets.mergeAttrsList (map (x: (let
(lib.attrsets.mergeAttrsList (
map (
x:
(
let
key = lib.elemAt (lib.strings.splitString ":" x.workspace) 1;
in {
in
{
"${modifier}+${key}" = "workspace ${x.workspace}";
"${modifier}+Shift+${key}" = "move container to workspace ${x.workspace}";
}))
cfg.workspaceOutputAssign))
}
)
) cfg.workspaceOutputAssign
))
// {
"${modifier}+t" = "exec ${terminal}";
"${modifier}+b" = "exec firefox";
@ -137,7 +182,8 @@ let
"${modifier}+period" = "workspace next_on_output";
};
};
in {
in
{
wayland.windowManager.sway.config = cfg;
xsession.windowManager.i3.config = cfg;
@ -146,9 +192,7 @@ in {
bars.main = {
blocks =
[
{
block = "net";
}
{ block = "net"; }
{
block = "cpu";
format = " $icon $utilization ";
@ -158,7 +202,10 @@ in {
format = " $icon $utilization $memory $temperature ";
}
]
++ {"patricknix" = [{block = "battery";}];}.${nixosConfig.node.name} or []
++ {
"patricknix" = [ { block = "battery"; } ];
}
.${nixosConfig.node.name} or [ ]
++ [
{
block = "sound";

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
imports = [
../.
./fuzzel.nix

View file

@ -1,4 +1,5 @@
{pkgs, ...}: {
{ pkgs, ... }:
{
stylix.targets.fuzzel.enable = true;
home.packages = with pkgs; [
(writeShellScriptBin "fuzzel" ''

View file

@ -3,9 +3,9 @@
lib,
nixosConfig,
...
}: let
inherit
(lib)
}:
let
inherit (lib)
mkMerge
optionals
elem
@ -46,7 +46,8 @@
# Listen to the Hyprland socket for events and process each line with the handle function
${pkgs.socat}/bin/socat -U - UNIX-CONNECT:$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock | while read -r line; do handle "$line"; done
'';
in {
in
{
wayland.windowManager.hyprland = {
enable = true;
settings = mkMerge [
@ -82,7 +83,8 @@ in {
focus_preferred_method = 1;
workspace_center_on = 1;
};
bind = let
bind =
let
monitor_binds = {
"1" = "j";
"2" = "d";
@ -146,12 +148,10 @@ in {
"SUPER + SHIFT,q,exit"
]
++ flip concatMap (map toString (lib.lists.range 1 9)) (
x: [
++ flip concatMap (map toString (lib.lists.range 1 9)) (x: [
"SUPER,${monitor_binds."${x}"},workspace,${x}"
"SUPER + SHIFT,${monitor_binds."${x}"},movetoworkspacesilent,${x}"
]
);
]);
cursor.no_warps = true;
debug.disable_logs = false;

View file

@ -1,8 +1,5 @@
{ config, nixosConfig, ... }:
{
config,
nixosConfig,
...
}: {
# import shared i3 config
imports = [ ../sway3.nix ];
stylix.targets.sway.enable = true;
@ -42,9 +39,11 @@
map_to_output = "eDP-1";
};
};
keybindings = let
keybindings =
let
cfg = config.wayland.windowManager.sway.config;
in {
in
{
"Menu" = "exec ${cfg.menu}";
};
}
@ -80,11 +79,12 @@
};
};
}
.${nixosConfig.node.name}
or {};
extraConfig = let
.${nixosConfig.node.name} or { };
extraConfig =
let
cfg = config.wayland.windowManager.sway.config;
in ''
in
''
bindgesture swipe:3:left workpace next
bindgesture swipe:3:right workpace prev
bindgesture pinch:4:outward exec ${cfg.menu}

View file

@ -1,8 +1,5 @@
{ config, lib, ... }:
{
config,
lib,
...
}: {
services.swaync = {
enable = true;
settings = {

Some files were not shown because too many files have changed in this diff Show more