# 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 c3d2.users 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 c3d2.hosts to /etc/hosts. ''; }; mergeNncpSettings = mkEnableOption '' Whether to merge c3d2.nncp.<…>.nncp into programs.nncp.settings. ''; k-ot.enable = mkEnableOption '' Add k-ot user to this machine. Anyone with an SSH key listed in c3d2.users 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 c3d2.users. ''; }; }; 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; }; }; }; }