mirror of
https://github.com/oddlama/nix-config.git
synced 2025-10-11 07:10:39 +02:00
refactor: major refactor into proper reusable modules. No logical changes.
This commit is contained in:
parent
04872f6ec5
commit
84ac34cb6c
80 changed files with 761 additions and 776 deletions
|
@ -1,10 +0,0 @@
|
|||
{lib, ...}: {
|
||||
boot.loader = {
|
||||
grub = {
|
||||
enable = true;
|
||||
efiSupport = false;
|
||||
};
|
||||
timeout = lib.mkDefault 2;
|
||||
};
|
||||
console.earlySetup = true;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
{config, ...}: {
|
||||
imports = [
|
||||
./impermanence.nix
|
||||
./inputrc.nix
|
||||
./issue.nix
|
||||
./net.nix
|
||||
./nix.nix
|
||||
./resolved.nix
|
||||
./ssh.nix
|
||||
./system.nix
|
||||
./xdg.nix
|
||||
|
||||
../../../users/root
|
||||
|
||||
../../../modules/deteministic-ids.nix
|
||||
../../../modules/distributed-config.nix
|
||||
../../../modules/extra.nix
|
||||
../../../modules/interface-naming.nix
|
||||
../../../modules/microvms.nix
|
||||
../../../modules/oauth2-proxy.nix
|
||||
../../../modules/promtail.nix
|
||||
../../../modules/provided-domains.nix
|
||||
../../../modules/repo.nix
|
||||
../../../modules/telegraf.nix
|
||||
../../../modules/wireguard.nix
|
||||
];
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
verbose = true;
|
||||
};
|
||||
|
||||
# If the host defines microvms, ensure that this core module and
|
||||
# some boilerplate is imported automatically.
|
||||
extra.microvms.commonImports = [
|
||||
./.
|
||||
{home-manager.users.root.home.minimal = true;}
|
||||
];
|
||||
|
||||
# Required even when using home-manager's zsh module since the /etc/profile load order
|
||||
# is partly controlled by this. See nix-community/home-manager#3681.
|
||||
programs.zsh.enable = true;
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
# Give agenix access to the hostkey independent of impermanence activation
|
||||
age.identityPaths = ["/persist/etc/ssh/ssh_host_ed25519_key"];
|
||||
|
||||
# State that should be kept across reboots, but is otherwise
|
||||
# NOT important information in any way that needs to be backed up.
|
||||
environment.persistence."/state" = {
|
||||
hideMounts = true;
|
||||
directories =
|
||||
[
|
||||
{
|
||||
directory = "/var/lib/systemd";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0755";
|
||||
}
|
||||
{
|
||||
directory = "/var/log";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0755";
|
||||
}
|
||||
#{ directory = "/tmp"; user = "root"; group = "root"; mode = "1777"; }
|
||||
#{ directory = "/var/tmp"; user = "root"; group = "root"; mode = "1777"; }
|
||||
{
|
||||
directory = "/var/spool";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0755";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.networking.wireless.iwd.enable [
|
||||
{
|
||||
directory = "/var/lib/iwd";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0700";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# State that should be kept forever, and backed up accordingly.
|
||||
environment.persistence."/persist" = {
|
||||
hideMounts = true;
|
||||
files = [
|
||||
"/etc/machine-id"
|
||||
"/etc/ssh/ssh_host_ed25519_key"
|
||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||
];
|
||||
directories =
|
||||
[
|
||||
{
|
||||
directory = "/var/lib/nixos";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0755";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.security.acme.acceptTerms [
|
||||
{
|
||||
directory = "/var/lib/acme";
|
||||
user = "acme";
|
||||
group = "acme";
|
||||
mode = "0755";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.printing.enable [
|
||||
{
|
||||
directory = "/var/lib/cups";
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.fail2ban.enable [
|
||||
{
|
||||
directory = "/var/lib/fail2ban";
|
||||
user = "fail2ban";
|
||||
group = "fail2ban";
|
||||
mode = "0750";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.postgresql.enable [
|
||||
{
|
||||
directory = "/var/lib/postgresql";
|
||||
user = "postgres";
|
||||
group = "postgres";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.gitea.enable [
|
||||
{
|
||||
directory = config.services.gitea.stateDir;
|
||||
user = "gitea";
|
||||
group = "gitea";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.caddy.enable [
|
||||
{
|
||||
directory = config.services.caddy.dataDir;
|
||||
user = "caddy";
|
||||
group = "caddy";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.loki.enable [
|
||||
{
|
||||
directory = "/var/lib/loki";
|
||||
user = "loki";
|
||||
group = "loki";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.grafana.enable [
|
||||
{
|
||||
directory = config.services.grafana.dataDir;
|
||||
user = "grafana";
|
||||
group = "grafana";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.kanidm.enableServer [
|
||||
{
|
||||
directory = "/var/lib/kanidm";
|
||||
user = "kanidm";
|
||||
group = "kanidm";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.vaultwarden.enable [
|
||||
{
|
||||
directory = "/var/lib/vaultwarden";
|
||||
user = "vaultwarden";
|
||||
group = "vaultwarden";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.influxdb2.enable [
|
||||
{
|
||||
directory = "/var/lib/influxdb2";
|
||||
user = "influxdb2";
|
||||
group = "influxdb2";
|
||||
mode = "0700";
|
||||
}
|
||||
]
|
||||
++ lib.optionals config.services.telegraf.enable [
|
||||
{
|
||||
directory = "/var/lib/telegraf";
|
||||
user = "telegraf";
|
||||
group = "telegraf";
|
||||
mode = "0700";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
{
|
||||
environment.etc."inputrc".text = ''
|
||||
# /etc/inputrc: initialization file for readline
|
||||
#
|
||||
# For more information on how this file works, please see the
|
||||
# INITIALIZATION FILE section of the readline(3) man page
|
||||
#
|
||||
# Quick dirty little note:
|
||||
# To get the key sequence for binding, you can abuse bash.
|
||||
# While running bash, hit CTRL+V, and then type the key sequence.
|
||||
# So, typing 'ALT + left arrow' in Konsole gets you back:
|
||||
# ^[[1;3D
|
||||
# The readline entry to make this skip back a word will then be:
|
||||
# "\e[1;3D" backward-word
|
||||
#
|
||||
# Customization note:
|
||||
# You don't need to put all your changes in this file. You can create
|
||||
# ~/.inputrc which starts off with the line:
|
||||
# $include /etc/inputrc
|
||||
# Then put all your own stuff after that.
|
||||
#
|
||||
|
||||
# do not bell on tab-completion
|
||||
set bell-style none
|
||||
|
||||
set history-size -1
|
||||
|
||||
set meta-flag on
|
||||
set input-meta on
|
||||
set convert-meta off
|
||||
set output-meta on
|
||||
|
||||
# dont output everything on first line
|
||||
set horizontal-scroll-mode off
|
||||
|
||||
|
||||
# append slash to completed directories & symlinked directories
|
||||
set mark-directories on
|
||||
set mark-symlinked-directories on
|
||||
|
||||
# dont expand ~ in tab completion
|
||||
set expand-tilde off
|
||||
|
||||
# instead of ringing bell, show list of ambigious completions directly, also show up to 300 items before asking
|
||||
set show-all-if-ambiguous on
|
||||
set completion-query-items 300
|
||||
|
||||
|
||||
$if mode=emacs
|
||||
|
||||
# for linux console and RH/Debian xterm
|
||||
# allow the use of the Home/End keys
|
||||
"\e[1~": beginning-of-line
|
||||
"\e[4~": end-of-line
|
||||
# map "page up" and "page down" to search history based on current cmdline
|
||||
"\e[5~": history-search-backward
|
||||
"\e[6~": history-search-forward
|
||||
# allow the use of the Delete/Insert keys
|
||||
"\e[3~": delete-char
|
||||
"\e[2~": quoted-insert
|
||||
|
||||
# gnome / others (escape + arrow key)
|
||||
"\e[5C": forward-word
|
||||
"\e[5D": backward-word
|
||||
# konsole / xterm / rxvt (escape + arrow key)
|
||||
"\e\e[C": forward-word
|
||||
"\e\e[D": backward-word
|
||||
# gnome / konsole / others (control + arrow key)
|
||||
"\e[1;5C": forward-word
|
||||
"\e[1;5D": backward-word
|
||||
# aterm / eterm (control + arrow key)
|
||||
"\eOc": forward-word
|
||||
"\eOd": backward-word
|
||||
|
||||
# konsole (alt + arrow key)
|
||||
"\e[1;3C": forward-word
|
||||
"\e[1;3D": backward-word
|
||||
|
||||
# Chromebooks remap alt + backspace so provide alternative (alt + k)
|
||||
"\ek": backward-kill-word
|
||||
|
||||
$if term=rxvt
|
||||
"\e[8~": end-of-line
|
||||
|
||||
"\e[3^": kill-line
|
||||
"\e[3@": backward-kill-line
|
||||
$endif
|
||||
|
||||
# for non RH/Debian xterm, can't hurt for RH/Debian xterm
|
||||
"\eOH": beginning-of-line
|
||||
"\eOF": end-of-line
|
||||
|
||||
# for freebsd console
|
||||
"\e[H": beginning-of-line
|
||||
"\e[F": end-of-line
|
||||
|
||||
# fix Home and End for German users
|
||||
"\e[7~": beginning-of-line
|
||||
"\e[8~": end-of-line
|
||||
|
||||
# ctrl [+ shift] + del = kill line [backward]
|
||||
"\e[3;5~": kill-line
|
||||
"\e[3;6~": backward-kill-line
|
||||
$endif
|
||||
|
||||
# Up and Down should search history based on current cmdline
|
||||
"\e[A": history-search-backward
|
||||
"\e[B": history-search-forward
|
||||
'';
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
let
|
||||
# IP addresses: ${"${interface} \e{halfbright}\4{${interface}}\e{reset} \e{halfbright}\6{${interface}}\e{reset}"}
|
||||
issue_text = ''
|
||||
\d \t
|
||||
\e{halfbright}\4\e{reset} \e{halfbright}\6\e{reset}
|
||||
This is \e{cyan}\n\e{reset} [\e{lightblue}\l\e{reset}] (\s \m \r)
|
||||
|
||||
'';
|
||||
in {
|
||||
environment.etc."issue".text = issue_text;
|
||||
environment.etc."issue.logo".text = issue_text;
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
nodeName,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
concatStringsSep
|
||||
head
|
||||
mapAttrsToList
|
||||
mkDefault
|
||||
mkForce
|
||||
;
|
||||
in {
|
||||
networking = {
|
||||
hostName = nodeName;
|
||||
useDHCP = mkForce false;
|
||||
useNetworkd = true;
|
||||
dhcpcd.enable = false;
|
||||
|
||||
nftables = {
|
||||
firewall.enable = true;
|
||||
stopRuleset = mkDefault ''
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority filter; policy drop;
|
||||
ct state invalid drop
|
||||
ct state {established, related} accept
|
||||
|
||||
iifname lo accept
|
||||
meta l4proto ipv6-icmp accept
|
||||
meta l4proto icmp accept
|
||||
tcp dport ${toString (head config.services.openssh.ports)} accept
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority filter; policy accept;
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# TODO mkForce nftables
|
||||
nftables.firewall = {
|
||||
zones = lib.mkForce {
|
||||
local.localZone = true;
|
||||
};
|
||||
|
||||
rules = lib.mkForce {
|
||||
icmp = {
|
||||
early = true;
|
||||
after = ["ct"];
|
||||
from = "all";
|
||||
to = ["local"];
|
||||
extraLines = [
|
||||
"ip6 nexthdr icmpv6 icmpv6 type { echo-request, destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept"
|
||||
"ip protocol icmp icmp type { echo-request, destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept"
|
||||
#"ip6 saddr fe80::/10 ip6 daddr fe80::/10 udp dport 546 accept" # (dhcpv6)
|
||||
];
|
||||
};
|
||||
|
||||
ssh = {
|
||||
early = true;
|
||||
after = ["ct"];
|
||||
from = "all";
|
||||
to = ["local"];
|
||||
allowedTCPPorts = config.services.openssh.ports;
|
||||
};
|
||||
|
||||
untrusted-to-local = {
|
||||
from = ["untrusted"];
|
||||
to = ["local"];
|
||||
|
||||
inherit
|
||||
(config.networking.firewall)
|
||||
allowedTCPPorts
|
||||
allowedUDPPorts
|
||||
;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network.enable = true;
|
||||
|
||||
# Rename known network interfaces
|
||||
extra.networking.renameInterfacesByMac = lib.mapAttrs (_: v: v.mac) (config.repo.secrets.local.networking.interfaces or {});
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
stateVersion,
|
||||
...
|
||||
}: {
|
||||
environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" ''
|
||||
assert builtins.trace "This is a dummy config, use colmena!" false;
|
||||
{ }
|
||||
'';
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
auto-optimise-store = true;
|
||||
allowed-users = ["@wheel"];
|
||||
trusted-users = ["root" "@wheel"];
|
||||
substituters = [
|
||||
"https://nix-config.cachix.org"
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"nix-config.cachix.org-1:Vd6raEuldeIZpttVQfrUbLvXJHzzzkS0pezXCVVjDG4="
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
cores = 0;
|
||||
max-jobs = "auto";
|
||||
};
|
||||
daemonCPUSchedPolicy = "batch";
|
||||
daemonIOSchedPriority = 5;
|
||||
distributedBuilds = true;
|
||||
extraOptions = ''
|
||||
builders-use-substitutes = true
|
||||
experimental-features = nix-command flakes
|
||||
flake-registry = /etc/nix/registry.json
|
||||
'';
|
||||
nixPath = ["nixpkgs=/run/current-system/nixpkgs"];
|
||||
optimise.automatic = true;
|
||||
gc = {
|
||||
automatic = true;
|
||||
dates = "monthly";
|
||||
options = "--delete-older-than 90d";
|
||||
};
|
||||
# Define global flakes for this system
|
||||
registry = {
|
||||
nixpkgs.flake = inputs.nixpkgs;
|
||||
p.flake = inputs.nixpkgs;
|
||||
pkgs.flake = inputs.nixpkgs;
|
||||
templates.flake = inputs.templates;
|
||||
};
|
||||
};
|
||||
|
||||
system = {
|
||||
extraSystemBuilderCmds = ''
|
||||
ln -sv ${pkgs.path} $out/nixpkgs
|
||||
'';
|
||||
inherit stateVersion;
|
||||
};
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
dnssec = "allow-downgrade";
|
||||
fallbackDns = [
|
||||
"1.1.1.1"
|
||||
"2606:4700:4700::1111"
|
||||
"8.8.8.8"
|
||||
"2001:4860:4860::8844"
|
||||
];
|
||||
llmnr = "false";
|
||||
extraConfig = ''
|
||||
Domains=~.
|
||||
MulticastDNS=true
|
||||
'';
|
||||
};
|
||||
|
||||
system.nssDatabases.hosts = lib.mkMerge [
|
||||
(lib.mkBefore ["mdns_minimal [NOTFOUND=return]"])
|
||||
(lib.mkAfter ["mdns"])
|
||||
];
|
||||
|
||||
# TODO mkForce nftables
|
||||
# Open port 5353 for any interfaces that have MulticastDNS enabled
|
||||
networking.nftables.firewall = let
|
||||
# Determine all networks that have MulticastDNS enabled
|
||||
networksWithMulticast =
|
||||
lib.filter
|
||||
(n: config.systemd.network.networks.${n}.networkConfig.MulticastDNS or false)
|
||||
(lib.attrNames config.systemd.network.networks);
|
||||
|
||||
# Determine all known mac addresses and the corresponding link name
|
||||
# based on the renameInterfacesByMac option.
|
||||
knownMacs =
|
||||
lib.mapAttrs'
|
||||
(k: v: lib.nameValuePair v k)
|
||||
config.extra.networking.renameInterfacesByMac;
|
||||
# A helper that returns the link name for the given mac address,
|
||||
# or null if it doesn't exist or the given mac was null.
|
||||
linkNameFor = mac:
|
||||
if mac == null
|
||||
then null
|
||||
else knownMacs.${mac} or null;
|
||||
|
||||
# Calls the given function for each network that has MulticastDNS enabled,
|
||||
# and collects all non-null values.
|
||||
mapNetworks = f: lib.filter (v: v != null) (map f networksWithMulticast);
|
||||
|
||||
# All interfaces on which MulticastDNS is used
|
||||
mdnsInterfaces = lib.unique (
|
||||
# For each network that is matched by MAC, lookup the link name
|
||||
# and if map the definition name to the link name.
|
||||
mapNetworks (x: linkNameFor (config.systemd.network.networks.${x}.matchConfig.MACAddress or null))
|
||||
# For each network that is matched by name, map the definition
|
||||
# name to the link name.
|
||||
++ mapNetworks (x: config.systemd.network.networks.${x}.matchConfig.Name or null)
|
||||
);
|
||||
in
|
||||
lib.mkIf (mdnsInterfaces != []) {
|
||||
zones = lib.mkForce {
|
||||
mdns.interfaces = mdnsInterfaces;
|
||||
};
|
||||
|
||||
rules = lib.mkForce {
|
||||
mdns-to-local = {
|
||||
from = ["mdns"];
|
||||
to = ["local"];
|
||||
allowedUDPPorts = [5353];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
{lib, ...}: {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
authorizedKeysFiles = lib.mkForce ["/etc/ssh/authorized_keys.d/%u"];
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
PermitRootLogin = "yes";
|
||||
};
|
||||
hostKeys = [
|
||||
{
|
||||
path = "/etc/ssh/ssh_host_ed25519_key";
|
||||
type = "ed25519";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,442 +0,0 @@
|
|||
{
|
||||
config,
|
||||
extraLib,
|
||||
inputs,
|
||||
lib,
|
||||
nodePath,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# IP address math library
|
||||
# https://gist.github.com/duairc/5c9bb3c922e5d501a1edb9e7b3b845ba
|
||||
# Plus some extensions by us
|
||||
lib = let
|
||||
libWithNet = (import "${inputs.lib-net}/net.nix" {inherit lib;}).lib;
|
||||
in
|
||||
lib.recursiveUpdate libWithNet {
|
||||
net = {
|
||||
cidr = rec {
|
||||
# host :: (ip | mac | integer) -> cidr -> ip
|
||||
#
|
||||
# Wrapper that extends the original host function to
|
||||
# check whether the argument `n` is in-range for the given cidr.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.host 255 "192.168.1.0/24"
|
||||
# "192.168.1.255"
|
||||
# > net.cidr.host (256) "192.168.1.0/24"
|
||||
# <fails with an error message>
|
||||
# > net.cidr.host (-1) "192.168.1.0/24"
|
||||
# "192.168.1.255"
|
||||
# > net.cidr.host (-256) "192.168.1.0/24"
|
||||
# "192.168.1.0"
|
||||
# > net.cidr.host (-257) "192.168.1.0/24"
|
||||
# <fails with an error message>
|
||||
host = i: n: let
|
||||
cap = libWithNet.net.cidr.capacity n;
|
||||
in
|
||||
assert lib.assertMsg (i >= (-cap) && i < cap) "The host ${toString i} lies outside of ${n}";
|
||||
libWithNet.net.cidr.host i n;
|
||||
# hostCidr :: (ip | mac | integer) -> cidr -> cidr
|
||||
#
|
||||
# Returns the nth host in the given cidr range (like cidr.host)
|
||||
# but as a cidr that retains the original prefix length.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.hostCidr 2 "192.168.1.0/24"
|
||||
# "192.168.1.2/24"
|
||||
hostCidr = n: x: "${libWithNet.net.cidr.host n x}/${toString (libWithNet.net.cidr.length x)}";
|
||||
# ip :: (cidr | ip) -> ip
|
||||
#
|
||||
# Returns just the ip part of the cidr.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.ip "192.168.1.100/24"
|
||||
# "192.168.1.100"
|
||||
# > net.cidr.ip "192.168.1.100"
|
||||
# "192.168.1.100"
|
||||
ip = x: lib.head (lib.splitString "/" x);
|
||||
# canonicalize :: cidr -> cidr
|
||||
#
|
||||
# Replaces the ip of the cidr with the canonical network address
|
||||
# (first contained address in range)
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.canonicalize "192.168.1.100/24"
|
||||
# "192.168.1.0/24"
|
||||
canonicalize = x: libWithNet.net.cidr.make (libWithNet.net.cidr.length x) (ip x);
|
||||
# mergev4 :: [cidrv4 | ipv4] -> (cidrv4 | null)
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given networks.
|
||||
# If no cidr mask is given, /32 is assumed.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.mergev4 ["192.168.1.1/24" "192.168.6.1/32"]
|
||||
# "192.168.0.0/21"
|
||||
mergev4 = addrs_: let
|
||||
# Append /32 if necessary
|
||||
addrs = map (x:
|
||||
if lib.hasInfix "/" x
|
||||
then x
|
||||
else "${x}/32")
|
||||
addrs_;
|
||||
# The smallest occurring length is the first we need to start checking, since
|
||||
# any greater cidr length represents a smaller address range which
|
||||
# wouldn't contain all of the original addresses.
|
||||
startLength = lib.foldl' lib.min 32 (map libWithNet.net.cidr.length addrs);
|
||||
possibleLengths = lib.reverseList (lib.range 0 startLength);
|
||||
# The first ip address will be "expanded" in cidr length until it covers all other
|
||||
# used addresses.
|
||||
firstIp = ip (lib.head addrs);
|
||||
# Return the first (i.e. greatest length -> smallest prefix) cidr length
|
||||
# in the list that covers all used addresses
|
||||
bestLength = lib.head (lib.filter
|
||||
# All given addresses must be contained by the generated address.
|
||||
(len:
|
||||
lib.all
|
||||
(x:
|
||||
libWithNet.net.cidr.contains
|
||||
(ip x)
|
||||
(libWithNet.net.cidr.make len firstIp))
|
||||
addrs)
|
||||
possibleLengths);
|
||||
in
|
||||
assert lib.assertMsg (!lib.any (lib.hasInfix ":") addrs) "mergev4 cannot operate on ipv6 addresses";
|
||||
if addrs == []
|
||||
then null
|
||||
else libWithNet.net.cidr.make bestLength firstIp;
|
||||
# mergev6 :: [cidrv6 | ipv6] -> (cidrv6 | null)
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given networks.
|
||||
# If no cidr mask is given, /128 is assumed.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.mergev6 ["fd00:dead:cafe::/64" "fd00:fd12:3456:7890::/56"]
|
||||
# "fd00:c000::/18"
|
||||
mergev6 = addrs_: let
|
||||
# Append /128 if necessary
|
||||
addrs = map (x:
|
||||
if lib.hasInfix "/" x
|
||||
then x
|
||||
else "${x}/128")
|
||||
addrs_;
|
||||
# The smallest occurring length is the first we need to start checking, since
|
||||
# any greater cidr length represents a smaller address range which
|
||||
# wouldn't contain all of the original addresses.
|
||||
startLength = lib.foldl' lib.min 128 (map libWithNet.net.cidr.length addrs);
|
||||
possibleLengths = lib.reverseList (lib.range 0 startLength);
|
||||
# The first ip address will be "expanded" in cidr length until it covers all other
|
||||
# used addresses.
|
||||
firstIp = ip (lib.head addrs);
|
||||
# Return the first (i.e. greatest length -> smallest prefix) cidr length
|
||||
# in the list that covers all used addresses
|
||||
bestLength = lib.head (lib.filter
|
||||
# All given addresses must be contained by the generated address.
|
||||
(len:
|
||||
lib.all
|
||||
(x:
|
||||
libWithNet.net.cidr.contains
|
||||
(ip x)
|
||||
(libWithNet.net.cidr.make len firstIp))
|
||||
addrs)
|
||||
possibleLengths);
|
||||
in
|
||||
assert lib.assertMsg (lib.all (lib.hasInfix ":") addrs) "mergev6 cannot operate on ipv4 addresses";
|
||||
if addrs == []
|
||||
then null
|
||||
else libWithNet.net.cidr.make bestLength firstIp;
|
||||
# merge :: [cidr] -> { cidrv4 = (cidrv4 | null); cidrv6 = (cidrv4 | null); }
|
||||
#
|
||||
# Returns the smallest cidr network that includes all given networks,
|
||||
# but yields two separate result for all given ipv4 and ipv6 addresses.
|
||||
# Equivalent to calling mergev4 and mergev6 on a partition individually.
|
||||
merge = addrs: let
|
||||
v4_and_v6 = lib.partition (lib.hasInfix ":") addrs;
|
||||
in {
|
||||
cidrv4 = mergev4 v4_and_v6.wrong;
|
||||
cidrv6 = mergev6 v4_and_v6.right;
|
||||
};
|
||||
# assignIps :: cidr -> [int | ip] -> [string] -> [ip]
|
||||
#
|
||||
# Assigns a semi-stable ip address from the given cidr network to each hostname.
|
||||
# The algorithm is based on hashing (abusing sha256) with linear probing.
|
||||
# The order of hosts doesn't matter. No ip (or offset) from the reserved list
|
||||
# will be assigned. The network address and broadcast address will always be reserved
|
||||
# automatically.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.cidr.assignIps "192.168.100.1/24" [] ["a" "b" "c"]
|
||||
# { a = "192.168.100.202"; b = "192.168.100.74"; c = "192.168.100.226"; }
|
||||
#
|
||||
# > net.cidr.assignIps "192.168.100.1/24" [] ["a" "b" "c" "a-new-elem"]
|
||||
# { a = "192.168.100.202"; a-new-elem = "192.168.100.88"; b = "192.168.100.74"; c = "192.168.100.226"; }
|
||||
#
|
||||
# > net.cidr.assignIps "192.168.100.1/24" [202 "192.168.100.74"] ["a" "b" "c"]
|
||||
# { a = "192.168.100.203"; b = "192.168.100.75"; c = "192.168.100.226"; }
|
||||
assignIps = net: reserved: hosts: let
|
||||
cidrSize = libWithNet.net.cidr.size net;
|
||||
capacity = libWithNet.net.cidr.capacity net;
|
||||
# The base address of the network. Used to convert ip-based reservations to offsets
|
||||
baseAddr = host 0 net;
|
||||
# Reserve some values for the network, host and broadcast address.
|
||||
# The network and broadcast address should never be used, and we
|
||||
# want to reserve the host address for the host. We also convert
|
||||
# any ips to offsets here.
|
||||
init = lib.unique (
|
||||
[0 (capacity - 1)]
|
||||
++ lib.flip map reserved (x:
|
||||
if builtins.typeOf x == "int"
|
||||
then x
|
||||
else -(libWithNet.net.ip.diff baseAddr x))
|
||||
);
|
||||
nHosts = builtins.length hosts;
|
||||
nInit = builtins.length init;
|
||||
# Pre-sort all hosts, to ensure ordering invariance
|
||||
sortedHosts =
|
||||
lib.warnIf
|
||||
((nInit + nHosts) > 0.3 * capacity)
|
||||
"assignIps: hash stability may be degraded since utilization is >30%"
|
||||
(builtins.sort builtins.lessThan hosts);
|
||||
# Generates a hash (i.e. offset value) for a given hostname
|
||||
hashElem = x:
|
||||
builtins.bitAnd (capacity - 1)
|
||||
(extraLib.hexToDec (builtins.substring 0 16 (builtins.hashString "sha256" x)));
|
||||
# Do linear probing. Returns the first unused value at or after the given value.
|
||||
probe = avoid: value:
|
||||
if lib.elem value avoid
|
||||
# Poor man's modulo, because nix has no modulo. Luckily we operate on a residue
|
||||
# class of x modulo 2^n, so we can use bitAnd instead.
|
||||
then probe avoid (builtins.bitAnd (capacity - 1) (value + 1))
|
||||
else value;
|
||||
# Hash a new element and avoid assigning any existing values.
|
||||
assignOne = {
|
||||
assigned,
|
||||
used,
|
||||
}: x: let
|
||||
value = probe used (hashElem x);
|
||||
in {
|
||||
assigned =
|
||||
assigned
|
||||
// {
|
||||
${x} = host value net;
|
||||
};
|
||||
used = [value] ++ used;
|
||||
};
|
||||
in
|
||||
assert lib.assertMsg (cidrSize >= 2 && cidrSize <= 62)
|
||||
"assignIps: cidrSize=${toString cidrSize} is not in [2, 62].";
|
||||
assert lib.assertMsg (nHosts <= capacity - nInit)
|
||||
"assignIps: number of hosts (${toString nHosts}) must be <= capacity (${toString capacity}) - reserved (${toString nInit})";
|
||||
# Assign an ip in the subnet to each element, in order
|
||||
(lib.foldl' assignOne {
|
||||
assigned = {};
|
||||
used = init;
|
||||
}
|
||||
sortedHosts)
|
||||
.assigned;
|
||||
};
|
||||
ip = rec {
|
||||
# Checks whether the given address (with or without cidr notation) is an ipv4 address.
|
||||
isv4 = x: !isv6 x;
|
||||
# Checks whether the given address (with or without cidr notation) is an ipv6 address.
|
||||
isv6 = lib.hasInfix ":";
|
||||
};
|
||||
mac = {
|
||||
# Adds offset to the given base address and ensures the result is in
|
||||
# a locally administered range by replacing the second nibble with a 2.
|
||||
addPrivate = base: offset: let
|
||||
added = libWithNet.net.mac.add base offset;
|
||||
pre = lib.substring 0 1 added;
|
||||
suf = lib.substring 2 (-1) added;
|
||||
in "${pre}2${suf}";
|
||||
# assignMacs :: mac (base) -> int (size) -> [int | mac] (reserved) -> [string] (hosts) -> [mac]
|
||||
#
|
||||
# Assigns a semi-stable MAC address starting in [base, base + 2^size) to each hostname.
|
||||
# The algorithm is based on hashing (abusing sha256) with linear probing.
|
||||
# The order of hosts doesn't matter. No mac (or offset) from the reserved list
|
||||
# will be assigned.
|
||||
#
|
||||
# Examples:
|
||||
#
|
||||
# > net.mac.assignMacs "11:22:33:00:00:00" 24 [] ["a" "b" "c"]
|
||||
# { a = "11:22:33:1b:bd:ca"; b = "11:22:33:39:59:4a"; c = "11:22:33:50:7a:e2"; }
|
||||
#
|
||||
# > net.mac.assignMacs "11:22:33:00:00:00" 24 [] ["a" "b" "c" "a-new-elem"]
|
||||
# { a = "11:22:33:1b:bd:ca"; a-new-elem = "11:22:33:d6:5d:58"; b = "11:22:33:39:59:4a"; c = "11:22:33:50:7a:e2"; }
|
||||
#
|
||||
# > net.mac.assignMacs "11:22:33:00:00:00" 24 ["11:22:33:1b:bd:ca"] ["a" "b" "c"]
|
||||
# { a = "11:22:33:1b:bd:cb"; b = "11:22:33:39:59:4a"; c = "11:22:33:50:7a:e2"; }
|
||||
assignMacs = base: size: reserved: hosts: let
|
||||
capacity = extraLib.pow 2 size;
|
||||
baseAsInt = libWithNet.net.mac.diff base "00:00:00:00:00:00";
|
||||
init = lib.unique (
|
||||
lib.flip map reserved (x:
|
||||
if builtins.typeOf x == "int"
|
||||
then x
|
||||
else libWithNet.net.mac.diff x base)
|
||||
);
|
||||
nHosts = builtins.length hosts;
|
||||
nInit = builtins.length init;
|
||||
# Pre-sort all hosts, to ensure ordering invariance
|
||||
sortedHosts =
|
||||
lib.warnIf
|
||||
((nInit + nHosts) > 0.3 * capacity)
|
||||
"assignMacs: hash stability may be degraded since utilization is >30%"
|
||||
(builtins.sort builtins.lessThan hosts);
|
||||
# Generates a hash (i.e. offset value) for a given hostname
|
||||
hashElem = x:
|
||||
builtins.bitAnd (capacity - 1)
|
||||
(extraLib.hexToDec (builtins.substring 0 16 (builtins.hashString "sha256" x)));
|
||||
# Do linear probing. Returns the first unused value at or after the given value.
|
||||
probe = avoid: value:
|
||||
if lib.elem value avoid
|
||||
# Poor man's modulo, because nix has no modulo. Luckily we operate on a residue
|
||||
# class of x modulo 2^n, so we can use bitAnd instead.
|
||||
then probe avoid (builtins.bitAnd (capacity - 1) (value + 1))
|
||||
else value;
|
||||
# Hash a new element and avoid assigning any existing values.
|
||||
assignOne = {
|
||||
assigned,
|
||||
used,
|
||||
}: x: let
|
||||
value = probe used (hashElem x);
|
||||
in {
|
||||
assigned =
|
||||
assigned
|
||||
// {
|
||||
${x} = libWithNet.net.mac.add value base;
|
||||
};
|
||||
used = [value] ++ used;
|
||||
};
|
||||
in
|
||||
assert lib.assertMsg (size >= 2 && size <= 62)
|
||||
"assignMacs: size=${toString size} is not in [2, 62].";
|
||||
assert lib.assertMsg (builtins.bitAnd (capacity - 1) baseAsInt == 0)
|
||||
"assignMacs: the size=${toString size} least significant bits of the base mac address must be 0.";
|
||||
assert lib.assertMsg (nHosts <= capacity - nInit)
|
||||
"assignMacs: number of hosts (${toString nHosts}) must be <= capacity (${toString capacity}) - reserved (${toString nInit})";
|
||||
# Assign an ip in the subnet to each element, in order
|
||||
(lib.foldl' assignOne {
|
||||
assigned = {};
|
||||
used = init;
|
||||
}
|
||||
sortedHosts)
|
||||
.assigned;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Define local repo secrets
|
||||
repo.secretFiles = let
|
||||
local = nodePath + "/secrets/local.nix.age";
|
||||
in
|
||||
{
|
||||
global = ../../../secrets/global.nix.age;
|
||||
}
|
||||
// lib.optionalAttrs (nodePath != null && lib.pathExists local) {inherit local;};
|
||||
|
||||
# Setup secret rekeying parameters
|
||||
age.rekey = {
|
||||
inherit
|
||||
(inputs.self.secretsConfig)
|
||||
masterIdentities
|
||||
extraEncryptionPubkeys
|
||||
;
|
||||
|
||||
# This is technically impure, but intended. We need to rekey on the
|
||||
# current system due to yubikey availability.
|
||||
forceRekeyOnSystem = builtins.extraBuiltins.unsafeCurrentSystem;
|
||||
hostPubkey = let
|
||||
pubkeyPath =
|
||||
if nodePath == null
|
||||
then null
|
||||
else nodePath + "/secrets/host.pub";
|
||||
in
|
||||
lib.mkIf (pubkeyPath != null && lib.pathExists pubkeyPath) pubkeyPath;
|
||||
};
|
||||
|
||||
age.generators.dhparams.script = {pkgs, ...}: "${pkgs.openssl}/bin/openssl dhparam 4096";
|
||||
age.generators.basic-auth.script = {
|
||||
pkgs,
|
||||
lib,
|
||||
decrypt,
|
||||
deps,
|
||||
...
|
||||
}:
|
||||
lib.flip lib.concatMapStrings deps ({
|
||||
name,
|
||||
host,
|
||||
file,
|
||||
}: ''
|
||||
echo " -> Aggregating [32m"${lib.escapeShellArg host}":[m[33m"${lib.escapeShellArg name}"[m" >&2
|
||||
${decrypt} ${lib.escapeShellArg file} \
|
||||
| ${pkgs.apacheHttpd}/bin/htpasswd -niBC 12 ${lib.escapeShellArg host}"+"${lib.escapeShellArg name} \
|
||||
|| die "Failure while aggregating basic auth hashes"
|
||||
'');
|
||||
|
||||
boot = {
|
||||
initrd.systemd = {
|
||||
enable = true;
|
||||
emergencyAccess = config.repo.secrets.global.root.hashedPassword;
|
||||
# TODO good idea? targets.emergency.wants = ["network.target" "sshd.service"];
|
||||
extraBin = with pkgs; {
|
||||
ip = "${iproute2}/bin/ip";
|
||||
};
|
||||
};
|
||||
|
||||
# Add "rd.systemd.unit=rescue.target" to debug initrd
|
||||
kernelParams = ["log_buf_len=10M"];
|
||||
tmp.useTmpfs = true;
|
||||
};
|
||||
|
||||
# Just before switching, remove the agenix directory if it exists.
|
||||
# This can happen when a secret is used in the initrd because it will
|
||||
# then be copied to the initramfs under the same path. This materializes
|
||||
# /run/agenix as a directory which will cause issues when the actual system tries
|
||||
# to create a link called /run/agenix. Agenix should probably fail in this case,
|
||||
# but doesn't and instead puts the generation link into the existing directory.
|
||||
# TODO See https://github.com/ryantm/agenix/pull/187.
|
||||
system.activationScripts.removeAgenixLink.text = "[[ ! -L /run/agenix ]] && [[ -d /run/agenix ]] && rm -rf /run/agenix";
|
||||
system.activationScripts.agenixNewGeneration.deps = ["removeAgenixLink"];
|
||||
|
||||
# Disable sudo which is entierly unnecessary.
|
||||
security.sudo.enable = false;
|
||||
|
||||
time.timeZone = lib.mkDefault "Europe/Berlin";
|
||||
i18n.defaultLocale = "C.UTF-8";
|
||||
console.keyMap = "de-latin1-nodeadkeys";
|
||||
|
||||
systemd.enableUnifiedCgroupHierarchy = true;
|
||||
users.mutableUsers = false;
|
||||
|
||||
users.deterministicIds = let
|
||||
uidGid = id: {
|
||||
uid = id;
|
||||
gid = id;
|
||||
};
|
||||
in {
|
||||
systemd-oom = uidGid 999;
|
||||
systemd-coredump = uidGid 998;
|
||||
sshd = uidGid 997;
|
||||
nscd = uidGid 996;
|
||||
polkituser = uidGid 995;
|
||||
microvm = uidGid 994;
|
||||
promtail = uidGid 993;
|
||||
grafana = uidGid 992;
|
||||
acme = uidGid 991;
|
||||
kanidm = uidGid 990;
|
||||
loki = uidGid 989;
|
||||
vaultwarden = uidGid 988;
|
||||
oauth2_proxy = uidGid 987;
|
||||
influxdb2 = uidGid 986;
|
||||
telegraf = uidGid 985;
|
||||
rtkit = uidGid 984;
|
||||
};
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
environment.etc."xdg/user-dirs.defaults".text = ''
|
||||
DESKTOP=tmp
|
||||
DOWNLOAD=download
|
||||
TEMPLATES=tmp
|
||||
PUBLICSHARE=opt
|
||||
DOCUMENTS=documents
|
||||
MUSIC=music
|
||||
PICTURES=pictures
|
||||
VIDEOS=tmp
|
||||
'';
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
imports = [
|
||||
./documentation.nix
|
||||
];
|
||||
|
||||
environment.enableDebugInfo = true;
|
||||
repo.defineNixExtraBuiltins = true;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
environment.systemPackages = with pkgs; [man-pages];
|
||||
documentation = {
|
||||
dev.enable = true;
|
||||
man.enable = true;
|
||||
info.enable = lib.mkForce false;
|
||||
};
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{lib, ...}: {
|
||||
boot.loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
systemd-boot = {
|
||||
enable = true;
|
||||
configurationLimit = 15;
|
||||
};
|
||||
timeout = lib.mkDefault 2;
|
||||
};
|
||||
console.earlySetup = true;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./fonts.nix
|
||||
./wayland.nix
|
||||
];
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
fonts = {
|
||||
enableDefaultFonts = false;
|
||||
enableGhostscriptFonts = false;
|
||||
fontDir.enable = false;
|
||||
fontconfig = {
|
||||
defaultFonts = {
|
||||
sansSerif = ["IBM Plex Sans"];
|
||||
serif = ["IBM Plex Sans"];
|
||||
monospace = ["FiraCode Nerd Font"];
|
||||
emoji = ["Noto Color Emoji"];
|
||||
};
|
||||
localConf = ''
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<alias binding="weak">
|
||||
<family>monospace</family>
|
||||
<prefer>
|
||||
<family>emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
<alias binding="weak">
|
||||
<family>sans-serif</family>
|
||||
<prefer>
|
||||
<family>emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
<alias binding="weak">
|
||||
<family>serif</family>
|
||||
<prefer>
|
||||
<family>emoji</family>
|
||||
</prefer>
|
||||
</alias>
|
||||
</fontconfig>
|
||||
'';
|
||||
};
|
||||
fonts = with pkgs; [
|
||||
(nerdfonts.override {fonts = ["FiraCode"];})
|
||||
ibm-plex
|
||||
dejavu_fonts
|
||||
unifont
|
||||
freefont_ttf
|
||||
gyre-fonts # TrueType substitutes for standard PostScript fonts
|
||||
liberation_ttf
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-cjk-serif
|
||||
noto-fonts-emoji
|
||||
noto-fonts-extra
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [wayland];
|
||||
services.dbus.enable = true;
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
wlr.enable = true;
|
||||
# gtk portal needed to make gtk apps happy
|
||||
extraPortals = with pkgs; [xdg-desktop-portal-gtk];
|
||||
};
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [bluetuith];
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
disabledPlugins = ["sap"];
|
||||
settings = {
|
||||
General = {
|
||||
FastConnectable = "true";
|
||||
JustWorksRepairing = "always";
|
||||
MultiProfile = "multiple";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware.pulseaudio = {
|
||||
package = pkgs.pulseaudio.override {bluetoothSupport = true;};
|
||||
extraConfig = ''
|
||||
load-module module-bluetooth-discover
|
||||
load-module module-bluetooth-policy
|
||||
load-module module-switch-on-connect
|
||||
'';
|
||||
extraModules = with pkgs; [pulseaudio-modules-bt];
|
||||
};
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
boot.initrd.availableKernelModules = ["virtio_pci" "virtio_net" "virtio_scsi" "virtio_blk"];
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
powerManagement.cpuFreqGovernor = "powersave";
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
boot.blacklistedKernelModules = ["nouveau"];
|
||||
|
||||
hardware = {
|
||||
nvidia = {
|
||||
modesetting.enable = true;
|
||||
nvidiaPersistenced = true;
|
||||
};
|
||||
opengl = {
|
||||
enable = true;
|
||||
driSupport32Bit = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.xserver.videoDrivers = ["nvidia"];
|
||||
|
||||
virtualisation.docker.enableNvidia = true;
|
||||
virtualisation.podman.enableNvidia = true;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
nixos-hardware,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
nixos-hardware.common-pc-ssd
|
||||
./physical.nix
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
# Ethernet
|
||||
"dwmac_generic"
|
||||
"dwmac_meson8b"
|
||||
"cfg80211"
|
||||
# HDMI
|
||||
"snd_soc_meson_g12a_tohdmitx"
|
||||
"snd_soc_meson_g12a_toacodec"
|
||||
"mdio_mux_meson_g12a"
|
||||
"dw_hdmi"
|
||||
"meson_vdec"
|
||||
"meson_dw_hdmi"
|
||||
"meson_drm"
|
||||
"meson_rng"
|
||||
"drm"
|
||||
"display_connector"
|
||||
];
|
||||
boot.kernelParams = ["console=ttyAML0,115200n8" "console=tty0"];
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
# Configuration for actual physical machines
|
||||
{config, ...}: {
|
||||
hardware = {
|
||||
enableRedistributableFirmware = true;
|
||||
enableAllFirmware = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
fwupd.enable = true;
|
||||
smartd.enable = true;
|
||||
thermald.enable = builtins.elem config.nixpkgs.system ["x86_64-linux"];
|
||||
};
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
nodePath,
|
||||
...
|
||||
}: {
|
||||
age.secrets.initrd_host_ed25519_key = {
|
||||
rekeyFile = nodePath + "/secrets/initrd_host_ed25519_key.age";
|
||||
# Generate only an ssh-ed25519 private key
|
||||
generator.script = {
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: ''
|
||||
(exec 3>&1; ${pkgs.openssh}/bin/ssh-keygen -q -t ed25519 -N "" -f /proc/self/fd/3 <<<y >/dev/null 2>&1)
|
||||
'';
|
||||
};
|
||||
|
||||
boot.initrd.network.enable = true;
|
||||
boot.initrd.network.ssh = {
|
||||
enable = true;
|
||||
port = 4;
|
||||
hostKeys = [config.age.secrets.initrd_host_ed25519_key.path];
|
||||
};
|
||||
|
||||
# Make sure that there is always a valid initrd hostkey available that can be installed into
|
||||
# the initrd. When bootstrapping a system (or re-installing), agenix cannot succeed in decrypting
|
||||
# whatever is given, since the correct hostkey doesn't even exist yet. We still require
|
||||
# a valid hostkey to be available so that the initrd can be generated successfully.
|
||||
# The correct initrd host-key will be installed with the next update after the host is booted
|
||||
# for the first time, and the secrets were rekeyed for the the new host identity.
|
||||
system.activationScripts.agenixEnsureInitrdHostkey = {
|
||||
text = ''
|
||||
[[ -e ${config.age.secrets.initrd_host_ed25519_key.path} ]] \
|
||||
|| ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -N "" -f ${config.age.secrets.initrd_host_ed25519_key.path}
|
||||
'';
|
||||
deps = ["agenixInstall"];
|
||||
};
|
||||
system.activationScripts.agenixChown.deps = ["agenixEnsureInitrdHostkey"];
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
systemd.network.wait-online.anyInterface = true;
|
||||
|
||||
services = {
|
||||
tlp.enable = true;
|
||||
physlock.enable = true;
|
||||
logind = {
|
||||
lidSwitch = "ignore";
|
||||
lidSwitchDocked = "ignore";
|
||||
lidSwitchExternalPower = "ignore";
|
||||
extraConfig = ''
|
||||
HandlePowerKey=suspend
|
||||
HandleSuspendKey=suspend
|
||||
HandleHibernateKey=suspend
|
||||
PowerKeyIgnoreInhibited=yes
|
||||
SuspendKeyIgnoreInhibited=yes
|
||||
HibernateKeyIgnoreInhibited=yes
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
environment.systemPackages = with pkgs; [pulseaudio pulsemixer];
|
||||
sound.enable = false; # ALSA
|
||||
hardware.pulseaudio.enable = lib.mkForce false;
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
jack.enable = true;
|
||||
pulse.enable = true;
|
||||
media-session.enable = false;
|
||||
wireplumber.enable = true;
|
||||
config = {
|
||||
pipewire."context.properties"."default.clock.allowed-rates" = [
|
||||
44100
|
||||
48000
|
||||
88200
|
||||
96000
|
||||
176400
|
||||
192000
|
||||
358000
|
||||
384000
|
||||
716000
|
||||
768000
|
||||
];
|
||||
pipewire-pulse."stream.properties"."resample.quality" = 15;
|
||||
client."stream.properties"."resample.quality" = 15;
|
||||
client-rt."stream.properties"."resample.quality" = 15;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; [yubikey-manager yubikey-personalization age-plugin-yubikey];
|
||||
services.udev.packages = with pkgs; [yubikey-personalization libu2f-host];
|
||||
services.pcscd.enable = true;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
boot.supportedFilesystems = ["zfs"];
|
||||
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
|
||||
# The root pool should never be imported forcefully.
|
||||
# Failure to import is important to notice!
|
||||
boot.zfs.forceImportRoot = false;
|
||||
|
||||
environment.systemPackages = with pkgs; [zfs];
|
||||
|
||||
services.zfs = {
|
||||
autoScrub = {
|
||||
enable = true;
|
||||
interval = "weekly";
|
||||
};
|
||||
trim = {
|
||||
enable = true;
|
||||
interval = "weekly";
|
||||
};
|
||||
};
|
||||
|
||||
services.telegraf.extraConfig.inputs = lib.mkIf config.services.telegraf.enable {
|
||||
zfs.poolMetrics = true;
|
||||
};
|
||||
}
|
|
@ -8,19 +8,17 @@
|
|||
nixos-hardware.common-gpu-intel
|
||||
nixos-hardware.common-pc-laptop
|
||||
nixos-hardware.common-pc-laptop-ssd
|
||||
../../modules/optional/hardware/intel.nix
|
||||
../../modules/optional/hardware/physical.nix
|
||||
|
||||
../common/core
|
||||
../common/dev
|
||||
../common/graphical
|
||||
|
||||
../common/hardware/intel.nix
|
||||
../common/hardware/physical.nix
|
||||
../common/efi.nix
|
||||
../common/initrd-ssh.nix
|
||||
../common/laptop.nix
|
||||
# ../common/sound.nix
|
||||
../common/yubikey.nix
|
||||
../common/zfs.nix
|
||||
../../modules
|
||||
../../modules/optional/boot-efi.nix
|
||||
../../modules/optional/initrd-ssh.nix
|
||||
../../modules/optional/dev
|
||||
../../modules/optional/graphical
|
||||
../../modules/optional/laptop.nix
|
||||
#../../modules/optional/sound.nix
|
||||
../../modules/optional/zfs.nix
|
||||
|
||||
../../users/myuser
|
||||
|
||||
|
@ -30,10 +28,8 @@
|
|||
|
||||
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod"];
|
||||
|
||||
hardware.opengl.enable = true;
|
||||
|
||||
console = {
|
||||
font = "ter-v28n";
|
||||
packages = with pkgs; [terminus_font];
|
||||
packages = [pkgs.terminus_font];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,5 +17,5 @@ in {
|
|||
reloadServices = ["nginx"];
|
||||
};
|
||||
};
|
||||
extra.acme.wildcardDomains = acme.domains;
|
||||
security.acme.wildcardDomains = acme.domains;
|
||||
}
|
||||
|
|
|
@ -4,32 +4,32 @@
|
|||
...
|
||||
}: {
|
||||
imports = [
|
||||
../common/core
|
||||
../common/hardware/hetzner-cloud.nix
|
||||
../common/bios-boot.nix
|
||||
../common/initrd-ssh.nix
|
||||
../common/zfs.nix
|
||||
../../modules/optional/hardware/hetzner-cloud.nix
|
||||
|
||||
./fs.nix
|
||||
./net.nix
|
||||
../../modules
|
||||
../../modules/optional/boot-bios.nix
|
||||
../../modules/optional/initrd-ssh.nix
|
||||
../../modules/optional/zfs.nix
|
||||
|
||||
./acme.nix
|
||||
./fs.nix
|
||||
./net.nix
|
||||
./oauth2.nix
|
||||
];
|
||||
|
||||
users.groups.acme.members = ["nginx"];
|
||||
services.nginx.enable = true;
|
||||
|
||||
extra.promtail = {
|
||||
meta.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${config.extra.wireguard.proxy-sentinel.ipv4} = [config.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
networking.hosts.${config.meta.wireguard.proxy-sentinel.ipv4} = [config.networking.providedDomains.influxdb];
|
||||
meta.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = config.providedDomains.influxdb;
|
||||
influxdb2.domain = config.networking.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
extra.wireguard.proxy-sentinel.server = {
|
||||
meta.wireguard.proxy-sentinel.server = {
|
||||
host = config.networking.fqdn;
|
||||
port = 51443;
|
||||
reservedAddresses = ["10.43.0.0/24" "fd00:43::/120"];
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
pkgs,
|
||||
...
|
||||
}: {
|
||||
extra.oauth2_proxy = {
|
||||
meta.oauth2_proxy = {
|
||||
enable = true;
|
||||
cookieDomain = config.repo.secrets.local.personalDomain;
|
||||
portalDomain = "oauth2.${config.repo.secrets.local.personalDomain}";
|
||||
|
@ -22,15 +22,15 @@
|
|||
in {
|
||||
provider = "oidc";
|
||||
scope = "openid email";
|
||||
loginURL = "https://${config.providedDomains.kanidm}/ui/oauth2";
|
||||
redeemURL = "https://${config.providedDomains.kanidm}/oauth2/token";
|
||||
validateURL = "https://${config.providedDomains.kanidm}/oauth2/openid/${clientId}/userinfo";
|
||||
loginURL = "https://${config.networking.providedDomains.kanidm}/ui/oauth2";
|
||||
redeemURL = "https://${config.networking.providedDomains.kanidm}/oauth2/token";
|
||||
validateURL = "https://${config.networking.providedDomains.kanidm}/oauth2/openid/${clientId}/userinfo";
|
||||
clientID = clientId;
|
||||
keyFile = config.age.secrets.oauth2-proxy-secret.path;
|
||||
email.domains = ["*"];
|
||||
|
||||
extraConfig = {
|
||||
oidc-issuer-url = "https://${config.providedDomains.kanidm}/oauth2/openid/${clientId}";
|
||||
oidc-issuer-url = "https://${config.networking.providedDomains.kanidm}/oauth2/openid/${clientId}";
|
||||
provider-display-name = "Kanidm";
|
||||
#skip-provider-button = true;
|
||||
};
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
imports = [
|
||||
nixos-hardware.common-cpu-intel
|
||||
nixos-hardware.common-pc-ssd
|
||||
../../modules/optional/hardware/intel.nix
|
||||
../../modules/optional/hardware/physical.nix
|
||||
|
||||
../common/core
|
||||
../common/hardware/intel.nix
|
||||
../common/hardware/physical.nix
|
||||
../common/initrd-ssh.nix
|
||||
../common/efi.nix
|
||||
../common/zfs.nix
|
||||
../../modules
|
||||
../../modules/optional/boot-efi.nix
|
||||
../../modules/optional/initrd-ssh.nix
|
||||
../../modules/optional/zfs.nix
|
||||
|
||||
./fs.nix
|
||||
./net.nix
|
||||
|
@ -21,16 +21,16 @@
|
|||
|
||||
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" "sdhci_pci" "r8169"];
|
||||
|
||||
extra.promtail = {
|
||||
meta.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${nodes.sentinel.config.extra.wireguard.proxy-sentinel.ipv4} = [nodes.sentinel.config.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
networking.hosts.${nodes.sentinel.config.meta.wireguard.proxy-sentinel.ipv4} = [nodes.sentinel.config.networking.providedDomains.influxdb];
|
||||
meta.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = nodes.sentinel.config.providedDomains.influxdb;
|
||||
influxdb2.domain = nodes.sentinel.config.networking.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
@ -38,7 +38,11 @@
|
|||
# TODO track my github stats
|
||||
# services.telegraf.extraConfig.inputs.github = {};
|
||||
|
||||
extra.microvms.vms = let
|
||||
meta.microvms.commonImports = [
|
||||
./microvms/common.nix
|
||||
];
|
||||
|
||||
meta.microvms.vms = let
|
||||
defaults = {
|
||||
system = "x86_64-linux";
|
||||
autostart = true;
|
||||
|
|
|
@ -8,30 +8,10 @@
|
|||
sentinelCfg = nodes.sentinel.config;
|
||||
adguardhomeDomain = "adguardhome.${sentinelCfg.repo.secrets.local.personalDomain}";
|
||||
in {
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [config.services.adguardhome.settings.bind_port];
|
||||
};
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.adguardhome.settings.bind_port];
|
||||
|
||||
nodes.sentinel = {
|
||||
providedDomains.adguard = adguardhomeDomain;
|
||||
networking.providedDomains.adguard = adguardhomeDomain;
|
||||
|
||||
services.nginx = {
|
||||
upstreams.adguardhome = {
|
||||
|
@ -43,7 +23,7 @@ in {
|
|||
};
|
||||
virtualHosts.${adguardhomeDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert adguardhomeDomain;
|
||||
useACMEWildcardHost = true;
|
||||
oauth2.enable = true;
|
||||
oauth2.allowedGroups = ["access_adguardhome"];
|
||||
locations."/" = {
|
||||
|
@ -57,7 +37,7 @@ in {
|
|||
services.adguardhome = {
|
||||
enable = true;
|
||||
settings = {
|
||||
bind_host = config.extra.wireguard.proxy-sentinel.ipv4;
|
||||
bind_host = config.meta.wireguard.proxy-sentinel.ipv4;
|
||||
bind_port = 3000;
|
||||
#dns = {
|
||||
# edns_client_subnet.enabled = false;
|
||||
|
|
18
hosts/ward/microvms/common.nix
Normal file
18
hosts/ward/microvms/common.nix
Normal file
|
@ -0,0 +1,18 @@
|
|||
{nodes, ...}: let
|
||||
sentinelCfg = nodes.sentinel.config;
|
||||
in {
|
||||
meta.wireguard-proxy.sentinel = {};
|
||||
meta.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.meta.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.networking.providedDomains.influxdb];
|
||||
meta.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.networking.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
}
|
|
@ -9,27 +9,7 @@
|
|||
sentinelCfg = nodes.sentinel.config;
|
||||
grafanaDomain = "grafana.${sentinelCfg.repo.secrets.local.personalDomain}";
|
||||
in {
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [config.services.grafana.settings.server.http_port];
|
||||
};
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.grafana.settings.server.http_port];
|
||||
|
||||
age.secrets.grafana-secret-key = {
|
||||
rekeyFile = ./secrets/grafana-secret-key.age;
|
||||
|
@ -55,7 +35,7 @@ in {
|
|||
config.age.secrets.grafana-loki-basic-auth-password
|
||||
];
|
||||
|
||||
providedDomains.grafana = grafanaDomain;
|
||||
networking.providedDomains.grafana = grafanaDomain;
|
||||
|
||||
services.nginx = {
|
||||
upstreams.grafana = {
|
||||
|
@ -67,7 +47,7 @@ in {
|
|||
};
|
||||
virtualHosts.${grafanaDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert grafanaDomain;
|
||||
useACMEWildcardHost = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://grafana";
|
||||
proxyWebsockets = true;
|
||||
|
@ -87,7 +67,7 @@ in {
|
|||
root_url = "https://${grafanaDomain}";
|
||||
enforce_domain = true;
|
||||
enable_gzip = true;
|
||||
http_addr = config.extra.wireguard.proxy-sentinel.ipv4;
|
||||
http_addr = config.meta.wireguard.proxy-sentinel.ipv4;
|
||||
http_port = 3001;
|
||||
};
|
||||
|
||||
|
@ -111,9 +91,9 @@ in {
|
|||
client_secret = "aZKNCM6KpjBy4RqwKJXMLXzyx9rKH6MZTFk4wYrKWuBqLj6t"; # TODO temporary test not a real secret
|
||||
scopes = "openid email profile";
|
||||
login_attribute_path = "prefered_username";
|
||||
auth_url = "https://${sentinelCfg.providedDomains.kanidm}/ui/oauth2";
|
||||
token_url = "https://${sentinelCfg.providedDomains.kanidm}/oauth2/token";
|
||||
api_url = "https://${sentinelCfg.providedDomains.kanidm}/oauth2/openid/grafana/userinfo";
|
||||
auth_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/ui/oauth2";
|
||||
token_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/token";
|
||||
api_url = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/openid/grafana/userinfo";
|
||||
use_pkce = true;
|
||||
# Allow mapping oauth2 roles to server admin
|
||||
allow_assign_grafana_admin = true;
|
||||
|
@ -128,7 +108,7 @@ in {
|
|||
name = "InfluxDB (servers)";
|
||||
type = "influxdb";
|
||||
access = "proxy";
|
||||
url = "https://${sentinelCfg.providedDomains.influxdb}";
|
||||
url = "https://${sentinelCfg.networking.providedDomains.influxdb}";
|
||||
orgId = 1;
|
||||
secureJsonData.token = "$__file{${config.age.secrets.grafana-influxdb-token.path}}";
|
||||
jsonData.version = "Flux";
|
||||
|
@ -140,7 +120,7 @@ in {
|
|||
name = "Loki";
|
||||
type = "loki";
|
||||
access = "proxy";
|
||||
url = "https://${sentinelCfg.providedDomains.loki}";
|
||||
url = "https://${sentinelCfg.networking.providedDomains.loki}";
|
||||
orgId = 1;
|
||||
basicAuth = true;
|
||||
basicAuthUser = "${nodeName}+grafana-loki-basic-auth-password";
|
||||
|
|
|
@ -10,31 +10,10 @@
|
|||
influxdbPort = 8086;
|
||||
in {
|
||||
microvm.mem = 1024;
|
||||
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [influxdbPort];
|
||||
};
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [influxdbPort];
|
||||
|
||||
nodes.sentinel = {
|
||||
providedDomains.influxdb = influxdbDomain;
|
||||
networking.providedDomains.influxdb = influxdbDomain;
|
||||
|
||||
services.nginx = {
|
||||
upstreams.influxdb = {
|
||||
|
@ -46,7 +25,7 @@ in {
|
|||
};
|
||||
virtualHosts.${influxdbDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert influxdbDomain;
|
||||
useACMEWildcardHost = true;
|
||||
oauth2.enable = true;
|
||||
oauth2.allowedGroups = ["access_influxdb"];
|
||||
locations."/" = {
|
||||
|
@ -54,7 +33,7 @@ in {
|
|||
proxyWebsockets = true;
|
||||
extraConfig = ''
|
||||
satisfy any;
|
||||
${lib.concatMapStrings (ip: "allow ${ip};\n") sentinelCfg.extra.wireguard.proxy-sentinel.server.reservedAddresses}
|
||||
${lib.concatMapStrings (ip: "allow ${ip};\n") sentinelCfg.meta.wireguard.proxy-sentinel.server.reservedAddresses}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
|
@ -66,7 +45,7 @@ in {
|
|||
enable = true;
|
||||
settings = {
|
||||
reporting-disabled = true;
|
||||
http-bind-address = "${config.extra.wireguard.proxy-sentinel.ipv4}:${toString influxdbPort}";
|
||||
http-bind-address = "${config.meta.wireguard.proxy-sentinel.ipv4}:${toString influxdbPort}";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -10,27 +10,7 @@
|
|||
kanidmDomain = "auth.${sentinelCfg.repo.secrets.local.personalDomain}";
|
||||
kanidmPort = 8300;
|
||||
in {
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [kanidmPort];
|
||||
};
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [kanidmPort];
|
||||
|
||||
age.secrets."kanidm-self-signed.crt" = {
|
||||
rekeyFile = ./secrets/kanidm-self-signed.crt.age;
|
||||
|
@ -45,7 +25,7 @@ in {
|
|||
};
|
||||
|
||||
nodes.sentinel = {
|
||||
providedDomains.kanidm = kanidmDomain;
|
||||
networking.providedDomains.kanidm = kanidmDomain;
|
||||
|
||||
services.nginx = {
|
||||
upstreams.kanidm = {
|
||||
|
@ -57,7 +37,7 @@ in {
|
|||
};
|
||||
virtualHosts.${kanidmDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert kanidmDomain;
|
||||
useACMEWildcardHost = true;
|
||||
locations."/".proxyPass = "https://kanidm";
|
||||
# Allow using self-signed certs to satisfy kanidm's requirement
|
||||
# for TLS connections. (Although this is over wireguard anyway)
|
||||
|
@ -76,7 +56,7 @@ in {
|
|||
origin = "https://${kanidmDomain}";
|
||||
tls_chain = config.age.secrets."kanidm-self-signed.crt".path;
|
||||
tls_key = config.age.secrets."kanidm-self-signed.key".path;
|
||||
bindaddress = "${config.extra.wireguard.proxy-sentinel.ipv4}:${toString kanidmPort}";
|
||||
bindaddress = "${config.meta.wireguard.proxy-sentinel.ipv4}:${toString kanidmPort}";
|
||||
trust_x_forward_for = true;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,30 +8,10 @@
|
|||
sentinelCfg = nodes.sentinel.config;
|
||||
lokiDomain = "loki.${sentinelCfg.repo.secrets.local.personalDomain}";
|
||||
in {
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [config.services.loki.configuration.server.http_listen_port];
|
||||
};
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [config.services.loki.configuration.server.http_listen_port];
|
||||
|
||||
nodes.sentinel = {
|
||||
providedDomains.loki = lokiDomain;
|
||||
networking.providedDomains.loki = lokiDomain;
|
||||
|
||||
age.secrets.loki-basic-auth-hashes = {
|
||||
rekeyFile = ./secrets/loki-basic-auth-hashes.age;
|
||||
|
@ -52,7 +32,7 @@ in {
|
|||
};
|
||||
virtualHosts.${lokiDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert lokiDomain;
|
||||
useACMEWildcardHost = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://loki";
|
||||
proxyWebsockets = true;
|
||||
|
@ -86,7 +66,7 @@ in {
|
|||
auth_enabled = false;
|
||||
|
||||
server = {
|
||||
http_listen_address = config.extra.wireguard.proxy-sentinel.ipv4;
|
||||
http_listen_address = config.meta.wireguard.proxy-sentinel.ipv4;
|
||||
http_listen_port = 3100;
|
||||
log_level = "warn";
|
||||
};
|
||||
|
|
|
@ -8,68 +8,50 @@
|
|||
sentinelCfg = nodes.sentinel.config;
|
||||
vaultwardenDomain = "pw.${sentinelCfg.repo.secrets.local.personalDomain}";
|
||||
in {
|
||||
imports = [
|
||||
../../../../modules/proxy-via-sentinel.nix
|
||||
meta.wireguard-proxy.sentinel.allowedTCPPorts = [
|
||||
config.services.vaultwarden.config.rocketPort
|
||||
config.services.vaultwarden.config.websocketPort
|
||||
];
|
||||
|
||||
extra.promtail = {
|
||||
enable = true;
|
||||
proxy = "sentinel";
|
||||
};
|
||||
|
||||
# Connect safely via wireguard to skip authentication
|
||||
networking.hosts.${sentinelCfg.extra.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.providedDomains.influxdb];
|
||||
extra.telegraf = {
|
||||
enable = true;
|
||||
influxdb2.domain = sentinelCfg.providedDomains.influxdb;
|
||||
influxdb2.organization = "servers";
|
||||
influxdb2.bucket = "telegraf";
|
||||
};
|
||||
|
||||
age.secrets.vaultwarden-env = {
|
||||
rekeyFile = ./secrets/vaultwarden-env.age;
|
||||
mode = "440";
|
||||
group = "vaultwarden";
|
||||
};
|
||||
|
||||
networking.nftables.firewall.rules = lib.mkForce {
|
||||
sentinel-to-local.allowedTCPPorts = [
|
||||
config.services.vaultwarden.config.rocketPort
|
||||
config.services.vaultwarden.config.websocketPort
|
||||
];
|
||||
};
|
||||
|
||||
nodes.sentinel = {
|
||||
providedDomains.vaultwarden = vaultwardenDomain;
|
||||
networking.providedDomains.vaultwarden = vaultwardenDomain;
|
||||
|
||||
upstreams.vaultwarden = {
|
||||
servers."${config.services.vaultwarden.config.rocketAddress}:${toString config.services.vaultwarden.config.rocketPort}" = {};
|
||||
extraConfig = ''
|
||||
zone vaultwarden 64k;
|
||||
keepalive 2;
|
||||
'';
|
||||
};
|
||||
upstreams.vaultwarden-websocket = {
|
||||
servers."${config.services.vaultwarden.config.websocketAddress}:${toString config.services.vaultwarden.config.websocketPort}" = {};
|
||||
extraConfig = ''
|
||||
zone vaultwarden-websocket 64k;
|
||||
keepalive 2;
|
||||
'';
|
||||
};
|
||||
virtualHosts.${vaultwardenDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEHost = sentinelCfg.lib.extra.matchingWildcardCert vaultwardenDomain;
|
||||
extraConfig = ''
|
||||
client_max_body_size 256M;
|
||||
'';
|
||||
locations."/".proxyPass = "http://vaultwarden";
|
||||
locations."/notifications/hub" = {
|
||||
proxyPass = "http://vaultwarden-websocket";
|
||||
proxyWebsockets = true;
|
||||
services.nginx = {
|
||||
upstreams.vaultwarden = {
|
||||
servers."${config.services.vaultwarden.config.rocketAddress}:${toString config.services.vaultwarden.config.rocketPort}" = {};
|
||||
extraConfig = ''
|
||||
zone vaultwarden 64k;
|
||||
keepalive 2;
|
||||
'';
|
||||
};
|
||||
locations."/notifications/hub/negotiate" = {
|
||||
proxyPass = "http://vaultwarden";
|
||||
proxyWebsockets = true;
|
||||
upstreams.vaultwarden-websocket = {
|
||||
servers."${config.services.vaultwarden.config.websocketAddress}:${toString config.services.vaultwarden.config.websocketPort}" = {};
|
||||
extraConfig = ''
|
||||
zone vaultwarden-websocket 64k;
|
||||
keepalive 2;
|
||||
'';
|
||||
};
|
||||
virtualHosts.${vaultwardenDomain} = {
|
||||
forceSSL = true;
|
||||
useACMEWildcardHost = true;
|
||||
extraConfig = ''
|
||||
client_max_body_size 256M;
|
||||
'';
|
||||
locations."/".proxyPass = "http://vaultwarden";
|
||||
locations."/notifications/hub" = {
|
||||
proxyPass = "http://vaultwarden-websocket";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
locations."/notifications/hub/negotiate" = {
|
||||
proxyPass = "http://vaultwarden";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -84,9 +66,9 @@ in {
|
|||
webVaultEnabled = true;
|
||||
|
||||
websocketEnabled = true;
|
||||
websocketAddress = config.extra.wireguard.proxy-sentinel.ipv4;
|
||||
websocketAddress = config.meta.wireguard.proxy-sentinel.ipv4;
|
||||
websocketPort = 3012;
|
||||
rocketAddress = config.extra.wireguard.proxy-sentinel.ipv4;
|
||||
rocketAddress = config.meta.wireguard.proxy-sentinel.ipv4;
|
||||
rocketPort = 8012;
|
||||
|
||||
signupsAllowed = false;
|
||||
|
|
|
@ -172,12 +172,12 @@ in {
|
|||
|
||||
systemd.services.kea-dhcp4-server.after = ["sys-subsystem-net-devices-${utils.escapeSystemdPath "lan-self"}.device"];
|
||||
|
||||
extra.microvms.networking = {
|
||||
meta.microvms.networking = {
|
||||
baseMac = config.repo.secrets.local.networking.interfaces.lan.mac;
|
||||
macvtapInterface = "lan";
|
||||
wireguard.openFirewallRules = ["lan-to-local"];
|
||||
};
|
||||
|
||||
# Allow accessing influx
|
||||
extra.wireguard.proxy-sentinel.client.via = "sentinel";
|
||||
meta.wireguard.proxy-sentinel.client.via = "sentinel";
|
||||
}
|
||||
|
|
|
@ -6,26 +6,25 @@
|
|||
...
|
||||
}: {
|
||||
imports = [
|
||||
../common/core
|
||||
../common/hardware/odroid-n2plus.nix
|
||||
../common/initrd-ssh.nix
|
||||
../common/zfs.nix
|
||||
../common/bios-boot.nix
|
||||
../../modules/optional/hardware/odroid-n2plus.nix
|
||||
|
||||
./fs.nix
|
||||
./net.nix
|
||||
../../modules
|
||||
../../modules/optional/boot-bios.nix
|
||||
../../modules/optional/initrd-ssh.nix
|
||||
../../modules/optional/zfs.nix
|
||||
|
||||
#./dnsmasq.nix
|
||||
./esphome.nix
|
||||
./fs.nix
|
||||
./home-assistant.nix
|
||||
./hostapd.nix
|
||||
./mosquitto.nix
|
||||
./net.nix
|
||||
./nginx.nix
|
||||
./zigbee2mqtt.nix
|
||||
];
|
||||
|
||||
# TODO boot.loader.grub.devices = ["/dev/disk/by-id/${config.repo.secrets.local.disk.main}"];
|
||||
console.earlySetup = true;
|
||||
|
||||
# Fails if there are no SMART devices
|
||||
services.smartd.enable = lib.mkForce false;
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
pkgs,
|
||||
...
|
||||
}: {
|
||||
imports = [../../modules/hostapd.nix];
|
||||
disabledModules = ["services/networking/hostapd.nix"];
|
||||
|
||||
# Associates each known client to a unique password
|
||||
age.secrets.wifi-clients.rekeyFile = ./secrets/wifi-clients.age;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue