Merge config/ into modules/
parent
1f100e5f87
commit
e9639581a3
282
config/c3d2.nix
282
config/c3d2.nix
|
@ -1,282 +0,0 @@
|
|||
# This module sets configuration for all NixOS machines defined in this flake
|
||||
|
||||
{ zentralwerk, hostRegistry, config, options, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
hqPrefix64 = lib.removeSuffix "::" (builtins.head (
|
||||
builtins.split "/" zentralwerk.lib.config.site.net.c3d2.subnets6.dn42
|
||||
));
|
||||
|
||||
# Generate a deterministic IPv6 address for a 64 bit prefix
|
||||
# and seed string. Prefix must not contain trailing ':'.
|
||||
toIpv6Address = prefix64: seed:
|
||||
with builtins;
|
||||
let
|
||||
digest = builtins.hashString "sha256" seed;
|
||||
hextets = map (i: substring (4 * i) 4 digest) [ 0 1 2 3 ];
|
||||
in concatStringsSep ":" ([ prefix64 ] ++ hextets);
|
||||
|
||||
# Generate a deterministic public IPv6 addresses
|
||||
# for the HQ networking using a seed string.
|
||||
toHqPrivateAddress = toIpv6Address hqPrefix64;
|
||||
|
||||
in {
|
||||
imports = [
|
||||
./stats.nix
|
||||
./audio-server
|
||||
./logging.nix
|
||||
];
|
||||
|
||||
|
||||
config = let
|
||||
cfg = config.c3d2;
|
||||
mkIfIsInHq = x: lib.mkIf cfg.isInHq (lib.mkDefault x);
|
||||
in {
|
||||
# Configuration specific to this machine
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.isInHq -> (config.users.users.root.password == null);
|
||||
message = "Root passwords not allowed in HQ";
|
||||
}
|
||||
{
|
||||
assertion = cfg.hq.enableBinaryCache -> cfg.mergeHostsFile;
|
||||
message = "mergeHostsFile must be enabled for enableBinaryCache";
|
||||
}
|
||||
{
|
||||
assertion = cfg.hq.enableMpdProxy -> cfg.mergeHostsFile;
|
||||
message = "mergeHostsFile must be enabled for enableMpdProxy";
|
||||
}
|
||||
{
|
||||
assertion = cfg.isInHq -> builtins.hasAttr config.networking.hostName cfg.hosts;
|
||||
message = "${config.networking.hostName} is not registered in ${
|
||||
toString ../host-registry.nix
|
||||
}";
|
||||
}
|
||||
( # Check for host registry address collisions
|
||||
let
|
||||
getAddrHosts = key:
|
||||
builtins.foldl' (result: host:
|
||||
if cfg.hosts.${host}.${key} != null
|
||||
then let
|
||||
addr = cfg.hosts."${host}"."${key}";
|
||||
in if result ? "${addr}"
|
||||
then result // {
|
||||
"${addr}" = result."${addr}" ++ [ host ];
|
||||
}
|
||||
else result // {
|
||||
"${addr}" = [ host ];
|
||||
}
|
||||
else result
|
||||
) {} (builtins.attrNames cfg.hosts);
|
||||
dupHosts =
|
||||
builtins.concatMap (hosts:
|
||||
if builtins.length hosts == 1
|
||||
then []
|
||||
else hosts
|
||||
) (
|
||||
builtins.attrValues (
|
||||
getAddrHosts "ip4" // getAddrHosts "ip6"
|
||||
)
|
||||
);
|
||||
in {
|
||||
assertion = dupHosts == [];
|
||||
message = "Hosts have duplicate addresses: ${
|
||||
lib.concatStringsSep " " dupHosts
|
||||
}";
|
||||
})
|
||||
];
|
||||
|
||||
boot.cleanTmpDir = true;
|
||||
|
||||
c3d2.allUsersCanSshRoot = lib.mkDefault true;
|
||||
|
||||
i18n = {
|
||||
defaultLocale = "en_US.UTF-8";
|
||||
supportedLocales = [
|
||||
"en_US.UTF-8/UTF-8"
|
||||
"de_DE.UTF-8/UTF-8"
|
||||
"C.UTF-8/UTF-8"
|
||||
];
|
||||
};
|
||||
|
||||
networking.defaultGateway = lib.mkIf (!config.networking.useNetworkd) (
|
||||
mkIfIsInHq "172.22.99.4"
|
||||
);
|
||||
|
||||
networking.domain = mkIfIsInHq "hq.c3d2.de";
|
||||
|
||||
systemd.network.networks =
|
||||
if cfg.hq.interface != null && config.networking.useNetworkd
|
||||
then {
|
||||
"40-eth0".routes = [ {
|
||||
routeConfig = {
|
||||
Gateway = "172.22.99.4";
|
||||
GatewayOnLink = true;
|
||||
};
|
||||
} ];
|
||||
} else {};
|
||||
networking.interfaces =
|
||||
/* (if cfg.hq.externalInterface == null then
|
||||
{ }
|
||||
else {
|
||||
"${cfg.hq.externalInterface}" = {
|
||||
ipv6.addresses = [{
|
||||
address = toHqPublicAddress config.networking.hostName;
|
||||
prefixLength = 64;
|
||||
}];
|
||||
};
|
||||
}) //
|
||||
*/
|
||||
if cfg.hq.interface == null then
|
||||
{ }
|
||||
else {
|
||||
"${cfg.hq.interface}" = {
|
||||
ipv6.addresses = [{
|
||||
address = toHqPrivateAddress config.networking.hostName;
|
||||
prefixLength = 64;
|
||||
}];
|
||||
};
|
||||
};
|
||||
|
||||
networking.nameservers = with hostRegistry.hosts.dnscache; [
|
||||
ip4
|
||||
ip6
|
||||
"9.9.9.9"
|
||||
];
|
||||
networking.useHostResolvConf = lib.mkIf (!config.services.resolved.enable) true;
|
||||
environment.etc."resolv.conf" = lib.mkIf (!config.services.resolved.enable) {
|
||||
text = lib.concatMapStrings (ns: ''
|
||||
nameserver ${ns}
|
||||
'') config.networking.nameservers;
|
||||
};
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
auto-optimise-store = true;
|
||||
trusted-public-keys = lib.mkIf (config.networking.hostName != "hydra") [
|
||||
(builtins.readFile ../hosts/hydra/cache-pub.key)
|
||||
];
|
||||
substituters = lib.mkIf (config.networking.hostName != "hydra") (
|
||||
lib.mkBefore [ "https://nix-serve.hq.c3d2.de" ]
|
||||
);
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
dates = "06:00";
|
||||
options = "--delete-older-than 21d";
|
||||
randomizedDelaySec = "6h";
|
||||
};
|
||||
registry.c3d2 = {
|
||||
from = {
|
||||
id = "c3d2";
|
||||
type = "indirect";
|
||||
};
|
||||
to = {
|
||||
type = "git";
|
||||
url = "https://gitea.c3d2.de/C3D2/nix-config.git";
|
||||
};
|
||||
};
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
builders-use-substitutes = true
|
||||
'';
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
# Required for deployment
|
||||
enable = true;
|
||||
permitRootLogin = "prohibit-password";
|
||||
};
|
||||
|
||||
sops.age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
# Network fetchers
|
||||
curl wget git
|
||||
# System monitors
|
||||
htop iotop bmon
|
||||
ripgrep
|
||||
# Terminal managers
|
||||
tmux screen
|
||||
# Editors
|
||||
vim
|
||||
# Pipeview
|
||||
pv
|
||||
# Network debugging
|
||||
tcpdump ethtool mtr
|
||||
];
|
||||
variables = {
|
||||
TERM = "xterm-256color";
|
||||
};
|
||||
# breaks various package builds
|
||||
noXlibs = lib.mkForce false;
|
||||
};
|
||||
|
||||
programs = {
|
||||
ssh.knownHosts = with builtins;
|
||||
let
|
||||
intersectKeys = intersectAttrs {
|
||||
publicKey = null;
|
||||
publicKeyFile = null;
|
||||
};
|
||||
list = map (name:
|
||||
let
|
||||
host = getAttr name cfg.hosts;
|
||||
sshAttrs = intersectKeys host;
|
||||
in if sshAttrs == { } then
|
||||
null
|
||||
else {
|
||||
inherit name;
|
||||
value = let
|
||||
ip6 = if host.ip6 != null then
|
||||
host.ip6
|
||||
else
|
||||
toHqPrivateAddress name;
|
||||
in {
|
||||
publicKey = null;
|
||||
publicKeyFile = null;
|
||||
hostNames = [ ip6 "${name}.hq.c3d2.de" "${name}.hq" name ];
|
||||
} // sshAttrs;
|
||||
}) (builtins.attrNames cfg.hosts);
|
||||
keyedHosts = filter (x: x.value.publicKey != null || x.value.publicKeyFile != null) list;
|
||||
in listToAttrs keyedHosts;
|
||||
|
||||
vim.defaultEditor = true;
|
||||
};
|
||||
|
||||
services.nginx = lib.mkIf config.services.nginx.enable {
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
time.timeZone = lib.mkDefault "Europe/Berlin";
|
||||
|
||||
# Reboot on hang
|
||||
systemd.watchdog = lib.mkIf (!config.boot.isContainer) {
|
||||
runtimeTime = "15s";
|
||||
rebootTime = "15s";
|
||||
};
|
||||
|
||||
# Defaults for LetsEncrypt
|
||||
security.acme =
|
||||
if options.security.acme ? defaults
|
||||
then {
|
||||
acceptTerms = true;
|
||||
# NixOS>=22.05
|
||||
defaults = {
|
||||
email = cfg.acmeEmail;
|
||||
# letsencrypt staging server with way higher rate limits
|
||||
# server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
||||
};
|
||||
}
|
||||
else {
|
||||
acceptTerms = true;
|
||||
# TODO: NixOS<=21.05
|
||||
email = cfg.acmeEmail;
|
||||
};
|
||||
zramSwap.enable = true;
|
||||
};
|
||||
}
|
|
@ -520,9 +520,9 @@
|
|||
})
|
||||
|
||||
self.nixosModules.c3d2
|
||||
./config/audio-server
|
||||
./config/c3d2.nix
|
||||
./config/stats.nix
|
||||
./modules/audio-server.nix
|
||||
./modules/c3d2.nix
|
||||
./modules/stats.nix
|
||||
./modules/pi-sensors.nix
|
||||
] ++ modules;
|
||||
};
|
||||
|
@ -962,7 +962,7 @@
|
|||
];
|
||||
c3d2.hosts = hostRegistry.hosts;
|
||||
c3d2.users = import ./users.nix;
|
||||
c3d2.nncp.neigh = import ./config/nncp-relays.nix;
|
||||
c3d2.nncp.neigh = import ./modules/nncp-relays.nix;
|
||||
};
|
||||
cluster = ./modules/cluster;
|
||||
cluster-network = ./modules/cluster-network.nix;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
./hydra.nix
|
||||
./updater.nix
|
||||
./nomad-server.nix
|
||||
../../config/c3d2.nix
|
||||
../../modules/c3d2.nix
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
{
|
||||
imports = [
|
||||
../../../config
|
||||
../../../config/lxc-container.nix
|
||||
../../../modules/lxc-container.nix
|
||||
];
|
||||
|
||||
networking = {
|
||||
|
|
532
modules/c3d2.nix
532
modules/c3d2.nix
|
@ -1,9 +1,12 @@
|
|||
# This module defines options for use by all C3D2 machines.
|
||||
|
||||
{ options, config, lib, pkgs, ... }:
|
||||
{ zentralwerk, hostRegistry, config, options, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.c3d2;
|
||||
|
||||
hqPrefix64 = lib.removeSuffix "::" (builtins.head (
|
||||
builtins.split "/" zentralwerk.lib.config.site.net.c3d2.subnets6.dn42
|
||||
));
|
||||
|
||||
neighMod = with lib; types.submodule {
|
||||
options = {
|
||||
addrs = mkOption {
|
||||
|
@ -18,145 +21,157 @@ let
|
|||
} // (with builtins; let value = mkOption { type = types.str; }; in
|
||||
listToAttrs (map (name: { inherit name value; }) [ "exchpub" "id" "noisepub" "signpub" ]));
|
||||
};
|
||||
|
||||
# Generate a deterministic IPv6 address for a 64 bit prefix
|
||||
# and seed string. Prefix must not contain trailing ':'.
|
||||
toIpv6Address = prefix64: seed:
|
||||
with builtins;
|
||||
let
|
||||
digest = builtins.hashString "sha256" seed;
|
||||
hextets = map (i: substring (4 * i) 4 digest) [ 0 1 2 3 ];
|
||||
in
|
||||
concatStringsSep ":" ([ prefix64 ] ++ hextets);
|
||||
|
||||
# Generate a deterministic public IPv6 addresses
|
||||
# for the HQ networking using a seed string.
|
||||
toHqPrivateAddress = toIpv6Address hqPrefix64;
|
||||
in
|
||||
{
|
||||
options.c3d2 = with lib;
|
||||
with lib.types; {
|
||||
imports = [
|
||||
./stats.nix
|
||||
./audio-server.nix
|
||||
./logging.nix
|
||||
];
|
||||
|
||||
acmeEmail = mkOption {
|
||||
type = str;
|
||||
default = "mail@c3d2.de";
|
||||
options.c3d2 = with lib; {
|
||||
acmeEmail = mkOption {
|
||||
type = types.str;
|
||||
default = "mail@c3d2.de";
|
||||
description = ''
|
||||
Admin email address to use for Letsencrypt
|
||||
'';
|
||||
};
|
||||
|
||||
allUsersCanSshRoot = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Let all people in <literal>c3d2.users</literal>
|
||||
login as root for deployment via SSH.
|
||||
'';
|
||||
};
|
||||
|
||||
isInHq = mkEnableOption "HQ presence (TODO: what is this? association to VLAN 5?)";
|
||||
|
||||
enableMotd = mkOption {
|
||||
type = types.bool;
|
||||
default = cfg.isInHq;
|
||||
defaultText = literalExample "config.c3d2.isInHq";
|
||||
};
|
||||
|
||||
mergeHostsFile = mkOption {
|
||||
type = types.bool;
|
||||
default = cfg.isInHq;
|
||||
description = ''
|
||||
Whether to add <literal>c3d2.hosts</literal> to /etc/hosts.
|
||||
'';
|
||||
};
|
||||
|
||||
mergeNncpSettings = mkEnableOption ''
|
||||
Whether to merge <literal>c3d2.nncp.<…>.nncp</literal>
|
||||
into <literal>programs.nncp.settings</literal>.
|
||||
'';
|
||||
|
||||
k-ot.enable = mkEnableOption ''
|
||||
Add k-ot user to this machine. Anyone with an SSH key listed in
|
||||
<literal>c3d2.users</literal> can log in as this user.
|
||||
'';
|
||||
|
||||
hq = {
|
||||
interface = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = "eth0";
|
||||
description = ''
|
||||
Admin email address to use for Letsencrypt
|
||||
Configure the given interface name with an internal IP address.
|
||||
'';
|
||||
};
|
||||
|
||||
allUsersCanSshRoot = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Let all people in <literal>c3d2.users</literal>
|
||||
login as root for deployment via SSH.
|
||||
'';
|
||||
};
|
||||
|
||||
isInHq = mkEnableOption "HQ presence (TODO: what is this? association to VLAN 5?)";
|
||||
|
||||
enableMotd = mkOption {
|
||||
type = bool;
|
||||
enableBinaryCache = mkOption {
|
||||
type = types.bool;
|
||||
default = cfg.isInHq;
|
||||
defaultText = literalExample "config.c3d2.isInHq";
|
||||
description = "Whether to enable the local Nix binary cache";
|
||||
};
|
||||
|
||||
mergeHostsFile = mkOption {
|
||||
type = bool;
|
||||
default = cfg.isInHq;
|
||||
enableMpdProxy = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to proxy the local MPD database";
|
||||
};
|
||||
|
||||
journalToMqtt = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
};
|
||||
|
||||
hosts =
|
||||
mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
ether = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
ip4 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
ip6 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
publicKey = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
wol = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
serial = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Hardware serial number to help identification when netbooting.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
nncp = {
|
||||
neigh = mkOption {
|
||||
type = with types; attrsOf neighMod;
|
||||
default = { };
|
||||
description = ''
|
||||
Whether to add <literal>c3d2.hosts</literal> to /etc/hosts.
|
||||
Attrset of NNCP neighbours for relaying packets.
|
||||
User endpoints go in <literal>c3d2.users</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
mergeNncpSettings = mkEnableOption ''
|
||||
Whether to merge <literal>c3d2.nncp.<…>.nncp</literal>
|
||||
into <literal>programs.nncp.settings</literal>.
|
||||
'';
|
||||
|
||||
k-ot.enable = mkEnableOption ''
|
||||
Add k-ot user to this machine. Anyone with an SSH key listed in
|
||||
<literal>c3d2.users</literal> can log in as this user.
|
||||
'';
|
||||
|
||||
hq = {
|
||||
interface = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
example = "eth0";
|
||||
description = ''
|
||||
Configure the given interface name with an internal IP address.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBinaryCache = mkOption {
|
||||
type = bool;
|
||||
default = cfg.isInHq;
|
||||
defaultText = literalExample "config.c3d2.isInHq";
|
||||
description = "Whether to enable the local Nix binary cache";
|
||||
};
|
||||
|
||||
enableMpdProxy = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
description = "Whether to proxy the local MPD database";
|
||||
};
|
||||
|
||||
journalToMqtt = mkOption {
|
||||
type = bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
hosts =
|
||||
mkOption {
|
||||
type = attrsOf (submodule {
|
||||
options = {
|
||||
ether = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
ip4 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
ip6 = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
publicKey = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
};
|
||||
wol = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
serial = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
Hardware serial number to help identification when netbooting.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
nncp = {
|
||||
neigh = mkOption {
|
||||
type = with types; attrsOf neighMod;
|
||||
default = { };
|
||||
description = ''
|
||||
Attrset of NNCP neighbours for relaying packets.
|
||||
User endpoints go in <literal>c3d2.users</literal>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
users =
|
||||
mkOption {
|
||||
type = attrsOf
|
||||
(submodule {
|
||||
options = {
|
||||
sshKeys = mkOption {
|
||||
type = with types;
|
||||
listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
users = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options.sshKeys = mkOption {
|
||||
type = with types; listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
adminKeys = (with builtins; lib.lists.flatten (
|
||||
|
@ -164,6 +179,7 @@ in
|
|||
(getAttr "sshKeys")
|
||||
(attrValues cfg.users)
|
||||
));
|
||||
mkIfIsInHq = x: lib.mkIf cfg.isInHq (lib.mkDefault x);
|
||||
in
|
||||
{
|
||||
networking.hosts = lib.mkIf cfg.mergeHostsFile
|
||||
|
@ -175,16 +191,13 @@ in
|
|||
(lib.attrsets.filterAttrs (n: v: v.ip6 != null) cfg.hosts)
|
||||
));
|
||||
|
||||
programs = lib.optionalAttrs (options.programs ? nncp) {
|
||||
nncp.settings = lib.optionalAttrs cfg.mergeNncpSettings cfg.nncp;
|
||||
};
|
||||
programs.nncp.settings = lib.optionalAttrs cfg.mergeNncpSettings cfg.nncp;
|
||||
|
||||
users.motd = lib.mkIf cfg.enableMotd (builtins.readFile ./motd);
|
||||
|
||||
users = {
|
||||
users = {
|
||||
k-ot = lib.mkIf cfg.k-ot.enable {
|
||||
packages = with pkgs; [ screen tmux ];
|
||||
createHome = true;
|
||||
isNormalUser = true;
|
||||
uid = 1000;
|
||||
|
@ -210,7 +223,7 @@ in
|
|||
current_boot_only = true;
|
||||
};
|
||||
sinks.mqtt = {
|
||||
inputs = ["journal"];
|
||||
inputs = [ "journal" ];
|
||||
type = "mqtt";
|
||||
host = "broker.serv.zentralwerk.org";
|
||||
# port = 8883;
|
||||
|
@ -239,7 +252,8 @@ in
|
|||
done
|
||||
echo '}'
|
||||
'';
|
||||
in {
|
||||
in
|
||||
{
|
||||
type = "exec";
|
||||
command = [
|
||||
catSecrets
|
||||
|
@ -251,13 +265,261 @@ in
|
|||
};
|
||||
sops.secrets = lib.mkIf config.c3d2.hq.journalToMqtt {
|
||||
"mqtt/user" = {
|
||||
sopsFile = ../config/mqtt.yaml;
|
||||
sopsFile = ../modules/mqtt.yaml;
|
||||
owner = config.systemd.services.vector.serviceConfig.User;
|
||||
};
|
||||
"mqtt/password" = {
|
||||
sopsFile = ../config/mqtt.yaml;
|
||||
sopsFile = ../modules/mqtt.yaml;
|
||||
owner = config.systemd.services.vector.serviceConfig.User;
|
||||
};
|
||||
};
|
||||
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.isInHq -> (config.users.users.root.password == null);
|
||||
message = "Root passwords not allowed in HQ";
|
||||
}
|
||||
{
|
||||
assertion = cfg.hq.enableBinaryCache -> cfg.mergeHostsFile;
|
||||
message = "mergeHostsFile must be enabled for enableBinaryCache";
|
||||
}
|
||||
{
|
||||
assertion = cfg.hq.enableMpdProxy -> cfg.mergeHostsFile;
|
||||
message = "mergeHostsFile must be enabled for enableMpdProxy";
|
||||
}
|
||||
{
|
||||
assertion = cfg.isInHq -> builtins.hasAttr config.networking.hostName cfg.hosts;
|
||||
message = "${config.networking.hostName} is not registered in ${toString ../host-registry.nix}";
|
||||
}
|
||||
(
|
||||
# Check for host registry address collisions
|
||||
let
|
||||
getAddrHosts = key:
|
||||
builtins.foldl'
|
||||
(result: host:
|
||||
if cfg.hosts.${host}.${key} != null
|
||||
then
|
||||
let
|
||||
addr = cfg.hosts."${host}"."${key}";
|
||||
in
|
||||
if result ? "${addr}"
|
||||
then result // {
|
||||
"${addr}" = result."${addr}" ++ [ host ];
|
||||
}
|
||||
else result // {
|
||||
"${addr}" = [ host ];
|
||||
}
|
||||
else result
|
||||
)
|
||||
{ }
|
||||
(builtins.attrNames cfg.hosts);
|
||||
dupHosts =
|
||||
builtins.concatMap
|
||||
(hosts:
|
||||
if builtins.length hosts == 1
|
||||
then [ ]
|
||||
else hosts
|
||||
)
|
||||
(
|
||||
builtins.attrValues (
|
||||
getAddrHosts "ip4" // getAddrHosts "ip6"
|
||||
)
|
||||
);
|
||||
in
|
||||
{
|
||||
assertion = dupHosts == [ ];
|
||||
message = "Hosts have duplicate addresses: ${lib.concatStringsSep " " dupHosts}";
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
boot.cleanTmpDir = true;
|
||||
|
||||
c3d2.allUsersCanSshRoot = lib.mkDefault true;
|
||||
|
||||
i18n = {
|
||||
defaultLocale = "en_US.UTF-8";
|
||||
supportedLocales = [
|
||||
"en_US.UTF-8"
|
||||
"de_DE.UTF-8"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.network.networks = lib.mkIf (cfg.hq.interface != null && config.networking.useNetworkd) {
|
||||
"40-eth0".routes = [{
|
||||
routeConfig = {
|
||||
Gateway = "172.22.99.4";
|
||||
GatewayOnLink = true;
|
||||
};
|
||||
}];
|
||||
};
|
||||
|
||||
networking = {
|
||||
defaultGateway = lib.mkIf (!config.networking.useNetworkd) (
|
||||
mkIfIsInHq "172.22.99.4"
|
||||
);
|
||||
|
||||
domain = mkIfIsInHq "hq.c3d2.de";
|
||||
|
||||
interfaces = lib.mkIf (cfg.hq.interface != null) {
|
||||
"${cfg.hq.interface}".ipv6.addresses = [{
|
||||
address = toHqPrivateAddress config.networking.hostName;
|
||||
prefixLength = 64;
|
||||
}];
|
||||
};
|
||||
|
||||
nameservers = with hostRegistry.hosts.dnscache; [
|
||||
ip4
|
||||
ip6
|
||||
"9.9.9.9"
|
||||
];
|
||||
useHostResolvConf = lib.mkIf (!config.services.resolved.enable) true;
|
||||
};
|
||||
|
||||
environment.etc."resolv.conf" = lib.mkIf (!config.services.resolved.enable) {
|
||||
text = lib.concatMapStrings
|
||||
(ns: ''
|
||||
nameserver ${ns}
|
||||
'')
|
||||
config.networking.nameservers;
|
||||
};
|
||||
|
||||
nix = {
|
||||
settings = {
|
||||
auto-optimise-store = true;
|
||||
trusted-public-keys = lib.mkIf (config.networking.hostName != "hydra") [
|
||||
(builtins.readFile ../hosts/hydra/cache-pub.key)
|
||||
];
|
||||
substituters = lib.mkIf (config.networking.hostName != "hydra") (
|
||||
lib.mkBefore [ "https://nix-serve.hq.c3d2.de" ]
|
||||
);
|
||||
};
|
||||
gc = {
|
||||
automatic = true;
|
||||
dates = "06:00";
|
||||
options = "--delete-older-than 21d";
|
||||
randomizedDelaySec = "6h";
|
||||
};
|
||||
registry.c3d2 = {
|
||||
from = {
|
||||
id = "c3d2";
|
||||
type = "indirect";
|
||||
};
|
||||
to = {
|
||||
type = "git";
|
||||
url = "https://gitea.c3d2.de/C3D2/nix-config.git";
|
||||
};
|
||||
};
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
builders-use-substitutes = true
|
||||
'';
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
# Required for deployment
|
||||
enable = true;
|
||||
permitRootLogin = "prohibit-password";
|
||||
};
|
||||
|
||||
sops.age.sshKeyPaths = lib.mkDefault [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
# Network fetchers
|
||||
curl
|
||||
wget
|
||||
git
|
||||
# System monitors
|
||||
htop
|
||||
iotop
|
||||
bmon
|
||||
ripgrep
|
||||
# Terminal managers
|
||||
tmux
|
||||
screen
|
||||
# Editors
|
||||
vim
|
||||
# Pipeview
|
||||
pv
|
||||
# Network debugging
|
||||
tcpdump
|
||||
ethtool
|
||||
mtr
|
||||
];
|
||||
variables = {
|
||||
# TERM = "xterm-256color";
|
||||
};
|
||||
# breaks various package builds
|
||||
noXlibs = lib.mkForce false;
|
||||
};
|
||||
|
||||
programs = {
|
||||
ssh.knownHosts = with builtins;
|
||||
let
|
||||
intersectKeys = intersectAttrs {
|
||||
publicKey = null;
|
||||
publicKeyFile = null;
|
||||
};
|
||||
list = map
|
||||
(name:
|
||||
let
|
||||
host = getAttr name cfg.hosts;
|
||||
sshAttrs = intersectKeys host;
|
||||
in
|
||||
if sshAttrs == { } then
|
||||
null
|
||||
else {
|
||||
inherit name;
|
||||
value =
|
||||
let ip6 = if host.ip6 != null then host.ip6 else toHqPrivateAddress name;
|
||||
in
|
||||
{
|
||||
publicKey = null;
|
||||
publicKeyFile = null;
|
||||
hostNames = [ ip6 "${name}.hq.c3d2.de" "${name}.hq" name ];
|
||||
} // sshAttrs;
|
||||
})
|
||||
(builtins.attrNames cfg.hosts);
|
||||
keyedHosts = filter (x: x.value.publicKey != null || x.value.publicKeyFile != null) list;
|
||||
in
|
||||
listToAttrs keyedHosts;
|
||||
|
||||
vim.defaultEditor = true;
|
||||
};
|
||||
|
||||
services.nginx = lib.mkIf config.services.nginx.enable {
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
time.timeZone = lib.mkDefault "Europe/Berlin";
|
||||
|
||||
# Reboot on hang
|
||||
systemd.watchdog = lib.mkIf (!config.boot.isContainer) {
|
||||
runtimeTime = "15s";
|
||||
rebootTime = "15s";
|
||||
};
|
||||
|
||||
# Defaults for LetsEncrypt
|
||||
security.acme =
|
||||
if options.security.acme ? defaults
|
||||
then {
|
||||
acceptTerms = true;
|
||||
# NixOS>=22.05
|
||||
defaults = {
|
||||
email = cfg.acmeEmail;
|
||||
# letsencrypt staging server with way higher rate limits
|
||||
# server = "https://acme-staging-v02.api.letsencrypt.org/directory";
|
||||
};
|
||||
}
|
||||
else {
|
||||
acceptTerms = true;
|
||||
# TODO: NixOS<=21.05
|
||||
email = cfg.acmeEmail;
|
||||
};
|
||||
zramSwap.enable = true;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue