nix-config/modules/c3d2.nix

264 lines
7.4 KiB
Nix

# This module defines options for use by all C3D2 machines.
{ options, config, lib, pkgs, ... }:
let
cfg = config.c3d2;
neighMod = with lib; types.submodule {
options = {
addrs = mkOption {
type = with types; attrsOf str;
default = { };
};
via = mkOption
{
type = with types; listOf str;
default = [ ];
};
} // (with builtins; let value = mkOption { type = types.str; }; in
listToAttrs (map (name: { inherit name value; }) [ "exchpub" "id" "noisepub" "signpub" ]));
};
in
{
options.c3d2 = with lib;
with lib.types; {
acmeEmail = mkOption {
type = 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 = bool;
default = cfg.isInHq;
defaultText = literalExample "config.c3d2.isInHq";
};
mergeHostsFile = mkOption {
type = 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 = 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 = [ ];
};
};
});
};
};
config =
let
adminKeys = (with builtins; lib.lists.flatten (
map
(getAttr "sshKeys")
(attrValues cfg.users)
));
in
{
networking.hosts = lib.mkIf cfg.mergeHostsFile
((
lib.attrsets.mapAttrs' (n: v: { name = v.ip4; value = [ "${n}.c3d2" ]; })
(lib.attrsets.filterAttrs (n: v: v.ip4 != null) cfg.hosts)
) // (
lib.attrsets.mapAttrs' (n: v: { name = v.ip6; value = [ "${n}.c3d2" ]; })
(lib.attrsets.filterAttrs (n: v: v.ip6 != null) cfg.hosts)
));
programs = lib.optionalAttrs (options.programs ? nncp) {
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;
extraGroups = [
"audio"
"video"
"wheel"
];
password = "k-otk-ot";
openssh.authorizedKeys.keys = adminKeys;
};
root.openssh.authorizedKeys.keys = lib.mkIf cfg.allUsersCanSshRoot adminKeys;
};
};
services.vector = lib.mkIf config.c3d2.hq.journalToMqtt {
enable = true;
journaldAccess = true;
settings = {
sources.journal = {
type = "journald";
current_boot_only = true;
};
sinks.mqtt = {
inputs = ["journal"];
type = "mqtt";
host = "broker.serv.zentralwerk.org";
# port = 8883;
user = "SECRET[mqtt.user]";
password = "SECRET[mqtt.password]";
client_id = "vector-${config.networking.hostName}";
encoding.codec = "json";
topic = "journal/{{ host }}/{{ _SYSTEMD_UNIT }}/{{ PRIORITY }}";
# tls.enabled = true;
# tls.ca_file = "/etc/ssl/certs/ca-certificates.crt";
};
secret.mqtt =
let
catSecrets = with pkgs; writeScript "cat-vector-secrets" ''
#!${runtimeShell} -e
echo '{'
COMMA=n
for F in $@; do
if [ $COMMA = y ]; then
echo ' ,'
else
COMMA=y
fi
echo ' "'$(basename $F)'": {"value": "'$(cat $F)'", "error": null }'
done
echo '}'
'';
in {
type = "exec";
command = [
catSecrets
config.sops.secrets."mqtt/user".path
config.sops.secrets."mqtt/password".path
];
};
};
};
sops.secrets = lib.mkIf config.c3d2.hq.journalToMqtt {
"mqtt/user" = {
sopsFile = ../config/mqtt.yaml;
owner = config.systemd.services.vector.serviceConfig.User;
};
"mqtt/password" = {
sopsFile = ../config/mqtt.yaml;
owner = config.systemd.services.vector.serviceConfig.User;
};
};
};
}