Merge branch 'master' of ssh://git.fudo.org:2222/fudosys/NixOS
This commit is contained in:
commit
b4081a4f09
|
@ -0,0 +1,7 @@
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./dns.nix
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,330 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.fudo.backplane.dns;
|
||||||
|
|
||||||
|
lisp-pkgs = with pkgs.localLispPackages; [
|
||||||
|
arrows
|
||||||
|
backplane-dns
|
||||||
|
backplane-server
|
||||||
|
cl-sasl
|
||||||
|
cl-xmpp
|
||||||
|
ip-utils
|
||||||
|
|
||||||
|
alexandria
|
||||||
|
babel
|
||||||
|
bordeaux-threads
|
||||||
|
cffi
|
||||||
|
cl-base64
|
||||||
|
cl-json
|
||||||
|
cl-postgres
|
||||||
|
cl-ppcre
|
||||||
|
cl-unicode
|
||||||
|
cl_plus_ssl
|
||||||
|
closer-mop
|
||||||
|
closure-common
|
||||||
|
cxml
|
||||||
|
flexi-streams
|
||||||
|
global-vars
|
||||||
|
introspect-environment
|
||||||
|
ironclad
|
||||||
|
iterate
|
||||||
|
lisp-namespace
|
||||||
|
md5
|
||||||
|
nibbles
|
||||||
|
postmodern
|
||||||
|
puri
|
||||||
|
s-sql
|
||||||
|
split-sequence
|
||||||
|
trivia
|
||||||
|
trivia_dot_balland2006
|
||||||
|
trivia_dot_level0
|
||||||
|
trivia_dot_level1
|
||||||
|
trivia_dot_level2
|
||||||
|
trivia_dot_trivial
|
||||||
|
trivial-cltl2
|
||||||
|
trivial-features
|
||||||
|
trivial-garbage
|
||||||
|
trivial-gray-streams
|
||||||
|
type-i
|
||||||
|
uax-15
|
||||||
|
usocket
|
||||||
|
];
|
||||||
|
|
||||||
|
backup-directory = "/var/lib/fudo/backplane/dns";
|
||||||
|
|
||||||
|
powerdns-home = "/var/lib/powerdns";
|
||||||
|
|
||||||
|
powerdns-conf-dir = "${powerdns-home}/conf.d";
|
||||||
|
|
||||||
|
backplaneOpts = { ... }: {
|
||||||
|
options = {
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Hostname of the backplane jabber server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
role = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Backplane XMPP role name for the DNS server.";
|
||||||
|
default = "service-dns";
|
||||||
|
};
|
||||||
|
|
||||||
|
password-file = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "File containing XMPP password for backplane role.";
|
||||||
|
};
|
||||||
|
|
||||||
|
database = mkOption {
|
||||||
|
type = with types; submodule databaseOpts;
|
||||||
|
description = "Database settings for backplane server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
cl-wrapper-package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = "Common Lisp wrapper package to use.";
|
||||||
|
default = pkgs.lispPackages.clwrapper;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
databaseOpts = { ... }: {
|
||||||
|
options = {
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Hostname or IP of the PostgreSQL server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
database = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Database to use for DNS backplane.";
|
||||||
|
default = "backplane_dns";
|
||||||
|
};
|
||||||
|
|
||||||
|
username = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Database user for DNS backplane.";
|
||||||
|
default = "backplane_dns";
|
||||||
|
};
|
||||||
|
|
||||||
|
password-file = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "File containing password for database user.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.backplane.dns = {
|
||||||
|
enable = mkEnableOption "Enable backplane dynamic DNS server.";
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
description = "Port on which to serve authoritative DNS requests.";
|
||||||
|
default = 53;
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-v4-addresses = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
description = "IPv4 addresses on which to listen for dns requests.";
|
||||||
|
default = [ "0.0.0.0" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-v6-addresses = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
description = "IPv6 addresses on which to listen for dns requests.";
|
||||||
|
example = [
|
||||||
|
"[abcd::1]"
|
||||||
|
];
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
required-services = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
description = "A list of services required before the DNS server can start.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "User as which to run DNS backplane listener service.";
|
||||||
|
default = "backplane-dns";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Group as which to run DNS backplane listener service.";
|
||||||
|
default = "backplane-dns";
|
||||||
|
};
|
||||||
|
|
||||||
|
database = mkOption {
|
||||||
|
type = with types; submodule databaseOpts;
|
||||||
|
description = "Database settings for the DNS server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane = mkOption {
|
||||||
|
type = with types; submodule backplaneOpts;
|
||||||
|
description = "Backplane Jabber settings for the DNS server.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
"${cfg.user}" = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = cfg.group;
|
||||||
|
createHome = true;
|
||||||
|
home = "/var/home/${cfg.user}";
|
||||||
|
};
|
||||||
|
backplane-powerdns = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
"${cfg.group}" = {
|
||||||
|
members = [cfg.user];
|
||||||
|
};
|
||||||
|
backplane-powerdns = {
|
||||||
|
members = [ "backplane-powerdns" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
targets = {
|
||||||
|
backplane-dns = {
|
||||||
|
description = "Fudo DNS backplane services.";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
|
||||||
|
backplane-powerdns = let
|
||||||
|
configDir = pkgs.writeTextDir "pdns.conf" ''
|
||||||
|
local-address=${lib.concatStringsSep ", " cfg.listen-v4-addresses}
|
||||||
|
local-ipv6=${lib.concatStringsSep ", " cfg.listen-v6-addresses}
|
||||||
|
local-port=${toString cfg.port}
|
||||||
|
launch=
|
||||||
|
include-dir=${powerdns-conf-dir}/
|
||||||
|
'';
|
||||||
|
|
||||||
|
psql-user = config.services.postgresql.superUser;
|
||||||
|
|
||||||
|
in {
|
||||||
|
unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)";
|
||||||
|
description = "Backplane PowerDNS name server";
|
||||||
|
requires = [
|
||||||
|
"postgresql.service"
|
||||||
|
"backplane-dns-config-generator.service"
|
||||||
|
"backplane-dns.target"
|
||||||
|
];
|
||||||
|
after = [
|
||||||
|
"network.target"
|
||||||
|
"postgresql.service"
|
||||||
|
];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
path = with pkgs; [ postgresql ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Restart="on-failure";
|
||||||
|
RestartSec="10";
|
||||||
|
StartLimitInterval="0";
|
||||||
|
PrivateDevices=true;
|
||||||
|
# CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT";
|
||||||
|
# NoNewPrivileges=true;
|
||||||
|
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${powerdns-home}";
|
||||||
|
ExecStart = "${pkgs.powerdns}/bin/pdns_server --setuid=backplane-powerdns --setgid=backplane-powerdns --chroot=${powerdns-home} --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}";
|
||||||
|
ProtectSystem="full";
|
||||||
|
# ProtectHome=true;
|
||||||
|
RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-dns-config-generator = {
|
||||||
|
description = "Generate postgres configuration for backplane DNS server.";
|
||||||
|
requiredBy = [ "backplane-powerdns.service" ];
|
||||||
|
requires = cfg.required-services;
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
restartIfChanged = true;
|
||||||
|
partOf = [ "backplane-dns.target" ];
|
||||||
|
|
||||||
|
preStart = ''
|
||||||
|
mkdir -p ${powerdns-conf-dir}
|
||||||
|
chown backplane-powerdns:backplane-powerdns ${powerdns-conf-dir}
|
||||||
|
'';
|
||||||
|
|
||||||
|
# This builds the config in a bash script, to avoid storing the password
|
||||||
|
# in the nix store at any point
|
||||||
|
script = ''
|
||||||
|
if [ ! -d ${powerdns-conf-dir} ]; then
|
||||||
|
mkdir ${powerdns-conf-dir}
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t pdns-XXXXXXXXXX)
|
||||||
|
TMPCONF=$TMPDIR/pdns.local.gpgsql.conf
|
||||||
|
|
||||||
|
if [ ! -f ${cfg.database.password-file} ]; then
|
||||||
|
echo "${cfg.database.password-file} does not exist!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch $TMPCONF
|
||||||
|
chown backplane-powerdns:backplane-powerdns $TMPCONF
|
||||||
|
chmod go-rwx $TMPCONF
|
||||||
|
PASSWORD=$(cat ${cfg.database.password-file})
|
||||||
|
echo "launch+=gpgsql" >> $TMPCONF
|
||||||
|
echo "gpgsql-host=${cfg.database.host}" >> $TMPCONF
|
||||||
|
echo "gpgsql-dbname=${cfg.database.database}" >> $TMPCONF
|
||||||
|
echo "gpgsql-user=${cfg.database.username}" >> $TMPCONF
|
||||||
|
echo "gpgsql-password=$PASSWORD" >> $TMPCONF
|
||||||
|
echo "gpgsql-dnssec=yes" >> $TMPCONF
|
||||||
|
|
||||||
|
mv $TMPCONF ${powerdns-conf-dir}/pdns.local.gpgsql.conf
|
||||||
|
|
||||||
|
rm -rf $TMPDIR
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-dns = {
|
||||||
|
description = "Fudo DNS Backplane Server";
|
||||||
|
restartIfChanged = true;
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.backplane-dns-server}/bin/launch-backplane-dns.sh";
|
||||||
|
Restart = "on-failure";
|
||||||
|
PIDFile = "/run/backplane-dns.$USERNAME.pid";
|
||||||
|
User = cfg.user;
|
||||||
|
Group = cfg.group;
|
||||||
|
};
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
# LD_LIBRARY_PATH = "${pkgs.openssl_1_1.out}/lib";
|
||||||
|
|
||||||
|
FUDO_DNS_BACKPLANE_XMPP_HOSTNAME = cfg.backplane.host;
|
||||||
|
FUDO_DNS_BACKPLANE_XMPP_USERNAME = cfg.backplane.role;
|
||||||
|
FUDO_DNS_BACKPLANE_XMPP_PASSWORD_FILE = cfg.backplane.password-file;
|
||||||
|
FUDO_DNS_BACKPLANE_DATABASE_HOSTNAME = cfg.backplane.database.host;
|
||||||
|
FUDO_DNS_BACKPLANE_DATABASE_NAME = cfg.backplane.database.database;
|
||||||
|
FUDO_DNS_BACKPLANE_DATABASE_USERNAME = cfg.backplane.database.username;
|
||||||
|
FUDO_DNS_BACKPLANE_DATABASE_PASSWORD_FILE = cfg.backplane.database.password-file;
|
||||||
|
|
||||||
|
# CL_SOURCE_REGISTRY = "${pkgs.localLispPackages.backplane-dns}//";
|
||||||
|
|
||||||
|
CL_SOURCE_REGISTRY = lib.concatStringsSep ":" (map (pkg: "${pkg}//")
|
||||||
|
lisp-pkgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
requires = cfg.required-services;
|
||||||
|
partOf = [ "backplane-dns.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.fudo.client.dns;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.client.dns = {
|
||||||
|
enable = mkEnableOption "Enable Fudo DynDNS Client.";
|
||||||
|
|
||||||
|
ipv4 = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Report host external IPv4 address to Fudo DynDNS server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv6 = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Report host external IPv6 address to Fudo DynDNS server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
sshfp = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Report host SSH fingerprints to the Fudo DynDNS server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
domain = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Domain under which this host is registered.";
|
||||||
|
default = "fudo.link";
|
||||||
|
};
|
||||||
|
|
||||||
|
server = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Backplane DNS server to which changes will be reported.";
|
||||||
|
default = "backplane.fudo.org";
|
||||||
|
};
|
||||||
|
|
||||||
|
password-file = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "File containing host password for backplane.";
|
||||||
|
example = "/path/to/secret.passwd";
|
||||||
|
};
|
||||||
|
|
||||||
|
frequency = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Frequency at which to report the local IP(s) to backplane.";
|
||||||
|
default = "*:0/15";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "User as which to run the client script (must have access to password file).";
|
||||||
|
default = "backplane-dns-client";
|
||||||
|
};
|
||||||
|
|
||||||
|
external-interface = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
description = "Interface with which this host communicates with the larger internet.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
# FIXME: take the relevant SSH package
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users.users = {
|
||||||
|
"${cfg.user}" = {
|
||||||
|
isSystemUser = true;
|
||||||
|
createHome = true;
|
||||||
|
home = "/var/home/${cfg.user}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
timers.backplane-dns-client = {
|
||||||
|
enable = true;
|
||||||
|
description = "Report local IP addresses to Fudo backplane.";
|
||||||
|
partOf = [ "backplane-dns-client.service" ];
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
requires = [ "network-online.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = cfg.frequency;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.backplane-dns-client-pw-file = {
|
||||||
|
enable = true;
|
||||||
|
requiredBy = [ "backplane-dns-client.services" ];
|
||||||
|
reloadIfChanged = true;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
chmod 600 ${cfg.password-file}
|
||||||
|
chown ${cfg.user} ${cfg.password-file}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.backplane-dns-client = {
|
||||||
|
enable = true;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
User = cfg.user;
|
||||||
|
};
|
||||||
|
path = [ pkgs.openssh ];
|
||||||
|
reloadIfChanged = true;
|
||||||
|
script = ''
|
||||||
|
${pkgs.backplane-dns-client}/bin/backplane-dns-client ${optionalString cfg.ipv4 "-4"} ${optionalString cfg.ipv6 "-6"} ${optionalString cfg.sshfp "-f"} ${optionalString (cfg.external-interface != null) "--interface=${cfg.external-interface}"} --domain=${cfg.domain} --server=${cfg.server} --password-file=${cfg.password-file}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,8 +5,6 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.dns;
|
cfg = config.fudo.dns;
|
||||||
|
|
||||||
ip = import ../../lib/ip.nix { lib = lib; };
|
|
||||||
|
|
||||||
join-lines = concatStringsSep "\n";
|
join-lines = concatStringsSep "\n";
|
||||||
|
|
||||||
hostOpts = { host, ...}: {
|
hostOpts = { host, ...}: {
|
||||||
|
@ -32,6 +30,19 @@ let
|
||||||
description = ''
|
description = ''
|
||||||
A list of DNS SSHFP records for this host.
|
A list of DNS SSHFP records for this host.
|
||||||
'';
|
'';
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
description = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
description = "Description of this host for a TXT record.";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
rp = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
description = "Responsible person.";
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -71,7 +82,11 @@ let
|
||||||
description = "A map of hostname to { host_attributes }.";
|
description = "A map of hostname to { host_attributes }.";
|
||||||
};
|
};
|
||||||
|
|
||||||
dnssec = mkEnableOption "Enable DNSSEC security for this zone.";
|
dnssec = mkOption {
|
||||||
|
type = bool;
|
||||||
|
description = "Enable DNSSEC security for this zone.";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
mx = mkOption {
|
mx = mkOption {
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
|
@ -125,9 +140,12 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
hostARecords = host: data:
|
hostRecords = host: data:
|
||||||
join-lines ((map (ip: "${host} IN A ${ip}") data.ip-addresses) ++
|
join-lines ((map (ip: "${host} IN A ${ip}") data.ip-addresses) ++
|
||||||
(map (ip: "${host} IN AAAA ${ip}") data.ipv6-addresses));
|
(map (ip: "${host} IN AAAA ${ip}") data.ipv6-addresses) ++
|
||||||
|
(map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints) ++
|
||||||
|
(optional (data.rp != null) "${host} IN RP ${data.rp}") ++
|
||||||
|
(optional (data.description != null) "${host} IN TXT ${data.description}"));
|
||||||
|
|
||||||
makeSrvRecords = protocol: type: records:
|
makeSrvRecords = protocol: type: records:
|
||||||
join-lines (map (record: "_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${toString record.host}.")
|
join-lines (map (record: "_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${toString record.host}.")
|
||||||
|
@ -137,8 +155,6 @@ let
|
||||||
|
|
||||||
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
||||||
|
|
||||||
hostSshFpRecords = host: data: join-lines (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints);
|
|
||||||
|
|
||||||
mxRecords = mxs:
|
mxRecords = mxs:
|
||||||
concatStringsSep "\n"
|
concatStringsSep "\n"
|
||||||
(map (mx: "@ IN MX 10 ${mx}.") mxs);
|
(map (mx: "@ IN MX 10 ${mx}.") mxs);
|
||||||
|
@ -147,9 +163,7 @@ let
|
||||||
optionalString (dmarc-email != null)
|
optionalString (dmarc-email != null)
|
||||||
''_dmarc IN TXT "v=DMARC1;p=quarantine;sp=quarantine;rua=mailto:${dmarc-email};"'';
|
''_dmarc IN TXT "v=DMARC1;p=quarantine;sp=quarantine;rua=mailto:${dmarc-email};"'';
|
||||||
|
|
||||||
nsRecords = ns-hosts:
|
nsRecords = dom: ns-hosts: join-lines (mapAttrsToList (host: _: "@ IN NS ${host}.${dom}.") ns-hosts);
|
||||||
join-lines ((mapAttrsToList (host: _: "@ IN NS ${host}.") ns-hosts) ++
|
|
||||||
(mapAttrsToList (host: ip: "${host} IN A ${ip}") ns-hosts));
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
@ -157,10 +171,21 @@ in {
|
||||||
enable = mkEnableOption "Enable master DNS services.";
|
enable = mkEnableOption "Enable master DNS services.";
|
||||||
|
|
||||||
# FIXME: This should allow for AAAA addresses too...
|
# FIXME: This should allow for AAAA addresses too...
|
||||||
dns-hosts = mkOption {
|
nameservers = mkOption {
|
||||||
type = loaOf str;
|
type = loaOf (submodule hostOpts);
|
||||||
description = "Map of domain nameserver FQDNs to IP.";
|
description = "Map of domain nameserver FQDNs to IP.";
|
||||||
example = { "ns1.domain.com" = "1.1.1.1"; };
|
example = {
|
||||||
|
"ns1.domain.com" = {
|
||||||
|
ip-addresses = [ "1.1.1.1" ];
|
||||||
|
ipv6-addresses = [];
|
||||||
|
description = "my fancy dns server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
identity = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "The identity (CH TXT ID.SERVER) of this host.";
|
||||||
};
|
};
|
||||||
|
|
||||||
domains = mkOption {
|
domains = mkOption {
|
||||||
|
@ -179,7 +204,7 @@ in {
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.nsd = {
|
services.nsd = {
|
||||||
enable = true;
|
enable = true;
|
||||||
identity = "procul.informis.land";
|
identity = cfg.identity;
|
||||||
interfaces = cfg.listen-ips;
|
interfaces = cfg.listen-ips;
|
||||||
zones = mapAttrs' (dom: dom-cfg:
|
zones = mapAttrs' (dom: dom-cfg:
|
||||||
nameValuePair "${dom}." {
|
nameValuePair "${dom}." {
|
||||||
|
@ -202,13 +227,13 @@ in {
|
||||||
|
|
||||||
$TTL 6h
|
$TTL 6h
|
||||||
|
|
||||||
${nsRecords cfg.dns-hosts}
|
${nsRecords dom cfg.nameservers}
|
||||||
|
${join-lines (mapAttrsToList hostRecords cfg.nameservers)}
|
||||||
|
|
||||||
${dmarcRecord dom-cfg.dmarc-report-address}
|
${dmarcRecord dom-cfg.dmarc-report-address}
|
||||||
|
|
||||||
${join-lines (mapAttrsToList makeSrvProtocolRecords dom-cfg.srv-records)}
|
${join-lines (mapAttrsToList makeSrvProtocolRecords dom-cfg.srv-records)}
|
||||||
${join-lines (mapAttrsToList hostARecords dom-cfg.hosts)}
|
${join-lines (mapAttrsToList hostRecords dom-cfg.hosts)}
|
||||||
${join-lines (mapAttrsToList hostSshFpRecords dom-cfg.hosts)}
|
|
||||||
${join-lines (mapAttrsToList cnameRecord dom-cfg.aliases)}
|
${join-lines (mapAttrsToList cnameRecord dom-cfg.aliases)}
|
||||||
${join-lines dom-cfg.extra-dns-records}
|
${join-lines dom-cfg.extra-dns-records}
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -5,9 +5,10 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.local-network;
|
cfg = config.fudo.local-network;
|
||||||
|
|
||||||
join-lines = concatStringsSep "\n";
|
ip = import ../../lib/ip.nix {};
|
||||||
|
dns = import ../../lib/dns.nix {};
|
||||||
|
|
||||||
ip = import ../../lib/ip.nix { lib = lib; };
|
join-lines = concatStringsSep "\n";
|
||||||
|
|
||||||
hostOpts = { hostname, ... }: {
|
hostOpts = { hostname, ... }: {
|
||||||
options = {
|
options = {
|
||||||
|
@ -36,33 +37,6 @@ let
|
||||||
|
|
||||||
traceout = out: builtins.trace out out;
|
traceout = out: builtins.trace out out;
|
||||||
|
|
||||||
srvRecordOpts = with types; {
|
|
||||||
options = {
|
|
||||||
weight = mkOption {
|
|
||||||
type = int;
|
|
||||||
description = "Weight relative to other records.";
|
|
||||||
default = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
priority = mkOption {
|
|
||||||
type = int;
|
|
||||||
description = "Priority to give this record.";
|
|
||||||
default = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = port;
|
|
||||||
description = "Port to use when connecting.";
|
|
||||||
};
|
|
||||||
|
|
||||||
host = mkOption {
|
|
||||||
type = str;
|
|
||||||
description = "Host to contact for this service.";
|
|
||||||
example = "my-host.my-domain.com.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
options.fudo.local-network = {
|
options.fudo.local-network = {
|
||||||
|
@ -144,7 +118,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
srv-records = mkOption {
|
srv-records = mkOption {
|
||||||
type = with types; attrsOf (attrsOf (listOf (submodule srvRecordOpts)));
|
type = dns.srvRecords;
|
||||||
description = "Map of traffic type to srv records.";
|
description = "Map of traffic type to srv records.";
|
||||||
default = {};
|
default = {};
|
||||||
example = {
|
example = {
|
||||||
|
@ -232,12 +206,6 @@ in {
|
||||||
hostSshFpRecords = host: data: join-lines (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints);
|
hostSshFpRecords = host: data: join-lines (map (sshfp: "${host} IN SSHFP ${sshfp}") data.ssh-fingerprints);
|
||||||
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
cnameRecord = alias: host: "${alias} IN CNAME ${host}";
|
||||||
|
|
||||||
makeSrvRecords = protocol: type: records:
|
|
||||||
join-lines (map (record: "_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${record.host}.")
|
|
||||||
records);
|
|
||||||
|
|
||||||
makeSrvProtocolRecords = protocol: types: join-lines (mapAttrsToList (makeSrvRecords protocol) types);
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
enable = true;
|
enable = true;
|
||||||
cacheNetworks = [ cfg.network "localhost" "localnets" ];
|
cacheNetworks = [ cfg.network "localhost" "localnets" ];
|
||||||
|
@ -275,7 +243,7 @@ in {
|
||||||
${join-lines (mapAttrsToList hostSshFpRecords cfg.hosts)}
|
${join-lines (mapAttrsToList hostSshFpRecords cfg.hosts)}
|
||||||
${join-lines (mapAttrsToList cnameRecord cfg.aliases)}
|
${join-lines (mapAttrsToList cnameRecord cfg.aliases)}
|
||||||
${join-lines cfg.extra-dns-records}
|
${join-lines cfg.extra-dns-records}
|
||||||
${join-lines (mapAttrsToList makeSrvProtocolRecords cfg.srv-records)}
|
${dns.srvRecordsToBindZone cfg.srv-records}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
] ++ blockZones;
|
] ++ blockZones;
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.fudo.password;
|
||||||
|
|
||||||
|
genOpts = {
|
||||||
|
options = {
|
||||||
|
file = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Password file in which to store a generated password.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "User to which the file should belong.";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
description = "Group to which the file should belong.";
|
||||||
|
default = "nogroup";
|
||||||
|
};
|
||||||
|
|
||||||
|
restart-services = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
description = "List of services to restart when the password file is generated.";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
generate-passwd-file = file: user: group: pkgs.writeShellScriptBin "generate-passwd-file.sh" ''
|
||||||
|
mkdir -p $(dirname ${file})
|
||||||
|
|
||||||
|
if touch ${file}; then
|
||||||
|
chown ${user}${optionalString (group != null) ":${group}"} ${file}
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
rm ${file}
|
||||||
|
echo "failed to set permissions on ${file}"
|
||||||
|
exit 4
|
||||||
|
fi
|
||||||
|
${pkgs.pwgen}/bin/pwgen 30 1 > ${file}
|
||||||
|
else
|
||||||
|
echo "cannot write to ${file}"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f ${file} ]; then
|
||||||
|
echo "Failed to create file ${file}"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
${if (group != null) then
|
||||||
|
"chmod 640 ${file}"
|
||||||
|
else
|
||||||
|
"chmod 600 ${file}"}
|
||||||
|
|
||||||
|
echo "created password file ${file}"
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
|
||||||
|
restart-script = service-name: ''
|
||||||
|
SYSCTL=${pkgs.systemd}/bin/systemctl
|
||||||
|
JOBTYPE=$(${pkgs.systemd}/bin/systemctl show ${service-name} -p Type)
|
||||||
|
if $SYSCTL is-active --quiet ${service-name} ||
|
||||||
|
[ $JOBTYPE == "Type=simple" ] ||
|
||||||
|
[ $JOBTYPE == "Type=oneshot" ] ; then
|
||||||
|
echo "restarting service ${service-name} because password has changed."
|
||||||
|
$SYSCTL restart ${service-name}
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
filterForRestarts = filterAttrs (name: opts: opts.restart-services != []);
|
||||||
|
|
||||||
|
in {
|
||||||
|
options.fudo.password = {
|
||||||
|
file-generator = mkOption {
|
||||||
|
type = with types; loaOf (submodule genOpts);
|
||||||
|
description = "List of password files to generate.";
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
systemd.targets.fudo-passwords = {
|
||||||
|
description = "Target indicating that all Fudo passwords have been generated.";
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = fold (a: b: a // b) {} (mapAttrsToList (name: opts: {
|
||||||
|
"file-generator-${name}" = {
|
||||||
|
enable = true;
|
||||||
|
partOf = [ "fudo-passwords.target" ];
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
description = "Generate password file for ${name}.";
|
||||||
|
script = "${generate-passwd-file opts.file opts.user opts.group}/bin/generate-passwd-file.sh";
|
||||||
|
reloadIfChanged = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"file-generator-watcher-${name}" = mkIf (! (opts.restart-services == [])) {
|
||||||
|
description = "Restart services upon regenerating password for ${name}";
|
||||||
|
after = [ "file-generator-${name}.service" ];
|
||||||
|
partOf = [ "fudo-passwords.target" ];
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
script = concatStringsSep "\n" (map restart-script opts.restart-services);
|
||||||
|
};
|
||||||
|
}) cfg.file-generator);
|
||||||
|
|
||||||
|
systemd.paths = mapAttrs' (name: opts:
|
||||||
|
nameValuePair "file-generator-watcher-${name}" {
|
||||||
|
partOf = [ "fudo-passwords.target"];
|
||||||
|
pathConfig.PathChanged = opts.file;
|
||||||
|
}) (filterForRestarts cfg.file-generator);
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,23 +2,51 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.fudo.postgresql;
|
cfg = config.fudo.postgresql;
|
||||||
|
|
||||||
|
utils = import ../../lib/utils.nix { inherit lib; };
|
||||||
|
|
||||||
|
join-lines = lib.concatStringsSep "\n";
|
||||||
|
|
||||||
|
userDatabaseOpts = { database, ... }: {
|
||||||
|
options = {
|
||||||
|
access = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Privileges for user on this database.";
|
||||||
|
default = "CONNECT";
|
||||||
|
};
|
||||||
|
|
||||||
|
entity-access = mkOption {
|
||||||
|
type = with types; attrsOf str;
|
||||||
|
description = "A list of entities mapped to the access this user should have.";
|
||||||
|
default = {};
|
||||||
|
example = {
|
||||||
|
"TABLE users" = "SELECT,DELETE";
|
||||||
|
"ALL SEQUENCES IN public" = "SELECT";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
userOpts = { username, ... }: {
|
userOpts = { username, ... }: {
|
||||||
options = {
|
options = {
|
||||||
password = mkOption {
|
password-file = mkOption {
|
||||||
type = with types; nullOr str;
|
type = with types; nullOr str;
|
||||||
description = "The user's (plaintext) password.";
|
description = "A file containing the user's (plaintext) password.";
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
databases = mkOption {
|
databases = mkOption {
|
||||||
type = with types; loaOf str;
|
type = with types; attrsOf (submodule userDatabaseOpts);
|
||||||
description = "Map of databases to which this user has access, to the required perms.";
|
description = "Map of databases to required database/table perms.";
|
||||||
default = {};
|
default = {};
|
||||||
example = {
|
example = {
|
||||||
my_database = "ALL PRIVILEGES";
|
my_database = {
|
||||||
|
access = "ALL PRIVILEGES";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES" = "SELECT";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -34,43 +62,68 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
userDatabaseAccess = user: databases:
|
filterPasswordedUsers = filterAttrs (user: opts: opts.password-file != null);
|
||||||
mapAttrs' (database: perms:
|
|
||||||
nameValuePair "DATABASE ${database}" perms)
|
|
||||||
databases;
|
|
||||||
|
|
||||||
stringJoin = joiner: els:
|
password-setter-script = user: password-file: sql-file: ''
|
||||||
if (length els) == 0 then
|
unset PASSWORD
|
||||||
""
|
if [ ! -f ${password-file} ]; then
|
||||||
else
|
echo "file does not exist: ${password-file}"
|
||||||
foldr(lel: rel: "${lel}${joiner}${rel}") (last els) (init els);
|
exit 1
|
||||||
|
fi
|
||||||
|
PASSWORD=$(cat ${password-file})
|
||||||
|
echo "setting password for user ${user}"
|
||||||
|
echo "ALTER USER ${user} ENCRYPTED PASSWORD '$PASSWORD';" >> ${sql-file}
|
||||||
|
'';
|
||||||
|
|
||||||
|
passwords-setter-script = users:
|
||||||
|
pkgs.writeScriptBin "postgres-set-passwords.sh" ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "usage: $0 output-file.sql"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
OUTPUT_FILE=$1
|
||||||
|
|
||||||
|
if [ ! -f $OUTPUT_FILE ]; then
|
||||||
|
echo "file doesn't exist: $OUTPUT_FILE"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
${join-lines
|
||||||
|
(mapAttrsToList
|
||||||
|
(user: opts: password-setter-script user opts.password-file "$OUTPUT_FILE")
|
||||||
|
(filterPasswordedUsers users))}
|
||||||
|
'';
|
||||||
|
|
||||||
|
userDatabaseAccess = user: databases:
|
||||||
|
mapAttrs' (database: databaseOpts:
|
||||||
|
nameValuePair "DATABASE ${database}" databaseOpts.access)
|
||||||
|
databases;
|
||||||
|
|
||||||
makeEntry = nw:
|
makeEntry = nw:
|
||||||
"host all all ${nw} gss include_realm=0 krb_realm=FUDO.ORG";
|
"host all all ${nw} gss include_realm=0 krb_realm=FUDO.ORG";
|
||||||
|
|
||||||
makeNetworksEntry = networks:
|
makeNetworksEntry = networks: join-lines (map makeEntry networks);
|
||||||
stringJoin "\n" (map makeEntry networks);
|
|
||||||
|
|
||||||
setPasswordSql = username: attrs:
|
|
||||||
"ALTER USER ${username} ENCRYPTED PASSWORD '${attrs.password}';";
|
|
||||||
|
|
||||||
setPasswordsSql = users:
|
|
||||||
(stringJoin "\n"
|
|
||||||
(mapAttrsToList (username: attrs: setPasswordSql username attrs)
|
|
||||||
(filterAttrs (user: attrs: attrs.password != null) users))) + "\n";
|
|
||||||
|
|
||||||
makeLocalUserPasswordEntries = users:
|
makeLocalUserPasswordEntries = users:
|
||||||
stringJoin "\n"
|
join-lines (mapAttrsToList
|
||||||
(mapAttrsToList
|
(user: opts: join-lines
|
||||||
(username: attrs:
|
(map (db: ''
|
||||||
stringJoin "\n"
|
local ${db} ${user} md5
|
||||||
(map (db: ''
|
host ${db} ${user} 127.0.0.1/16 md5
|
||||||
local ${db} ${username} md5
|
host ${db} ${user} ::1/128 md5
|
||||||
host ${db} ${username} 127.0.0.1/16 md5
|
'') (attrNames opts.databases)))
|
||||||
host ${db} ${username} ::1/128 md5
|
(filterPasswordedUsers users));
|
||||||
'') (attrNames attrs.databases)))
|
|
||||||
users);
|
|
||||||
|
|
||||||
|
userTableAccessSql = user: entity: access: "GRANT ${access} ON ${entity} TO ${user};";
|
||||||
|
userDatabaseAccessSql = user: database: dbOpts: ''
|
||||||
|
\c ${database}
|
||||||
|
${join-lines (mapAttrsToList (userTableAccessSql user) dbOpts.entity-access)}
|
||||||
|
'';
|
||||||
|
userAccessSql = user: userOpts: join-lines (mapAttrsToList (userDatabaseAccessSql user) userOpts.databases);
|
||||||
|
usersAccessSql = users: join-lines (mapAttrsToList userAccessSql users);
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
@ -106,8 +159,15 @@ in {
|
||||||
description = "A map of users to user attributes.";
|
description = "A map of users to user attributes.";
|
||||||
example = {
|
example = {
|
||||||
sampleUser = {
|
sampleUser = {
|
||||||
password = "some-password";
|
password-file = "/path/to/password/file";
|
||||||
databases = [ "sample_user_db" ];
|
databases = {
|
||||||
|
some_database = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"TABLE some_table" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default = {};
|
default = {};
|
||||||
|
@ -136,6 +196,13 @@ in {
|
||||||
description = "Users able to access the server via local socket.";
|
description = "Users able to access the server via local socket.";
|
||||||
default = [];
|
default = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
required-services = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
description = "List of services that should run before postgresql.";
|
||||||
|
default = [];
|
||||||
|
example = [ "password-generator.service" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
@ -166,13 +233,6 @@ in {
|
||||||
group = "postgres";
|
group = "postgres";
|
||||||
source = cfg.keytab;
|
source = cfg.keytab;
|
||||||
};
|
};
|
||||||
|
|
||||||
"postgresql/private/user-script.sql" = {
|
|
||||||
mode = "0400";
|
|
||||||
user = "postgres";
|
|
||||||
group = "postgres";
|
|
||||||
text = setPasswordsSql cfg.users;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,15 +247,20 @@ in {
|
||||||
package = pkgs.postgresql_11_gssapi;
|
package = pkgs.postgresql_11_gssapi;
|
||||||
enableTCPIP = true;
|
enableTCPIP = true;
|
||||||
ensureDatabases = mapAttrsToList (name: value: name) cfg.databases;
|
ensureDatabases = mapAttrsToList (name: value: name) cfg.databases;
|
||||||
ensureUsers = mapAttrsToList
|
ensureUsers = ((mapAttrsToList
|
||||||
(username: attrs:
|
(username: attrs:
|
||||||
{
|
{
|
||||||
name = username;
|
name = username;
|
||||||
ensurePermissions =
|
ensurePermissions = userDatabaseAccess username attrs.databases;
|
||||||
#{ "DATABASE ${username}" = "ALL PRIVILEGES"; };
|
|
||||||
(userDatabaseAccess username attrs.databases);
|
|
||||||
})
|
})
|
||||||
cfg.users;
|
cfg.users) ++ (flatten (mapAttrsToList
|
||||||
|
(database: opts:
|
||||||
|
(map (username: {
|
||||||
|
name = username;
|
||||||
|
ensurePermissions = {
|
||||||
|
"DATABASE ${database}" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}) opts.users)) cfg.databases)));
|
||||||
|
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
krb_server_keyfile = '/etc/postgresql/private/postgres.keytab'
|
krb_server_keyfile = '/etc/postgresql/private/postgres.keytab'
|
||||||
|
@ -221,15 +286,54 @@ in {
|
||||||
# local networks
|
# local networks
|
||||||
${makeNetworksEntry cfg.local-networks}
|
${makeNetworksEntry cfg.local-networks}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# initialScript = pkgs.writeText "database-init.sql" ''
|
|
||||||
# ${setPasswordsSql cfg.users}
|
|
||||||
# '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.postgresql.postStart = ''
|
systemd = {
|
||||||
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${pkgs.postgresql}/bin/psql --port ${toString config.services.postgresql.port} -f /etc/postgresql/private/user-script.sql -d postgres
|
|
||||||
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
|
services = {
|
||||||
'';
|
|
||||||
|
postgresql-password-setter = let
|
||||||
|
passwords-script = passwords-setter-script cfg.users;
|
||||||
|
password-wrapper-script = pkgs.writeScriptBin "password-script-wrapper.sh" ''
|
||||||
|
#!${pkgs.bash}/bin/bash
|
||||||
|
TMPDIR=$(${pkgs.coreutils}/bin/mktemp -d -t postgres-XXXXXXXXXX)
|
||||||
|
echo "using temp dir $TMPDIR"
|
||||||
|
PASSWORD_SQL_FILE=$TMPDIR/user-passwords.sql
|
||||||
|
echo "password file $PASSWORD_SQL_FILE"
|
||||||
|
touch $PASSWORD_SQL_FILE
|
||||||
|
chown ${config.services.postgresql.superUser} $PASSWORD_SQL_FILE
|
||||||
|
chmod go-rwx $PASSWORD_SQL_FILE
|
||||||
|
${passwords-script}/bin/postgres-set-passwords.sh $PASSWORD_SQL_FILE
|
||||||
|
echo "executing $PASSWORD_SQL_FILE"
|
||||||
|
${pkgs.postgresql}/bin/psql --port ${toString config.services.postgresql.port} -d postgres -f $PASSWORD_SQL_FILE
|
||||||
|
echo rm $PASSWORD_SQL_FILE
|
||||||
|
echo "Postgresql user passwords set.";
|
||||||
|
exit 0
|
||||||
|
'';
|
||||||
|
|
||||||
|
in {
|
||||||
|
description = "A service to set postgresql user passwords after the server has started.";
|
||||||
|
after = [ "postgresql.service" ] ++ cfg.required-services;
|
||||||
|
requires = [ "postgresql.service" ] ++ cfg.required-services;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = config.services.postgresql.superUser;
|
||||||
|
};
|
||||||
|
script = "${password-wrapper-script}/bin/password-script-wrapper.sh";
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql.postStart = let
|
||||||
|
allow-user-login = user: "ALTER ROLE ${user} WITH LOGIN;";
|
||||||
|
|
||||||
|
extra-settings-sql = pkgs.writeText "settings.sql" ''
|
||||||
|
${concatStringsSep "\n" (map allow-user-login (mapAttrsToList (key: val: key) cfg.users))}
|
||||||
|
${usersAccessSql cfg.users}
|
||||||
|
'';
|
||||||
|
in ''
|
||||||
|
${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} ${pkgs.postgresql}/bin/psql --port ${toString config.services.postgresql.port} -d postgres -f ${extra-settings-sql}
|
||||||
|
${pkgs.coreutils}/bin/chgrp ${cfg.socket-group} ${cfg.socket-directory}/.s.PGSQL*
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,29 +4,44 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.fudo.vpn;
|
cfg = config.fudo.vpn;
|
||||||
|
|
||||||
peerOpts = { peer-name, ... }: {
|
generate-pubkey-pkg = name: privkey:
|
||||||
options = with types; {
|
pkgs.runCommand "wireguard-${name}-pubkey" {
|
||||||
public-key = mkOption {
|
WIREGUARD_PRIVATE_KEY = privkey;
|
||||||
type = str;
|
} ''
|
||||||
description = "Peer public key.";
|
mkdir $out
|
||||||
};
|
PUBKEY=$(echo $WIREGUARD_PRIVATE_KEY | ${pkgs.wireguard-tools}/bin/wg pubkey)
|
||||||
|
echo $PUBKEY > $out/pubkey.key
|
||||||
|
'';
|
||||||
|
|
||||||
allowed-ips = mkOption {
|
generate-client-config = privkey-file: server-pubkey: network: server-ip: listen-port: dns-servers: ''
|
||||||
type = listOf str;
|
[Interface]
|
||||||
description = "List of allowed IP ranges from which this peer can connect.";
|
Address = ${ip.networkMinIp network}
|
||||||
example = [ "10.100.0.0/16" ];
|
PrivateKey = ${fileContents privkey-file}
|
||||||
default = [];
|
ListenPort = ${toString listen-port}
|
||||||
};
|
DNS = ${concatStringsSep ", " dns-servers}
|
||||||
};
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = ${server-pubkey}
|
||||||
|
Endpoint = ${server-ip}:${toString listen-port}
|
||||||
|
AllowedIps = 0.0.0.0/0, ::/0
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
'';
|
||||||
|
|
||||||
|
generate-peer-entry = peer-name: peer-privkey-path: peer-allowed-ips: let
|
||||||
|
peer-pkg = generate-pubkey-pkg "client-${peer-name}" (fileContents peer-privkey-path);
|
||||||
|
pubkey-path = "${peer-pkg}/pubkey.key";
|
||||||
|
in {
|
||||||
|
publicKey = fileContents pubkey-path;
|
||||||
|
allowedIPs = peer-allowed-ips;
|
||||||
};
|
};
|
||||||
|
|
||||||
in {
|
in {
|
||||||
options.fudo.vpn = with types; {
|
options.fudo.vpn = with types; {
|
||||||
enable = mkEnableOption "Enable Fudo VPN";
|
enable = mkEnableOption "Enable Fudo VPN";
|
||||||
|
|
||||||
ips = mkOption {
|
network = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "IP range to assign this interface.";
|
description = "Network range to assign this interface.";
|
||||||
default = "10.100.0.0/16";
|
default = "10.100.0.0/16";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -42,30 +57,68 @@ in {
|
||||||
default = 51820;
|
default = 51820;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dns-servers = mkOption {
|
||||||
|
type = listOf str;
|
||||||
|
description = "A list of dns servers to pass to clients.";
|
||||||
|
default = ["1.1.1.1" "8.8.8.8"];
|
||||||
|
};
|
||||||
|
|
||||||
|
server-ip = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "IP of this WireGuard server.";
|
||||||
|
};
|
||||||
|
|
||||||
peers = mkOption {
|
peers = mkOption {
|
||||||
type = loaOf (submodule peerOpts);
|
type = loaOf str;
|
||||||
description = "A list of peers allowed to connect.";
|
description = "A map of peers to shared private keys.";
|
||||||
default = {};
|
default = {};
|
||||||
example = {
|
example = {
|
||||||
peer0 = {
|
peer0 = "/path/to/priv.key";
|
||||||
public-key = "xyz";
|
|
||||||
allowed-ips = ["10.100.1.0/24"];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
environment.etc = let
|
||||||
|
peer-data = imap1 (i: peer:{
|
||||||
|
name = peer.name;
|
||||||
|
privkey-path = peer.privkey-path;
|
||||||
|
network-range = let
|
||||||
|
base = ip.intToIpv4
|
||||||
|
((ip.ipv4ToInt (ip.getNetworkBase cfg.network)) + (i * 256));
|
||||||
|
in "${base}/24";
|
||||||
|
}) (mapAttrsToList (name: privkey-path: {
|
||||||
|
name = name;
|
||||||
|
privkey-path = privkey-path;
|
||||||
|
}) cfg.peers);
|
||||||
|
|
||||||
|
server-pubkey-pkg = generate-pubkey-pkg "server-pubkey" (fileContents cfg.private-key-file);
|
||||||
|
|
||||||
|
server-pubkey = fileContents "${server-pubkey-pkg}/pubkey.key";
|
||||||
|
|
||||||
|
in listToAttrs
|
||||||
|
(map (peer: nameValuePair "wireguard/clients/${peer.name}.conf" {
|
||||||
|
mode = "0400";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
text = generate-client-config
|
||||||
|
peer.privkey-path
|
||||||
|
server-pubkey
|
||||||
|
peer.network-range
|
||||||
|
cfg.server-ip
|
||||||
|
cfg.listen-port
|
||||||
|
cfg.dns-servers;
|
||||||
|
}) peer-data);
|
||||||
|
|
||||||
networking.wireguard = {
|
networking.wireguard = {
|
||||||
enable = true;
|
enable = true;
|
||||||
interfaces.wgtun0 = {
|
interfaces.wgtun0 = {
|
||||||
generatePrivateKeyFile = false;
|
generatePrivateKeyFile = false;
|
||||||
ips = [ cfg.ips ];
|
ips = [ cfg.network ];
|
||||||
listenPort = cfg.listen-port;
|
listenPort = cfg.listen-port;
|
||||||
peers = mapAttrsToList (peer-name: peer-config: {
|
peers = mapAttrsToList
|
||||||
publicKey = peer-config.public-key;
|
(name: private-key: generate-peer-entry name private-key ["0.0.0.0/0" "::/0"])
|
||||||
allowedIPs = peer-config.allowed-ips;
|
cfg.peers;
|
||||||
}) cfg.peers;
|
|
||||||
privateKeyFile = cfg.private-key-file;
|
privateKeyFile = cfg.private-key-file;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -329,6 +329,7 @@ in {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
description = "Change ownership of the phpfpm socket for webmail once it's started.";
|
description = "Change ownership of the phpfpm socket for webmail once it's started.";
|
||||||
requires = [ "phpfpm-webmail.service" ];
|
requires = [ "phpfpm-webmail.service" ];
|
||||||
|
after = [ "phpfpm.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = ''
|
ExecStart = ''
|
||||||
${pkgs.coreutils}/bin/chown ${webmail-user}:${webmail-group} ${config.services.phpfpm.pools.webmail.socket}
|
${pkgs.coreutils}/bin/chown ${webmail-user}:${webmail-group} ${config.services.phpfpm.pools.webmail.socket}
|
||||||
|
@ -337,8 +338,10 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
nginx = {
|
nginx = {
|
||||||
requires = [ "webmail-init.service" ];
|
requires = [
|
||||||
wantedBy = [ "phpfpm-webmail-socket-perm.service" ];
|
"webmail-init.service"
|
||||||
|
"phpfpm-webmail-socket-perm.service"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,9 @@ with lib;
|
||||||
imports = [
|
imports = [
|
||||||
./fudo/acme-for-hostname.nix
|
./fudo/acme-for-hostname.nix
|
||||||
./fudo/authentication.nix
|
./fudo/authentication.nix
|
||||||
|
./fudo/backplane
|
||||||
./fudo/chat.nix
|
./fudo/chat.nix
|
||||||
|
./fudo/client/dns.nix
|
||||||
./fudo/common.nix
|
./fudo/common.nix
|
||||||
./fudo/dns.nix
|
./fudo/dns.nix
|
||||||
./fudo/garbage-collector.nix
|
./fudo/garbage-collector.nix
|
||||||
|
@ -19,6 +21,7 @@ with lib;
|
||||||
./fudo/minecraft-server.nix
|
./fudo/minecraft-server.nix
|
||||||
./fudo/netinfo-email.nix
|
./fudo/netinfo-email.nix
|
||||||
./fudo/node-exporter.nix
|
./fudo/node-exporter.nix
|
||||||
|
./fudo/password.nix
|
||||||
./fudo/postgres.nix
|
./fudo/postgres.nix
|
||||||
./fudo/prometheus.nix
|
./fudo/prometheus.nix
|
||||||
./fudo/secure-dns-proxy.nix
|
./fudo/secure-dns-proxy.nix
|
||||||
|
|
38
defaults.nix
38
defaults.nix
|
@ -1,12 +1,16 @@
|
||||||
# Ref: https://learnxinyminutes.com/docs/nix/
|
# Ref: https://learnxinyminutes.com/docs/nix/
|
||||||
|
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
let
|
||||||
|
state-version = "20.03";
|
||||||
|
|
||||||
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
./packages/local.nix
|
./packages/local.nix
|
||||||
./config/local.nix
|
./config/local.nix
|
||||||
|
<home-manager/nixos>
|
||||||
];
|
];
|
||||||
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
@ -21,6 +25,7 @@
|
||||||
boot
|
boot
|
||||||
bind
|
bind
|
||||||
binutils
|
binutils
|
||||||
|
# bpytop
|
||||||
btrfs-progs
|
btrfs-progs
|
||||||
bundix
|
bundix
|
||||||
byobu
|
byobu
|
||||||
|
@ -29,6 +34,7 @@
|
||||||
certbot
|
certbot
|
||||||
clang
|
clang
|
||||||
curl
|
curl
|
||||||
|
doomEmacsInit
|
||||||
dpkg
|
dpkg
|
||||||
enca
|
enca
|
||||||
fail2ban
|
fail2ban
|
||||||
|
@ -41,6 +47,7 @@
|
||||||
google-cloud-sdk
|
google-cloud-sdk
|
||||||
guile
|
guile
|
||||||
heimdalFull
|
heimdalFull
|
||||||
|
home-manager
|
||||||
imagemagick
|
imagemagick
|
||||||
ipfs
|
ipfs
|
||||||
iptables
|
iptables
|
||||||
|
@ -56,6 +63,7 @@
|
||||||
lshw
|
lshw
|
||||||
mkpasswd
|
mkpasswd
|
||||||
ncurses5
|
ncurses5
|
||||||
|
nixfmt
|
||||||
nix-index
|
nix-index
|
||||||
nix-prefetch-git
|
nix-prefetch-git
|
||||||
nmap
|
nmap
|
||||||
|
@ -83,7 +91,7 @@
|
||||||
yubikey-personalization
|
yubikey-personalization
|
||||||
];
|
];
|
||||||
|
|
||||||
system.stateVersion = "20.03";
|
system.stateVersion = state-version;
|
||||||
|
|
||||||
system.autoUpgrade.enable = true;
|
system.autoUpgrade.enable = true;
|
||||||
|
|
||||||
|
@ -126,6 +134,9 @@
|
||||||
enableSSHSupport = true;
|
enableSSHSupport = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fish = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
@ -192,6 +203,7 @@
|
||||||
uid = 10000;
|
uid = 10000;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
description = "Niten";
|
description = "Niten";
|
||||||
|
shell = pkgs.fish;
|
||||||
extraGroups = ["wheel" "audio" "video" "disk" "floppy" "lp" "cdrom" "tape" "dialout" "adm" "input" "systemd-journal" "fudosys" "libvirtd"];
|
extraGroups = ["wheel" "audio" "video" "disk" "floppy" "lp" "cdrom" "tape" "dialout" "adm" "input" "systemd-journal" "fudosys" "libvirtd"];
|
||||||
group = "users";
|
group = "users";
|
||||||
home = "/home/niten";
|
home = "/home/niten";
|
||||||
|
@ -218,4 +230,24 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home-manager.users = {
|
||||||
|
niten = import ./users/niten.nix { inherit config pkgs lib; };
|
||||||
|
root = import ./users/root.nix { inherit config pkgs lib; };
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.fudo-environment-init = {
|
||||||
|
enable = true;
|
||||||
|
description = "Fudo common settings.";
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
|
||||||
|
# Careful, this WILL run many times
|
||||||
|
script = ''
|
||||||
|
# Create a directory for system user homedirs if it doesn't already exist
|
||||||
|
if [ ! -d /var/home ]; then
|
||||||
|
mkdir -p /var/home
|
||||||
|
chmod +x /var/home
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
{ config, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
dnssec = true;
|
||||||
|
|
||||||
|
mx = ["mail.fudo.org"];
|
||||||
|
|
||||||
|
hosts = {
|
||||||
|
cisco = {
|
||||||
|
ip-addresses = [ "198.163.150.211" ];
|
||||||
|
description = "\"allbran\" \"converge\"";
|
||||||
|
};
|
||||||
|
cisco-int = {
|
||||||
|
ip-addresses = [ "10.73.77.10" ];
|
||||||
|
description = "\"fruitloops\" \"aironet\"";
|
||||||
|
};
|
||||||
|
cupid = {
|
||||||
|
ip-addresses = [ "208.38.36.100" ];
|
||||||
|
};
|
||||||
|
docker = {
|
||||||
|
ip-addresses = [ "208.81.3.126" ];
|
||||||
|
};
|
||||||
|
france = {
|
||||||
|
ip-addresses = [ "208.81.3.117" ];
|
||||||
|
ssh-fingerprints = [
|
||||||
|
"4 1 c95a198f504a589fc62893a95424b12f0b24732d"
|
||||||
|
"4 2 3e7dad879d6cab7f7fb6769e156d7988d0c01281618d03b793834eea2f09bc96"
|
||||||
|
"1 1 1b6d62dafae9ebc59169dfb4ef828582a5450d94"
|
||||||
|
"1 2 079e7a57873542541095bf3d2f97b7350bb457d027b423a6fb56f7f6aa84ac80"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
frankfurt = {
|
||||||
|
ip-addresses = [ "208.81.3.120" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d200:1:5054:ff:fe8c:9738" ];
|
||||||
|
ssh-fingerprints = [
|
||||||
|
"2 1 4b9e4ed16a6b3fe6d41ed0f5cdeed853cc101e12"
|
||||||
|
"2 2 286ce32326874fe8aa15e3fd60b176b906ebd87306109f7c250d077db4ba85c5"
|
||||||
|
"3 1 3531dfd2f240ce0cd548b748462f78451df3f081"
|
||||||
|
"3 2 338809345ed38eb6808fd468067a74b2a8000fd8cc3bc016b9f977050bf1bba8"
|
||||||
|
"1 1 fb9ba707daa78243f8a8801f024fe790516b99a7"
|
||||||
|
"1 2 407f9692fedbd83449f0daf1cf795258b561a7e9c7e8072577cc84ffc0c84130"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
germany = {
|
||||||
|
ip-addresses = [ "208.81.3.116" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d200:1:78d9:d8ff:fe0f:dd88" ];
|
||||||
|
ssh-fingerprints = [
|
||||||
|
"2 1 5609a728a91d7e52a6060ea7f3a7790005ba5e81"
|
||||||
|
"2 2 520a8eb3b9013837ac3ab4b28254f96b7718f9613e751a20dc488bf7d967b485"
|
||||||
|
"3 1 ee5b49888a36a34e7d4ee0d18626c82a16c2fcdf"
|
||||||
|
"3 2 d5e44cf2d85032638d49c030a9ccbff6638198c354efcb11bf173017d1257f49"
|
||||||
|
"1 1 9915d2515d7acdb38924d8829925113d5ce80b88"
|
||||||
|
"1 2 a7c866306e9661b8b568b2de282367c84065301d6228e58e57e6c4d3d33e3051"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
hanover = {
|
||||||
|
ip-addresses = [ "208.81.1.130" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d100:1:5054:ff:fe61:ac8b" ];
|
||||||
|
};
|
||||||
|
localhost = {
|
||||||
|
ip-addresses = [ "127.0.0.1" ];
|
||||||
|
};
|
||||||
|
lsbb-gba = {
|
||||||
|
ip-addresses = [ "199.101.56.34" ];
|
||||||
|
};
|
||||||
|
lsbb-abg = {
|
||||||
|
ip-addresses = [ "199.101.56.38" ];
|
||||||
|
};
|
||||||
|
lsbb-hwd = {
|
||||||
|
ip-addresses = [ "199.101.56.106" ];
|
||||||
|
};
|
||||||
|
lsbb-hcl = {
|
||||||
|
ip-addresses = [ "199.101.56.110" ];
|
||||||
|
};
|
||||||
|
procul = {
|
||||||
|
ip-addresses = [ "172.86.179.18" ];
|
||||||
|
};
|
||||||
|
prunel = {
|
||||||
|
ip-addresses = [ "208.81.3.123" ];
|
||||||
|
};
|
||||||
|
mbix = {
|
||||||
|
ip-addresses = [ "208.81.7.146" ];
|
||||||
|
};
|
||||||
|
ns3-fudo = {
|
||||||
|
ip-addresses = [ "208.75.74.205" ];
|
||||||
|
};
|
||||||
|
ns3-dair = {
|
||||||
|
ip-addresses = [ "208.75.74.205" ];
|
||||||
|
};
|
||||||
|
ns4-fudo = {
|
||||||
|
ip-addresses = [ "208.75.75.157" ];
|
||||||
|
};
|
||||||
|
ns4-dair = {
|
||||||
|
ip-addresses = [ "208.75.75.157" ];
|
||||||
|
};
|
||||||
|
paris = {
|
||||||
|
ip-addresses = [ "208.81.3.125" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d200:1:5054:ff:fe67:d0c1" ];
|
||||||
|
ssh-fingerprints = [
|
||||||
|
"2 1 9fe9e689a36316831ffafffc22c85913748670a6"
|
||||||
|
"2 2 f2ce57bf470c907604b79b6ef031c928a64a81031e78892fd475bbcf65ae728b"
|
||||||
|
"3 1 5c56e93a20868886ffe76e1fab012989ce8e995f"
|
||||||
|
"3 2 af4f383cb349fc3b2496a0bf0911da3a09f98a6d4d2a3c81bb0fb23a45bde950"
|
||||||
|
"4 1 71a1d35c32b4445b98ce339696f155e1d4c39bd5"
|
||||||
|
"4 2 a9e4810a24bd52082c9bb2b1019a9de7d7983246fecb454dd8d918ac5a11af81"
|
||||||
|
"1 1 18e8dd7cac48f1ac6103ec21c279e339d8690be1"
|
||||||
|
"1 2 72e4aa05c733441da57c464e6540486f5306b6768d784dd97c666e16629d77a0"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
probe = {
|
||||||
|
ip-addresses = [ "208.81.3.119" ];
|
||||||
|
};
|
||||||
|
tours = {
|
||||||
|
ip-addresses = [ "208.81.3.121" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d200:1:5054:ff:fe95:34e5" ];
|
||||||
|
ssh-fingerprints = [
|
||||||
|
"2 2 41cddf1457880c7e86fa3838eabdbbe7cf803f98998ed406319ba3e43036964c"
|
||||||
|
"3 1 89b72a740ef6ef7ad9aaf5fe2178d356cdc7ee5b"
|
||||||
|
"3 2 c39346def56817aaf4c64db5667ccc6aeb400ff1166125fe630b63b5eab0ef29"
|
||||||
|
"4 1 049b1e6ef1d338d35e97baf312d8a371a266b7d1"
|
||||||
|
"4 2 1a889e43148ea1ded9f8bc60799ccf1bc32cb084946c8815abed6cc31f212594"
|
||||||
|
"1 1 bae37560759ec8dba35755473fbb346f9dc4e333"
|
||||||
|
"1 2 3d0d5efe2da329ea19b191f227c3aaad45271c651717ec3315cda131e992bbcf"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
default-host = "208.81.3.117";
|
||||||
|
|
||||||
|
srv-records = {
|
||||||
|
tcp = {
|
||||||
|
domain = [
|
||||||
|
{
|
||||||
|
host = "ns1.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns2.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns3.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns4.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ssh = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 22;
|
||||||
|
}];
|
||||||
|
smtp = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 25;
|
||||||
|
}];
|
||||||
|
submission = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 587;
|
||||||
|
}];
|
||||||
|
kerberos = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 88;
|
||||||
|
}];
|
||||||
|
imaps = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 993;
|
||||||
|
}];
|
||||||
|
ldap = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 389;
|
||||||
|
}];
|
||||||
|
ldaps = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 636;
|
||||||
|
}];
|
||||||
|
pop3s = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 995;
|
||||||
|
}];
|
||||||
|
http = [{
|
||||||
|
host = "wiki.fudo.org";
|
||||||
|
port = 80;
|
||||||
|
}];
|
||||||
|
https = [{
|
||||||
|
host = "wiki.fudo.org";
|
||||||
|
port = 80;
|
||||||
|
}];
|
||||||
|
xmpp-server = [{
|
||||||
|
host = "fudo.im";
|
||||||
|
port = 5269;
|
||||||
|
}];
|
||||||
|
xmpp-client = [{
|
||||||
|
host = "fudo.im";
|
||||||
|
port = 5222;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
udp = {
|
||||||
|
domain = [
|
||||||
|
{
|
||||||
|
host = "ns1.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns2.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns3.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
host = "ns4.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
kerberos = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 88;
|
||||||
|
}];
|
||||||
|
kerberos-master = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 88;
|
||||||
|
}];
|
||||||
|
kpasswd = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 464;
|
||||||
|
}];
|
||||||
|
xmpp-server = [{
|
||||||
|
host = "fudo.im";
|
||||||
|
port = 5269;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
aliases = {
|
||||||
|
pop = "mail.fudo.org.";
|
||||||
|
smtp = "mail.fudo.org.";
|
||||||
|
imap = "mail.fudo.org.";
|
||||||
|
webmail = "france.fudo.org.";
|
||||||
|
|
||||||
|
archiva = "france.fudo.org.";
|
||||||
|
auth = "france.fudo.org.";
|
||||||
|
backplane = "france.fudo.org.";
|
||||||
|
chat = "france.fudo.org.";
|
||||||
|
de = "germany.fudo.org.";
|
||||||
|
fr = "france.fudo.org.";
|
||||||
|
git = "france.fudo.org.";
|
||||||
|
metrics = "france.fudo.org.";
|
||||||
|
minecraft = "france.fudo.org.";
|
||||||
|
monitor = "france.fudo.org.";
|
||||||
|
user = "paris.fudo.org.";
|
||||||
|
u = "user.fudo.org.";
|
||||||
|
w = "www.fudo.org.";
|
||||||
|
ww = "www.fudo.org.";
|
||||||
|
www = "hanover.fudo.org.";
|
||||||
|
wiki = "hanover.fudo.org.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extra-dns-records = [
|
||||||
|
''_kerberos IN TXT "FUDO.ORG"''
|
||||||
|
''@ IN TXT "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
||||||
|
''@ IN SPF "v=spf1 mx ip4:208.81.3.112/28 ip6:2605:e200:d200::1/48 -all"''
|
||||||
|
];
|
||||||
|
|
||||||
|
dmarc-report-address = "dmarc-report@fudo.org";
|
||||||
|
}
|
|
@ -2,11 +2,7 @@
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
reboot-if-necessary = pkgs.writeScriptBin "reboot-if-necessary" ''
|
reboot-if-necessary = pkgs.writeShellScriptBin "reboot-if-necessary" ''
|
||||||
#!${pkgs.stdenv.shell}
|
|
||||||
|
|
||||||
set -ne
|
|
||||||
|
|
||||||
if [ $# -ne 1 ]; then
|
if [ $# -ne 1 ]; then
|
||||||
echo "FAILED: no sync file provided."
|
echo "FAILED: no sync file provided."
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -24,11 +20,7 @@ let
|
||||||
exit 0
|
exit 0
|
||||||
'';
|
'';
|
||||||
|
|
||||||
test-config = pkgs.writeScriptBin "fudo-test-config" ''
|
test-config = pkgs.writeShellScriptBin "fudo-test-config" ''
|
||||||
#!${pkgs.stdenv.shell}
|
|
||||||
|
|
||||||
set -ne
|
|
||||||
|
|
||||||
if [ $# -gt 1 ]; then
|
if [ $# -gt 1 ]; then
|
||||||
echo "usage: $0 [timeout]"
|
echo "usage: $0 [timeout]"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
{ host_ipv4, config }:
|
||||||
|
|
||||||
|
{
|
||||||
|
dnssec = true;
|
||||||
|
|
||||||
|
mx = ["mail.fudo.org"];
|
||||||
|
|
||||||
|
hosts = {
|
||||||
|
forum = {
|
||||||
|
ip-addresses = [ "208.81.3.117" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
default-host = "208.81.3.117";
|
||||||
|
|
||||||
|
srv-records = {
|
||||||
|
tcp = {
|
||||||
|
domain = [{
|
||||||
|
host = "ns1.fudo.org";
|
||||||
|
port = "53";
|
||||||
|
}];
|
||||||
|
ssh = [{
|
||||||
|
host = "france.fudo.org";
|
||||||
|
port = 22;
|
||||||
|
}];
|
||||||
|
submission = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 587;
|
||||||
|
}];
|
||||||
|
kerberos = [{
|
||||||
|
host = "auth.fudo.org";
|
||||||
|
port = 88;
|
||||||
|
}];
|
||||||
|
imaps = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 993;
|
||||||
|
}];
|
||||||
|
pop3s = [{
|
||||||
|
host = "mail.fudo.org";
|
||||||
|
port = 995;
|
||||||
|
}];
|
||||||
|
http = [{
|
||||||
|
host = "forum.selby.ca";
|
||||||
|
port = 80;
|
||||||
|
}];
|
||||||
|
https = [{
|
||||||
|
host = "forum.selby.ca";
|
||||||
|
port = 80;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
udp = {
|
||||||
|
domain = [{
|
||||||
|
host = "auth.fudo.org";
|
||||||
|
port = 53;
|
||||||
|
}];
|
||||||
|
kerberos = [{
|
||||||
|
host = "auth.fudo.org";
|
||||||
|
port = 88;
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
aliases = {
|
||||||
|
pop = "mail.fudo.org.";
|
||||||
|
smtp = "mail.fudo.org.";
|
||||||
|
imap = "mail.fudo.org.";
|
||||||
|
mail = "mail.fudo.org.";
|
||||||
|
ns1 = "ns1.fudo.org.";
|
||||||
|
ns2 = "ns2.fudo.org.";
|
||||||
|
webmail = "france.fudo.org.";
|
||||||
|
forum = "frankfurt.fudo.org.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extra-dns-records = [
|
||||||
|
''_kerberos IN TXT "FUDO.ORG"''
|
||||||
|
''@ IN TXT "v=spf1 mx ip4:${host_ipv4}/29 -all"''
|
||||||
|
''@ IN SPF "v=spf1 mx ip4:${host_ipv4}/29 -all"''
|
||||||
|
];
|
||||||
|
|
||||||
|
dmarc-report-address = "dmarc-report@selby.ca";
|
||||||
|
}
|
|
@ -75,7 +75,8 @@
|
||||||
uid = 10035;
|
uid = 10035;
|
||||||
group = "selby";
|
group = "selby";
|
||||||
common-name = "Ken Selby";
|
common-name = "Ken Selby";
|
||||||
hashed-password = "{SSHA}X8DxUcwH2Fzel5UKbGVNhC5B2vg0Prsc";
|
hashed-password = "{SSHA}wUGV/9dr8inz/HyqSF/OWKxy0DCy5AI3";
|
||||||
|
# hashed-password = "{SSHA}X8DxUcwH2Fzel5UKbGVNhC5B2vg0Prsc";
|
||||||
};
|
};
|
||||||
|
|
||||||
reaper = {
|
reaper = {
|
||||||
|
@ -390,7 +391,8 @@
|
||||||
uid = 10108;
|
uid = 10108;
|
||||||
group = "selby";
|
group = "selby";
|
||||||
common-name = "Lauren Hotel";
|
common-name = "Lauren Hotel";
|
||||||
hashed-password = "{SSHA}DKnhrycmXSu4HKWFPeBXA9xvZ0ytgXIpZA10tg==";
|
hashed-password = "{SSHA}1q/MC5LKROlIT1nDrKrMvcFAXFtcQXIR";
|
||||||
|
# hashed-password = "{SSHA}DKnhrycmXSu4HKWFPeBXA9xvZ0ytgXIpZA10tg==";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Used to send alerts from grafana
|
# Used to send alerts from grafana
|
||||||
|
|
122
hosts/france.nix
122
hosts/france.nix
|
@ -7,7 +7,7 @@ let
|
||||||
mail-hostname = "mail.${domain}";
|
mail-hostname = "mail.${domain}";
|
||||||
host_ipv4 = "208.81.3.117";
|
host_ipv4 = "208.81.3.117";
|
||||||
# Use a special IP for git.fudo.org, since it needs to be SSH-able
|
# Use a special IP for git.fudo.org, since it needs to be SSH-able
|
||||||
git_ipv4 = "208.81.3.126";
|
link_ipv4 = "208.81.3.126";
|
||||||
all-hostnames = [];
|
all-hostnames = [];
|
||||||
|
|
||||||
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
acme-private-key = hostname: "/var/lib/acme/${hostname}/key.pem";
|
||||||
|
@ -32,6 +32,7 @@ in {
|
||||||
../hardware-configuration.nix
|
../hardware-configuration.nix
|
||||||
../defaults.nix
|
../defaults.nix
|
||||||
./france/jabber.nix
|
./france/jabber.nix
|
||||||
|
./france/backplane.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
@ -39,18 +40,10 @@ in {
|
||||||
lxd
|
lxd
|
||||||
multipath-tools
|
multipath-tools
|
||||||
nix-prefetch-docker
|
nix-prefetch-docker
|
||||||
|
powerdns
|
||||||
tshark
|
tshark
|
||||||
];
|
];
|
||||||
|
|
||||||
# services.openssh = {
|
|
||||||
# listenAddresses = [
|
|
||||||
# {
|
|
||||||
# addr = host_ipv4;
|
|
||||||
# port = 22;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# };
|
|
||||||
|
|
||||||
fudo.common = {
|
fudo.common = {
|
||||||
# Sets some server-common settings. See /etc/nixos/fudo/profiles/...
|
# Sets some server-common settings. See /etc/nixos/fudo/profiles/...
|
||||||
profile = "server";
|
profile = "server";
|
||||||
|
@ -122,41 +115,113 @@ in {
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
fudo_git = {
|
fudo_git = {
|
||||||
password = fileContents "/srv/git/secure/db.passwd";
|
password-file = "/srv/git/secure/db.passwd";
|
||||||
databases = {
|
databases = {
|
||||||
fudo_git = "ALL PRIVILEGES";
|
fudo_git = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
grafana = {
|
grafana = {
|
||||||
password = fileContents "/srv/grafana/secure/db.passwd";
|
password-file = "/srv/grafana/secure/db.passwd";
|
||||||
databases = {
|
databases = {
|
||||||
grafana = "ALL PRIVILEGES";
|
grafana = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
mattermost = {
|
mattermost = {
|
||||||
password = fileContents "/srv/mattermost/secure/db.passwd";
|
password-file = "/srv/mattermost/secure/db.passwd";
|
||||||
databases = {
|
databases = {
|
||||||
mattermost = "ALL PRIVILEGES";
|
mattermost = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
webmail = {
|
webmail = {
|
||||||
password = fileContents "/srv/webmail/secure/db.passwd";
|
password-file = "/srv/webmail/secure/db.passwd";
|
||||||
databases = {
|
databases = {
|
||||||
webmail = "ALL PRIVILEGES";
|
webmail = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
niten = {};
|
niten = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
local-users = [
|
local-users = [
|
||||||
|
"niten"
|
||||||
"fudo_git"
|
"fudo_git"
|
||||||
];
|
];
|
||||||
|
|
||||||
databases = {
|
databases = {
|
||||||
fudo_git = ["niten"];
|
fudo_git = {
|
||||||
grafana = ["niten"];
|
users = ["niten"];
|
||||||
mattermost = ["niten"];
|
};
|
||||||
webmail = ["niten"];
|
grafana = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
|
mattermost = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
|
webmail = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fudo.dns = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
identity = "france.fudo.org";
|
||||||
|
|
||||||
|
nameservers = {
|
||||||
|
ns1 = {
|
||||||
|
ip-addresses = [ "208.81.3.117" ];
|
||||||
|
ipv6-addresses = [ "2605:e200:d200:1:5054:ff:fe8c:9738" ];
|
||||||
|
description = "Nameserver 1, france, in Winnipeg, MB, CA";
|
||||||
|
rp = "reaper reaper.rp";
|
||||||
|
};
|
||||||
|
ns2 = {
|
||||||
|
ip-addresses = [ "209.117.102.102" ];
|
||||||
|
ipv6-addresses = [ "2001:470:1f16:40::2" ];
|
||||||
|
description = "Nameserver 2, musashi, in Winnipeg, MB, CA";
|
||||||
|
rp = "reaper reaper.rp";
|
||||||
|
};
|
||||||
|
ns3 = {
|
||||||
|
ip-addresses = [ "104.131.53.95" ];
|
||||||
|
ipv6-addresses = [ "2604:a880:800:10::8:7001" ];
|
||||||
|
description = "Nameserver 3, ns2.henchmman21.net, in New York City, NY, US";
|
||||||
|
rp = "reaper reaper.rp";
|
||||||
|
};
|
||||||
|
ns4 = {
|
||||||
|
ip-addresses = [ "204.42.254.5" ];
|
||||||
|
ipv6-addresses = [ "2001:418:3f4::5" ];
|
||||||
|
description = "Nameserver 4, puck.nether.net, in Chicago, IL, US";
|
||||||
|
rp = "reaper reaper.rp";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
listen-ips = [host_ipv4];
|
||||||
|
|
||||||
|
domains = {
|
||||||
|
"fudo.org" = import ../fudo/fudo.org.nix { inherit config; };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -217,6 +282,15 @@ in {
|
||||||
# TODO: not used yet
|
# TODO: not used yet
|
||||||
fudo.acme.hostnames = all-hostnames;
|
fudo.acme.hostnames = all-hostnames;
|
||||||
|
|
||||||
|
fudo.client.dns = {
|
||||||
|
enable = true;
|
||||||
|
ipv4 = true;
|
||||||
|
ipv6 = true;
|
||||||
|
user = "fudo-client";
|
||||||
|
external-interface = "extif0";
|
||||||
|
password-file = "/srv/client/secure/client.passwd";
|
||||||
|
};
|
||||||
|
|
||||||
fudo.mail-server = import ../fudo/email.nix { inherit config; } // {
|
fudo.mail-server = import ../fudo/email.nix { inherit config; } // {
|
||||||
enableContainer = true;
|
enableContainer = true;
|
||||||
debug = true;
|
debug = true;
|
||||||
|
@ -350,7 +424,7 @@ in {
|
||||||
repository-dir = /srv/git/repo;
|
repository-dir = /srv/git/repo;
|
||||||
state-dir = /srv/git/state;
|
state-dir = /srv/git/state;
|
||||||
ssh = {
|
ssh = {
|
||||||
listen-ip = git_ipv4;
|
listen-ip = link_ipv4;
|
||||||
listen-port = 2222;
|
listen-port = 2222;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -396,7 +470,7 @@ in {
|
||||||
macAddress = "02:6d:e2:e1:ad:ca";
|
macAddress = "02:6d:e2:e1:ad:ca";
|
||||||
ipv4.addresses = [
|
ipv4.addresses = [
|
||||||
{
|
{
|
||||||
address = git_ipv4;
|
address = link_ipv4;
|
||||||
prefixLength = 28;
|
prefixLength = 28;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
|
||||||
|
in {
|
||||||
|
config = {
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
backplane-powerdns = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
backplane-dns = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
backplane-powerdns = {
|
||||||
|
members = [ "backplane-powerdns" ];
|
||||||
|
};
|
||||||
|
backplane-dns = {
|
||||||
|
members = [ "backplane-dns" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fudo = {
|
||||||
|
password.file-generator = {
|
||||||
|
dns_backplane_powerdns = {
|
||||||
|
file = "/srv/backplane/dns/secure/db_powerdns.passwd";
|
||||||
|
user = config.services.postgresql.superUser;
|
||||||
|
group = "backplane-powerdns";
|
||||||
|
restart-services = [
|
||||||
|
"backplane-dns-config-generator.service"
|
||||||
|
"postgresql-password-setter.service"
|
||||||
|
"backplane-powerdns.service"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
dns_backplane_database = {
|
||||||
|
file = "/srv/backplane/dns/secure/db_backplane.passwd";
|
||||||
|
user = config.services.postgresql.superUser;
|
||||||
|
group = "backplane-dns";
|
||||||
|
restart-services = [
|
||||||
|
"backplane-dns.service"
|
||||||
|
"postgresql-password-setter.service"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
postgresql = {
|
||||||
|
enable = true;
|
||||||
|
required-services = [ "fudo-passwords.target" ];
|
||||||
|
|
||||||
|
users = {
|
||||||
|
backplane_powerdns = {
|
||||||
|
password-file = "/srv/backplane/dns/secure/db_powerdns.passwd";
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
access = "CONNECT";
|
||||||
|
# entity-access = {
|
||||||
|
# "ALL TABLES IN SCHEMA public" = "SELECT";
|
||||||
|
# };
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
backplane_dns = {
|
||||||
|
password-file = "/srv/backplane/dns/secure/db_backplane.passwd";
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
databases = {
|
||||||
|
backplane_dns = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane.dns = {
|
||||||
|
enable = true;
|
||||||
|
listen-v4-addresses = [ "208.81.3.126" ];
|
||||||
|
listen-v6-addresses = [ "[2605:e200:d200:1:6d:e2ff:fee1:adca]" ];
|
||||||
|
required-services = [ "fudo-passwords.target" ];
|
||||||
|
user = "backplane-dns";
|
||||||
|
group = "backplane-dns";
|
||||||
|
database = {
|
||||||
|
username = "backplane_powerdns";
|
||||||
|
database = "backplane_dns";
|
||||||
|
# Uses an IP to avoid cyclical dependency...not really relevant, but
|
||||||
|
# whatever
|
||||||
|
host = "127.0.0.1";
|
||||||
|
password-file = "/srv/backplane/dns/secure/db_powerdns.passwd";
|
||||||
|
};
|
||||||
|
backplane = {
|
||||||
|
host = "backplane.fudo.org";
|
||||||
|
role = "service-dns";
|
||||||
|
password-file = "/srv/backplane/dns/secure/backplane.passwd";
|
||||||
|
database = {
|
||||||
|
username = "backplane_dns";
|
||||||
|
database = "backplane_dns";
|
||||||
|
host = "127.0.0.1";
|
||||||
|
password-file = "/srv/backplane/dns/secure/db_backplane.passwd";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,6 +4,9 @@ with lib;
|
||||||
let
|
let
|
||||||
backplane-auth = "/etc/nixos/static/backplane-auth.scm";
|
backplane-auth = "/etc/nixos/static/backplane-auth.scm";
|
||||||
|
|
||||||
|
host-passwd-file = "/srv/jabber/secret/hosts-passwd.scm";
|
||||||
|
service-passwd-file = "/srv/jabber/secret/services-passwd.scm";
|
||||||
|
|
||||||
cert-basedir = "/var/lib/ejabberd/certs";
|
cert-basedir = "/var/lib/ejabberd/certs";
|
||||||
|
|
||||||
target-certs = ["key" "cert" "chain" "fullchain"];
|
target-certs = ["key" "cert" "chain" "fullchain"];
|
||||||
|
@ -50,30 +53,67 @@ in {
|
||||||
security.acme.certs."fudo.im".email = "admin@fudo.org";
|
security.acme.certs."fudo.im".email = "admin@fudo.org";
|
||||||
security.acme.certs."backplane.fudo.org".email = "admin@fudo.org";
|
security.acme.certs."backplane.fudo.org".email = "admin@fudo.org";
|
||||||
|
|
||||||
systemd.services = {
|
systemd = {
|
||||||
ejabberd-generate-certs = {
|
services = {
|
||||||
enable = true;
|
ejabberd-generate-certs = {
|
||||||
description = "Generate required SSL certs for ejabberd.";
|
enable = true;
|
||||||
wantedBy = [ "ejabberd.service" ];
|
description = "Generate required SSL certs for ejabberd.";
|
||||||
after = [
|
wantedBy = [ "ejabberd.service" ];
|
||||||
"acme-backplane.fudo.org.service"
|
after = [
|
||||||
"acme-fudo.im.service"
|
"acme-backplane.fudo.org.service"
|
||||||
];
|
"acme-fudo.im.service"
|
||||||
|
];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${move-server-certs ["fudo.im" "backplane.fudo.org"]}";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStop = remove-server-certs;
|
||||||
|
StandardOutput = "journal";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
serviceConfig = {
|
ejabberd = {
|
||||||
Type = "oneshot";
|
requires = [ "ejabberd-generate-certs.service" ];
|
||||||
ExecStart = "${move-server-certs ["fudo.im" "backplane.fudo.org"]}";
|
environment = {
|
||||||
RemainAfterExit = true;
|
FUDO_HOST_PASSWD_FILE = host-passwd-file;
|
||||||
ExecStop = remove-server-certs;
|
FUDO_SERVICE_PASSWD_FILE = service-passwd-file;
|
||||||
StandardOutput = "journal";
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
ejabberd-hostfile-watcher = {
|
||||||
|
description = "Watch the ejabberd host file and restart if changes occur.";
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
after = [ "ejabberd.service" ];
|
||||||
|
script = ''
|
||||||
|
SYSCTL=${pkgs.systemd}/bin/systemctl
|
||||||
|
if $SYSCTL is-active --quiet ejabberd.service; then
|
||||||
|
echo "restarting ejabberd.service because hostfile has changed."
|
||||||
|
$SYSCTL restart ejabberd.service
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
ejabberd-servicefile-watcher = {
|
||||||
|
description = "Watch the ejabberd service file and restart if changes occur.";
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
after = [ "ejabberd.service" ];
|
||||||
|
script = ''
|
||||||
|
SYSCTL=${pkgs.systemd}/bin/systemctl
|
||||||
|
if $SYSCTL is-active --quiet ejabberd.service; then
|
||||||
|
echo "restarting ejabberd.service because servicefile has changed."
|
||||||
|
$SYSCTL restart ejabberd.service
|
||||||
|
fi
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
ejabberd = {
|
paths = {
|
||||||
requires = [ "ejabberd-generate-certs.service" ];
|
ejabberd-hostfile-watcher = {
|
||||||
environment = {
|
pathConfig.PathChanged = host-passwd-file;
|
||||||
FUDO_HOST_PASSWD_FILE = "/srv/jabber/secret/hosts-passwd.scm";
|
};
|
||||||
FUDO_SERVICE_PASSWD_FILE = "/srv/jabber/secret/services-passwd.scm";
|
|
||||||
|
ejabberd-servicefile-watcher = {
|
||||||
|
pathConfig.PathChanged = service-passwd-file;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
{ lib, config, pkgs, ... }:
|
{ lib, config, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
let
|
let
|
||||||
hostname = "nostromo";
|
hostname = "nostromo";
|
||||||
host-internal-ip = "10.0.0.1";
|
host-internal-ip = "10.0.0.1";
|
||||||
inherit (lib.strings) concatStringsSep;
|
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
dnsproxy
|
||||||
|
google-photos-uploader
|
||||||
|
libguestfs-with-appliance
|
||||||
|
libvirt
|
||||||
|
powerdns
|
||||||
|
virtmanager
|
||||||
|
];
|
||||||
|
|
||||||
boot.kernelModules = [ "kvm-amd" ];
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
|
||||||
boot.loader.grub.enable = true;
|
boot.loader.grub.enable = true;
|
||||||
|
@ -34,7 +43,6 @@ in {
|
||||||
dns-serve-ips = [ host-internal-ip "127.0.0.1" "127.0.1.1" ];
|
dns-serve-ips = [ host-internal-ip "127.0.0.1" "127.0.1.1" ];
|
||||||
# Using a pihole running in docker, see below
|
# Using a pihole running in docker, see below
|
||||||
recursive-resolver = "${host-internal-ip} port 5353";
|
recursive-resolver = "${host-internal-ip} port 5353";
|
||||||
# recursive-resolver = "1.1.1.1";
|
|
||||||
server-ip = host-internal-ip;
|
server-ip = host-internal-ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,11 +51,31 @@ in {
|
||||||
enable = true;
|
enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# systemd.network.networks.eno2 = {
|
||||||
|
# dhcpV6Config = {
|
||||||
|
# IPv6PrefixDelegation = "dhcpv6";
|
||||||
|
# PrefixDelegationHint = 60;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
systemd.network.networks.eno2 = {
|
||||||
|
extraConfig = {
|
||||||
|
IPv6AcceptRA = true;
|
||||||
|
IPv6PrefixDelegation = "dhcpv6";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
hostName = hostname;
|
hostName = hostname;
|
||||||
|
|
||||||
nameservers = [ host-internal-ip ];
|
nameservers = [ host-internal-ip ];
|
||||||
|
|
||||||
|
dhcpcd.extraConfig = ''
|
||||||
|
interface eno2
|
||||||
|
ia_na 1
|
||||||
|
ia_pd 2 eno2/0
|
||||||
|
'';
|
||||||
|
|
||||||
# Create a bridge for VMs to use
|
# Create a bridge for VMs to use
|
||||||
macvlans = {
|
macvlans = {
|
||||||
intif0 = {
|
intif0 = {
|
||||||
|
@ -65,7 +93,9 @@ in {
|
||||||
enp9s0f0.useDHCP = false;
|
enp9s0f0.useDHCP = false;
|
||||||
enp9s0f1.useDHCP = false;
|
enp9s0f1.useDHCP = false;
|
||||||
|
|
||||||
eno2.useDHCP = true;
|
eno2 = {
|
||||||
|
useDHCP = true;
|
||||||
|
};
|
||||||
|
|
||||||
intif0 = {
|
intif0 = {
|
||||||
useDHCP = false;
|
useDHCP = false;
|
||||||
|
@ -86,21 +116,35 @@ in {
|
||||||
nat = {
|
nat = {
|
||||||
enable = true;
|
enable = true;
|
||||||
externalInterface = "eno2";
|
externalInterface = "eno2";
|
||||||
internalInterfaces = ["intif0"];
|
internalInterfaces = [ "intif0" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users = {
|
||||||
|
users = {
|
||||||
|
fudo-client = {
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
groups = {
|
||||||
|
backplane-powerdns = {
|
||||||
|
members = [ "backplane-powerdns" ];
|
||||||
|
};
|
||||||
|
backplane-dns = {
|
||||||
|
members = [ "backplane-dns" ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo = {
|
fudo = {
|
||||||
postgresql = {
|
client.dns = {
|
||||||
enable = true;
|
enable = true;
|
||||||
ssl-private-key = "/srv/nostromo/certs/private/privkey.pem";
|
ipv4 = true;
|
||||||
ssl-certificate = "/srv/nostromo/certs/cert.pem";
|
ipv6 = true;
|
||||||
keytab = "/srv/nostromo/keytabs/postgres.keytab";
|
user = "fudo-client";
|
||||||
|
external-interface = "eno2";
|
||||||
local-networks = [
|
password-file = "/srv/client/secure/client.passwd";
|
||||||
"10.0.0.1/24"
|
|
||||||
"127.0.0.1/8"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
secure-dns-proxy = {
|
secure-dns-proxy = {
|
||||||
|
@ -119,13 +163,6 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
dnsproxy
|
|
||||||
libguestfs-with-appliance
|
|
||||||
libvirt
|
|
||||||
virtmanager
|
|
||||||
];
|
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
docker = {
|
docker = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
@ -166,9 +203,6 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
# HMMMMMMM
|
|
||||||
dhcpd6.enable = false;
|
|
||||||
|
|
||||||
nginx = {
|
nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
@ -193,33 +227,5 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# ceph = {
|
|
||||||
# enable = true;
|
|
||||||
|
|
||||||
# global = {
|
|
||||||
# clusterName = "sea-data";
|
|
||||||
# clusterNetwork = "10.0.10.0/24";
|
|
||||||
# fsid = "d443e192-896d-4102-a60f-f8f0777eb2a3";
|
|
||||||
# monHost = "10.0.10.2";
|
|
||||||
# monInitialMembers = "mon-1";
|
|
||||||
# publicNetwork = "10.0.0.0/22";
|
|
||||||
# };
|
|
||||||
|
|
||||||
# mds = {
|
|
||||||
# enable = true;
|
|
||||||
# daemons = ["srv-2"];
|
|
||||||
# };
|
|
||||||
|
|
||||||
# mgr = {
|
|
||||||
# enable = true;
|
|
||||||
# daemons = ["srv-2"];
|
|
||||||
# };
|
|
||||||
|
|
||||||
# mon = {
|
|
||||||
# enable = true;
|
|
||||||
# daemons = ["srv-2"];
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,6 @@ in {
|
||||||
../informis/users.nix
|
../informis/users.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
multipath-tools
|
|
||||||
];
|
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
hostName = hostname;
|
hostName = hostname;
|
||||||
|
|
||||||
|
@ -110,6 +106,15 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
client.dns = {
|
||||||
|
enable = true;
|
||||||
|
ipv4 = true;
|
||||||
|
ipv6 = true;
|
||||||
|
user = "fudo-client";
|
||||||
|
external-interface = "extif0";
|
||||||
|
password-file = "/srv/client/secure/client.passwd";
|
||||||
|
};
|
||||||
|
|
||||||
# Not all users need access to procul; don't allow LDAP-user access.
|
# Not all users need access to procul; don't allow LDAP-user access.
|
||||||
authentication.enable = false;
|
authentication.enable = false;
|
||||||
|
|
||||||
|
@ -214,15 +219,23 @@ in {
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
gituser = {
|
gituser = {
|
||||||
password = fileContents "/srv/git/secure/db.passwd";
|
password-file = "/srv/git/secure/db.passwd";
|
||||||
databases = {
|
databases = {
|
||||||
git = "ALL PRIVILEGES";
|
git = {
|
||||||
|
access = "CONNECT";
|
||||||
|
entity-access = {
|
||||||
|
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
|
||||||
|
"ALL SEQUENCES IN SCHEMA public" = "SELECT, UPDATE";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
databases = {
|
databases = {
|
||||||
git = ["niten"];
|
git = {
|
||||||
|
users = ["niten"];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -273,22 +286,15 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
fudo.vpn = {
|
fudo.vpn = {
|
||||||
enable = true;
|
# fer some fuckin reason this sets the default gw to the vpn interface
|
||||||
ips = "10.100.0.0/16";
|
enable = false;
|
||||||
|
network = "10.100.0.0/16";
|
||||||
|
server-ip = host_ipv4;
|
||||||
private-key-file = "/srv/wireguard/secure/secret.key";
|
private-key-file = "/srv/wireguard/secure/secret.key";
|
||||||
peers = {
|
peers = {
|
||||||
peter = {
|
peter = "/srv/wireguard/clients/peter.key";
|
||||||
allowed-ips = [ "10.100.1.0/24" ];
|
ken = "/srv/wireguard/clients/ken.key";
|
||||||
public-key = "d1NfRFWRkcKq2gxvqfMy7Oe+JFYf5DjomnsTyisvgB4=";
|
helen = "/srv/wireguard/clients/helen.key";
|
||||||
};
|
|
||||||
ken = {
|
|
||||||
allowed-ips = [ "10.100.2.0/24" ];
|
|
||||||
public-key = "y294rTCK0iSRhA6EIOErPzEuqzJMuYAG4XbHasySMVU=";
|
|
||||||
};
|
|
||||||
helen = {
|
|
||||||
allowed-ips = [ "10.100.3.0/24" ];
|
|
||||||
public-key = "7Hdko6RibhIYdoPLWXGwmElY5vKvZ+rURmqFTDUfC2w=";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {}, ... }:
|
||||||
|
|
||||||
|
with pkgs.lib;
|
||||||
|
let
|
||||||
|
join-lines = concatStringsSep "\n";
|
||||||
|
|
||||||
|
makeSrvRecords = protocol: type: records:
|
||||||
|
join-lines (map (record:
|
||||||
|
"_${type}._${protocol} IN SRV ${toString record.priority} ${toString record.weight} ${toString record.port} ${record.host}.")
|
||||||
|
records);
|
||||||
|
|
||||||
|
makeSrvProtocolRecords = protocol: types: join-lines (mapAttrsToList (makeSrvRecords protocol) types);
|
||||||
|
|
||||||
|
srvRecordOpts = with types; {
|
||||||
|
options = {
|
||||||
|
weight = mkOption {
|
||||||
|
type = int;
|
||||||
|
description = "Weight relative to other records.";
|
||||||
|
default = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
priority = mkOption {
|
||||||
|
type = int;
|
||||||
|
description = "Priority to give this record.";
|
||||||
|
default = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "Port to use when connecting.";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Host to contact for this service.";
|
||||||
|
example = "my-host.my-domain.com.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
srvRecordPair = domain: protocol: type: record: {
|
||||||
|
"_${type}._${protocol}.${domain}" = "${toString record.priority} ${toString record.weight} ${toString record.port} ${record.host}.";
|
||||||
|
};
|
||||||
|
|
||||||
|
in rec {
|
||||||
|
|
||||||
|
srvRecords = with types; attrsOf (attrsOf (listOf (submodule srvRecordOpts)));
|
||||||
|
|
||||||
|
srvRecordsToBindZone = srvRecords: join-lines (mapAttrsToList makeSrvProtocolRecords srvRecords);
|
||||||
|
|
||||||
|
concatMapAttrs = f: attrs: concatMap (x: x) (mapAttrsToList (key: val: f key val) attrs);
|
||||||
|
|
||||||
|
srvRecordsToPairs = domain: srvRecords:
|
||||||
|
listToAttrs
|
||||||
|
(concatMapAttrs (protocol: types:
|
||||||
|
concatMapAttrs (type: records: map (srvRecordPair domain protocol type) records) types)
|
||||||
|
srvRecords);
|
||||||
|
}
|
41
lib/ip.nix
41
lib/ip.nix
|
@ -1,56 +1,63 @@
|
||||||
{ lib }:
|
{ pkgs ? import <nixpkgs> {}, ... }:
|
||||||
|
|
||||||
with lib;
|
with pkgs.lib;
|
||||||
let
|
let
|
||||||
joinString = lib.concatStringsSep;
|
joinString = concatStringsSep;
|
||||||
|
|
||||||
pow = x: e: if (e == 0) then 1 else x * (pow x (e - 1));
|
pow = x: e: if (e == 0) then 1 else x * (pow x (e - 1));
|
||||||
|
|
||||||
in rec {
|
|
||||||
|
|
||||||
generateNBits = n: let
|
generateNBits = n: let
|
||||||
helper = n: c: if (c == n) then pow 2 c else (pow 2 c) + (helper n (c + 1));
|
helper = n: c: if (c == n) then pow 2 c else (pow 2 c) + (helper n (c + 1));
|
||||||
in if (n <= 0) then throw "Can't generate 0 or fewer bits" else helper (n - 1) 0;
|
in if (n <= 0) then throw "Can't generate 0 or fewer bits" else helper (n - 1) 0;
|
||||||
|
|
||||||
|
rightPadBits = int: bits: bitOr int (generateNBits bits);
|
||||||
|
|
||||||
reverseIpv4 = ip: joinString "." (reverseList (splitString "." ip));
|
reverseIpv4 = ip: joinString "." (reverseList (splitString "." ip));
|
||||||
|
|
||||||
intToBinaryList = int: let
|
intToBinaryList = int: let
|
||||||
helper = int: cur: let
|
helper = int: cur: let
|
||||||
curExp = pow 2 cur;
|
curExp = pow 2 cur;
|
||||||
in if (curExp > int) then
|
in if (curExp > int) then
|
||||||
[]
|
[]
|
||||||
else
|
else
|
||||||
[(if ((bitAnd curExp int) > 0) then 1 else 0)] ++ (helper int (cur + 1));
|
[(if ((bitAnd curExp int) > 0) then 1 else 0)] ++ (helper int (cur + 1));
|
||||||
in reverseList (helper int 0);
|
in reverseList (helper int 0);
|
||||||
|
|
||||||
leftShift = int: n: int * (pow 2 n);
|
leftShift = int: n: int * (pow 2 n);
|
||||||
|
|
||||||
rightShift = int: n: int / (pow 2 n);
|
rightShift = int: n: int / (pow 2 n);
|
||||||
|
|
||||||
|
in rec {
|
||||||
|
|
||||||
ipv4ToInt = ip: let
|
ipv4ToInt = ip: let
|
||||||
els = map toInt (reverseList (splitString "." ip));
|
els = map toInt (reverseList (splitString "." ip));
|
||||||
in foldr (a: b: a + b) 0 (imap0 (i: el: (leftShift el (i * 8))) els);
|
in foldr (a: b: a + b) 0 (imap0 (i: el: (leftShift el (i * 8))) els);
|
||||||
|
|
||||||
intToIpv4 = int: joinString "." (map (i: toString (bitAnd (rightShift int (i * 8)) 255)) [ 3 2 1 0 ]);
|
intToIpv4 = int: joinString "." (map (i: toString (bitAnd (rightShift int (i * 8)) 255)) [ 3 2 1 0 ]);
|
||||||
|
|
||||||
rightPadBits = int: bits: bitOr int (generateNBits bits);
|
|
||||||
|
|
||||||
maskFromV32Network = network: let
|
maskFromV32Network = network: let
|
||||||
fullMask = ipv4ToInt "255.255.255.255";
|
fullMask = ipv4ToInt "255.255.255.255";
|
||||||
insignificantBits = 32 - (getNetworkMask network);
|
insignificantBits = 32 - (getNetworkMask network);
|
||||||
in intToIpv4 (leftShift (rightShift fullMask insignificantBits) insignificantBits);
|
in intToIpv4 (leftShift (rightShift fullMask insignificantBits) insignificantBits);
|
||||||
|
|
||||||
getNetworkMask = network: toInt (elemAt (splitString "/" network) 1);
|
|
||||||
|
|
||||||
getNetworkBase = network: let
|
|
||||||
ip = elemAt (splitString "/" network) 0;
|
|
||||||
insignificantBits = 32 - (getNetworkMask network);
|
|
||||||
in intToIpv4 (leftShift (rightShift (ipv4ToInt ip) insignificantBits) insignificantBits);
|
|
||||||
|
|
||||||
networkMinIp = network: intToIpv4 (1 + (ipv4ToInt (getNetworkBase network)));
|
networkMinIp = network: intToIpv4 (1 + (ipv4ToInt (getNetworkBase network)));
|
||||||
|
|
||||||
networkMaxIp = network: intToIpv4 (rightPadBits (ipv4ToInt (getNetworkBase network)) (32 - (getNetworkMask network)));
|
networkMaxIp = network: intToIpv4 (rightPadBits (ipv4ToInt (getNetworkBase network)) (32 - (getNetworkMask network)));
|
||||||
|
|
||||||
# To avoid broadcast IP...
|
# To avoid broadcast IP...
|
||||||
networkMaxButOneIp = network: intToIpv4 ((rightPadBits (ipv4ToInt (getNetworkBase network)) (32 - (getNetworkMask network))) - 1);
|
networkMaxButOneIp = network: intToIpv4 ((rightPadBits (ipv4ToInt (getNetworkBase network)) (32 - (getNetworkMask network))) - 1);
|
||||||
|
|
||||||
|
ipv4OnNetwork = ip: network: let
|
||||||
|
ip-int = ipv4ToInt ip;
|
||||||
|
net-min = networkMinIp network;
|
||||||
|
net-max = networkMaxIp network;
|
||||||
|
in
|
||||||
|
(ip-int >= networkMinIp) && (ip-int <= networkMaxIp);
|
||||||
|
|
||||||
|
getNetworkMask = network: toInt (elemAt (splitString "/" network) 1);
|
||||||
|
|
||||||
|
getNetworkBase = network: let
|
||||||
|
ip = elemAt (splitString "/" network) 0;
|
||||||
|
insignificantBits = 32 - (getNetworkMask network);
|
||||||
|
in intToIpv4 (leftShift (rightShift (ipv4ToInt ip) insignificantBits) insignificantBits);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
{
|
||||||
|
recursiveMergeAttrs = a: b: let
|
||||||
|
commonAttrs = intersectLists (attrNames a) (attrNames b);
|
||||||
|
aAttrs = subtractLists (attrNames a) commonAttrs;
|
||||||
|
bAttrs = subtractLists (attrNames b) commonAttrs;
|
||||||
|
aSide = (filterAttrs (k: v: elem k aAttrs) a);
|
||||||
|
bSide = (filterAttrs (k: v: elem k bAttrs) b);
|
||||||
|
common = (foldr (a: b: a // b) {}
|
||||||
|
(map (k: { ${k} = a.${k} // b.${k}; }) commonAttrs));
|
||||||
|
in aSide // bSide // common;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
{ stdenv, fetchgit, pkgs, bundlerEnv }:
|
||||||
|
|
||||||
|
let
|
||||||
|
url = "https://git.fudo.org/fudo-public/backplane-dns-client.git";
|
||||||
|
version = "0.1";
|
||||||
|
srcdir = ../static/backplane-dns-client;
|
||||||
|
gems = bundlerEnv {
|
||||||
|
name = "backplane-dns-client-env";
|
||||||
|
ruby = pkgs.ruby;
|
||||||
|
gemdir = srcdir;
|
||||||
|
};
|
||||||
|
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
name = "backplane-dns-client-${version}";
|
||||||
|
|
||||||
|
src = srcdir;
|
||||||
|
|
||||||
|
buildInputs = [gems pkgs.ruby];
|
||||||
|
|
||||||
|
phases = ["installPhase"];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out/bin" "$out/lib"
|
||||||
|
|
||||||
|
cp "$src/dns-client.rb" "$out/lib"
|
||||||
|
|
||||||
|
BIN="$out/bin/backplane-dns-client"
|
||||||
|
|
||||||
|
cat > $BIN <<EOF
|
||||||
|
#!${pkgs.bash}/bin/bash -e
|
||||||
|
exec ${gems}/bin/bundle exec ${pkgs.ruby}/bin/ruby $out/lib/dns-client.rb "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x $BIN
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
{ pkgs, localLispPackages, ... }:
|
||||||
|
|
||||||
|
with pkgs.lib;
|
||||||
|
let
|
||||||
|
launcher = pkgs.writeText "launch-backplane-dns.lisp" ''
|
||||||
|
(require :asdf)
|
||||||
|
(asdf:load-system :backplane-dns)
|
||||||
|
(backplane-dns:start-listener-with-env)
|
||||||
|
(loop (sleep 600))
|
||||||
|
'';
|
||||||
|
|
||||||
|
launcherScript = pkgs.writeShellScriptBin "launch-backplane-dns.sh" ''
|
||||||
|
${pkgs.lispPackages.clwrapper}/bin/common-lisp.sh --load ${launcher}
|
||||||
|
'';
|
||||||
|
|
||||||
|
in pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "backplane-dns-server";
|
||||||
|
version = "0.1.0";
|
||||||
|
|
||||||
|
propagatedBuildInputs = with pkgs; [
|
||||||
|
asdf
|
||||||
|
sbcl
|
||||||
|
lispPackages.clwrapper
|
||||||
|
localLispPackages.backplane-dns
|
||||||
|
];
|
||||||
|
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out/bin"
|
||||||
|
cp ${launcherScript}/bin/launch-backplane-dns.sh "$out/bin"
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{ stdenv, fetchgit, pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
url = "https://git.fudo.org/fudo-public/backplane-dns.git";
|
||||||
|
version = "0.1";
|
||||||
|
|
||||||
|
in stdenv.mkDerivation {
|
||||||
|
name = "backplane-dns-${version}";
|
||||||
|
|
||||||
|
src = fetchgit {
|
||||||
|
url = url;
|
||||||
|
rev = "c552394e55816541a9426974c5f8e6f1f83bf195";
|
||||||
|
sha256 = "0r61bwj5a2dvzl41cwdf2pdnhdsmp3kzfyxa5x5hsg67al6s7vi8";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
phases = ["installPhase"];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out/lib/common-lisp/backplane-dns"
|
||||||
|
cp "$src/backplane-dns.asd" "$out/lib/common-lisp/backplane-dns"
|
||||||
|
cp -R $src/*.lisp "$out/lib/common-lisp/backplane-dns"
|
||||||
|
'';
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
baseName = "arrows";
|
||||||
|
packageName = "arrows";
|
||||||
|
description = "Clojure-style arrows for Common Lisp";
|
||||||
|
|
||||||
|
buildSystems = [ "arrows" ];
|
||||||
|
|
||||||
|
deps = [];
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://gitlab.com/Harleqin/arrows.git";
|
||||||
|
rev = "df7cf0067e0132d9697ac8b1a4f1b9c88d4f5382";
|
||||||
|
sha256 = "042k9vkssrqx9nhp14wdzm942zgdxvp35mba0p2syz98i75im2yy";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [ "arrows.asd" ];
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
{ pkgs, backplane-server, arrows, ip-utils, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
baseName = "backplane-dns";
|
||||||
|
packageName = "backplane-dns";
|
||||||
|
description = "XMPP Backplane DNS Server";
|
||||||
|
|
||||||
|
buildSystems = [ "backplane-dns" ];
|
||||||
|
|
||||||
|
deps = with pkgs.lispPackages; [
|
||||||
|
arrows
|
||||||
|
alexandria
|
||||||
|
backplane-server
|
||||||
|
cl-ppcre
|
||||||
|
ip-utils
|
||||||
|
postmodern
|
||||||
|
trivia
|
||||||
|
];
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://git.fudo.org/fudo-public/backplane-dns.git";
|
||||||
|
rev = "d9e13bae165b08976fd025053bb2dde44bb4278d";
|
||||||
|
sha256 = "0b4y75hq5753v8pk47c4pwpyc95igpjl7md7f29jjvqaviys66xh";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [ "backplane-dns.asd" ];
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{ pkgs, lib, arrows, cl-xmpp, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
baseName = "backplane-server";
|
||||||
|
packageName = "backplane-server";
|
||||||
|
description = "XMPP Backplane Server";
|
||||||
|
|
||||||
|
buildSystems = [ "backplane-server" ];
|
||||||
|
|
||||||
|
deps = with pkgs.lispPackages; [
|
||||||
|
alexandria
|
||||||
|
arrows
|
||||||
|
cl-json
|
||||||
|
cl-xmpp
|
||||||
|
];
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://git.fudo.org/fudo-public/backplane-server.git";
|
||||||
|
rev = "665f362ce1a0a22bc10d3bbe95d5a8adec2df653";
|
||||||
|
sha256 = "0lzq0vlqjymcwxbc80x6wp5mij80am12w9fi7abs5wnqcs68lwnf";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [ "backplane-server.asd" ];
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
description = "SASL package for common lisp";
|
||||||
|
baseName = "cl-sasl";
|
||||||
|
packageName = "cl-sasl";
|
||||||
|
|
||||||
|
buildSystems = [ "cl-sasl" ];
|
||||||
|
|
||||||
|
deps = with pkgs.lispPackages; [
|
||||||
|
ironclad
|
||||||
|
];
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "legoscia";
|
||||||
|
repo = "cl-sasl";
|
||||||
|
rev = "64f195c0756cb80fa5961c072b62907be20a7380";
|
||||||
|
sha256 = "0a05q8rls2hn46rbbk6w5km9kqvhsj365zlw6hp32724xy2nd98w";
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [ "cl-sasl.asd" ];
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
{ pkgs, cl-sasl, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
baseName = "cl-xmpp";
|
||||||
|
packageName = "cl-xmpp";
|
||||||
|
description = "XMPP library for Common Lisp";
|
||||||
|
|
||||||
|
buildSystems = [
|
||||||
|
"cl-xmpp"
|
||||||
|
"cl-xmpp-sasl"
|
||||||
|
"cl-xmpp-tls"
|
||||||
|
];
|
||||||
|
|
||||||
|
deps = with pkgs.lispPackages; [
|
||||||
|
cl-base64
|
||||||
|
cl_plus_ssl
|
||||||
|
cl-sasl
|
||||||
|
cxml
|
||||||
|
ironclad
|
||||||
|
usocket
|
||||||
|
];
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "j4yk";
|
||||||
|
repo = "cl-xmpp";
|
||||||
|
rev = "a0f206e583c72d80523bdf108e7d507597555c6d";
|
||||||
|
sha256 = "16qwm7yvwi73q07rsg0i5wrxbv44wm75m3710ph0vf1lzdkrsizk";
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [
|
||||||
|
"cl-xmpp.asd"
|
||||||
|
"cl-xmpp-sasl.asd"
|
||||||
|
"cl-xmpp-tls.asd"
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
arrows = import ./arrows.nix { inherit pkgs; };
|
||||||
|
cl-sasl = import ./cl-sasl.nix { inherit pkgs; };
|
||||||
|
cl-xmpp = import ./cl-xmpp.nix { inherit pkgs cl-sasl; };
|
||||||
|
backplane-dns = import ./backplane-dns.nix {
|
||||||
|
inherit pkgs arrows backplane-server ip-utils;
|
||||||
|
};
|
||||||
|
backplane-server = import ./backplane-server.nix {
|
||||||
|
inherit pkgs lib arrows cl-xmpp;
|
||||||
|
};
|
||||||
|
ip-utils = import ./ip-utils.nix { inherit pkgs; };
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
pkgs.lispPackages.buildLispPackage {
|
||||||
|
baseName = "ip-utils";
|
||||||
|
packageName = "ip-utils";
|
||||||
|
description = "Simple Common Lisp utility functions for working with IPs";
|
||||||
|
|
||||||
|
buildSystems = [ "ip-utils" ];
|
||||||
|
|
||||||
|
deps = with pkgs.lispPackages; [
|
||||||
|
cl-ppcre
|
||||||
|
split-sequence
|
||||||
|
trivia
|
||||||
|
];
|
||||||
|
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://git.fudo.org/fudo-public/ip-utils.git";
|
||||||
|
rev = "bf590d0eeab9496bc47db43c997dfe9f0151163a";
|
||||||
|
sha256 = "19n17pdzyl8j0fw82dr8lrjy6hkcagszm8kbyv8qbv2jl80176hp";
|
||||||
|
fetchSubmodules = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
asdFilesToKeep = [ "ip-utils.asd" ];
|
||||||
|
}
|
|
@ -1,19 +1,25 @@
|
||||||
{ pkgs, ... }:
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
{
|
let unstablePkgs = import <nixos-unstable> { };
|
||||||
|
|
||||||
|
in {
|
||||||
nixpkgs.config.packageOverrides = pkgs: rec {
|
nixpkgs.config.packageOverrides = pkgs: rec {
|
||||||
|
|
||||||
letsencrypt-ca = import ./letsencrypt-ca.nix {
|
letsencrypt-ca = import ./letsencrypt-ca.nix {
|
||||||
stdenv = pkgs.stdenv;
|
stdenv = pkgs.stdenv;
|
||||||
fetchurl = builtins.fetchurl;
|
fetchurl = builtins.fetchurl;
|
||||||
};
|
};
|
||||||
|
|
||||||
minecraft-server_1_15_1 = pkgs.minecraft-server.overrideAttrs (oldAttrs: rec {
|
minecraft-server_1_15_1 = pkgs.minecraft-server.overrideAttrs
|
||||||
version = "1.15.1";
|
(oldAttrs: rec {
|
||||||
src = builtins.fetchurl {
|
version = "1.15.1";
|
||||||
url = "https://launcher.mojang.com/v1/objects/4d1826eebac84847c71a77f9349cc22afd0cf0a1/server.jar";
|
src = builtins.fetchurl {
|
||||||
sha256 = "a0c062686bee5a92d60802ca74d198548481802193a70dda6d5fe7ecb7207993";
|
url =
|
||||||
};
|
"https://launcher.mojang.com/v1/objects/4d1826eebac84847c71a77f9349cc22afd0cf0a1/server.jar";
|
||||||
});
|
sha256 =
|
||||||
|
"a0c062686bee5a92d60802ca74d198548481802193a70dda6d5fe7ecb7207993";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
minecraft-current = pkgs.minecraft.overrideAttrs (oldAttrs: rec {
|
minecraft-current = pkgs.minecraft.overrideAttrs (oldAttrs: rec {
|
||||||
src = builtins.fetchurl {
|
src = builtins.fetchurl {
|
||||||
|
@ -25,26 +31,24 @@
|
||||||
# DON'T LEAVE THE HASH--Nix will think the package hasn't changed
|
# DON'T LEAVE THE HASH--Nix will think the package hasn't changed
|
||||||
minecraft-server_1_16_1 = let
|
minecraft-server_1_16_1 = let
|
||||||
version = "1.16.1";
|
version = "1.16.1";
|
||||||
url = "https://launcher.mojang.com/v1/objects/a412fd69db1f81db3f511c1463fd304675244077/server.jar";
|
url =
|
||||||
|
"https://launcher.mojang.com/v1/objects/a412fd69db1f81db3f511c1463fd304675244077/server.jar";
|
||||||
sha256 = "0nwkdig6yw4cnm2ld78z4j4xzhbm1rwv55vfxz0gzhsbf93xb0i7";
|
sha256 = "0nwkdig6yw4cnm2ld78z4j4xzhbm1rwv55vfxz0gzhsbf93xb0i7";
|
||||||
in (pkgs.minecraft-server.overrideAttrs (oldAttrs: rec {
|
in (pkgs.minecraft-server.overrideAttrs (oldAttrs: rec {
|
||||||
name = "minecraft-server-${version}";
|
name = "minecraft-server-${version}";
|
||||||
inherit version;
|
inherit version;
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl { inherit url sha256; };
|
||||||
inherit url sha256;
|
|
||||||
};
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
minecraft-server_1_16_2 = let
|
minecraft-server_1_16_2 = let
|
||||||
version = "1.16.2";
|
version = "1.16.2";
|
||||||
url = "https://launcher.mojang.com/v1/objects/c5f6fb23c3876461d46ec380421e42b289789530/server.jar";
|
url =
|
||||||
|
"https://launcher.mojang.com/v1/objects/c5f6fb23c3876461d46ec380421e42b289789530/server.jar";
|
||||||
sha256 = "0fbghwrj9b2y9lkn2b17id4ghglwvyvcc8065h582ksfz0zys0i9";
|
sha256 = "0fbghwrj9b2y9lkn2b17id4ghglwvyvcc8065h582ksfz0zys0i9";
|
||||||
in (pkgs.minecraft-server.overrideAttrs (oldAttrs: rec {
|
in (pkgs.minecraft-server.overrideAttrs (oldAttrs: rec {
|
||||||
name = "minecraft-server-${version}";
|
name = "minecraft-server-${version}";
|
||||||
inherit version;
|
inherit version;
|
||||||
src = pkgs.fetchurl {
|
src = pkgs.fetchurl { inherit url sha256; };
|
||||||
inherit url sha256;
|
|
||||||
};
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
postgresql_11_gssapi = pkgs.postgresql_11.overrideAttrs (oldAttrs: rec {
|
postgresql_11_gssapi = pkgs.postgresql_11.overrideAttrs (oldAttrs: rec {
|
||||||
|
@ -58,7 +62,16 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
hll2380dw-cups = import ./hll2380dw-cups.nix {
|
hll2380dw-cups = import ./hll2380dw-cups.nix {
|
||||||
inherit (pkgs) stdenv fetchurl makeWrapper cups dpkg a2ps ghostscript gnugrep gnused coreutils file perl which;
|
inherit (pkgs)
|
||||||
|
stdenv fetchurl makeWrapper cups dpkg a2ps ghostscript gnugrep gnused
|
||||||
|
coreutils file perl which;
|
||||||
|
};
|
||||||
|
|
||||||
|
backplane-dns-client = import ./backplane-dns-client.nix {
|
||||||
|
pkgs = pkgs;
|
||||||
|
stdenv = pkgs.stdenv;
|
||||||
|
fetchgit = pkgs.fetchgit;
|
||||||
|
bundlerEnv = pkgs.bundlerEnv;
|
||||||
};
|
};
|
||||||
|
|
||||||
cl-gemini = import ./cl-gemini.nix {
|
cl-gemini = import ./cl-gemini.nix {
|
||||||
|
@ -71,5 +84,72 @@
|
||||||
fetchgit = pkgs.fetchgit;
|
fetchgit = pkgs.fetchgit;
|
||||||
pkgs = pkgs;
|
pkgs = pkgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
google-photos-uploader = pkgs.buildGoModule rec {
|
||||||
|
pname = "google-photos-uploader";
|
||||||
|
version = "1.6.1";
|
||||||
|
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "int128";
|
||||||
|
repo = "gpup";
|
||||||
|
rev = "${version}";
|
||||||
|
sha256 = "0zdkd5iwkp270p0810dijg25djkzrsdyqiqaqv6rzzgzj5d5pwhm";
|
||||||
|
};
|
||||||
|
|
||||||
|
modSha256 = "15ndc6jq51f9mz1v089416x2lxrifp3wglbxpff8b055jj07hbkw";
|
||||||
|
|
||||||
|
subPackages = [ "." ];
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Google photos uploader, written in Go.";
|
||||||
|
homepage = "https://github.com/int128/gpup";
|
||||||
|
license = licenses.asl20;
|
||||||
|
platforms = platforms.linux ++ platforms.darwin;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
doomEmacsInit = pkgs.writeShellScriptBin "doom-emacs-init.sh" ''
|
||||||
|
DOOMDIR=$HOME/.emacs.d
|
||||||
|
|
||||||
|
function clone_into() {
|
||||||
|
${pkgs.git}/bin/git clone https://github.com/hlissner/doom-emacs.git $1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d "$DOOMDIR" ]; then
|
||||||
|
clone_into $DOOMDIR
|
||||||
|
$DOOMDIR/bin/doom -y install
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f $DOOMDIR/bin/doom ]; then
|
||||||
|
# legacy...move to a backup
|
||||||
|
mv $HOME/.emacs.d $HOME/.emacs.d.bak
|
||||||
|
mv $HOME/.emacs $HOME/.emacs
|
||||||
|
clone_into $DOOMDIR
|
||||||
|
$DOOMDIR/bin/doom -y install
|
||||||
|
fi
|
||||||
|
|
||||||
|
$DOOMDIR/bin/doom sync
|
||||||
|
|
||||||
|
#if ${pkgs.emacs}/bin/emacsclient -ca false -e '(delete-frame)'; then
|
||||||
|
# # emacs is running
|
||||||
|
# ${pkgs.emacs}/bin/emacsclient -e '(doom/reload)'
|
||||||
|
#fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
localLispPackages = (import ./lisp {
|
||||||
|
inherit lib;
|
||||||
|
pkgs = unstablePkgs;
|
||||||
|
}) // unstablePkgs.lispPackages;
|
||||||
|
|
||||||
|
backplane-dns-server = import ./backplane-dns-server.nix {
|
||||||
|
inherit localLispPackages;
|
||||||
|
pkgs = unstablePkgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
doom-emacs-config = pkgs.fetchgit {
|
||||||
|
url = "https://git.fudo.org/niten/doom-emacs.git";
|
||||||
|
rev = "ed65ca4881d0cc3cfe308f5fc66ccbf15f560043";
|
||||||
|
sha256 = "17z4scl4p84hin6yzx69a707s5ibjk3jrxszy07cg8zijrg1744a";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gem "xmpp4r"
|
|
@ -0,0 +1,13 @@
|
||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
xmpp4r (0.5.6)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
xmpp4r
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
1.17.2
|
|
@ -0,0 +1,295 @@
|
||||||
|
|
||||||
|
require "ipaddr"
|
||||||
|
require "socket"
|
||||||
|
require "optparse"
|
||||||
|
require "json"
|
||||||
|
require "securerandom"
|
||||||
|
|
||||||
|
require "xmpp4r"
|
||||||
|
|
||||||
|
puts ARGV
|
||||||
|
|
||||||
|
options = {}
|
||||||
|
OptionParser.new do |opts|
|
||||||
|
opts.banner = "usage: ${$0} [opts]"
|
||||||
|
|
||||||
|
opts.on("-i", "--interface=INTERFACE",
|
||||||
|
"Publicly-accessible interface") do |interface|
|
||||||
|
options[:interface] = interface
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-d", "--domain=DOMAIN",
|
||||||
|
"Domain on which we wish to set the new ip") do |domain|
|
||||||
|
options[:domain] = domain
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-s", "--server=SERVER",
|
||||||
|
"Backplane DNS XMPP server") do |server|
|
||||||
|
options[:server] = server
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-p", "--password-file=/path/to/file",
|
||||||
|
"File containing password for XMPP server") do |pw_file|
|
||||||
|
options[:pw_file] = pw_file
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-4", "--ipv4",
|
||||||
|
"Check for a public IPv4 and register with the backplane.") do
|
||||||
|
options[:ipv4] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-6", "--ipv6",
|
||||||
|
"Check for a public IPv6 and register with the backplane.") do
|
||||||
|
options[:ipv6] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on("-f", "--sshfp",
|
||||||
|
"Register host SSH key fingerprints with the backplane.") do
|
||||||
|
options[:sshfp] = true
|
||||||
|
end
|
||||||
|
end.parse!
|
||||||
|
|
||||||
|
def error(msg)
|
||||||
|
puts msg
|
||||||
|
throw msg
|
||||||
|
end
|
||||||
|
|
||||||
|
error("domain is required") if not options[:domain]
|
||||||
|
error("server is required") if not options[:server]
|
||||||
|
error("password file is required") if not options[:pw_file]
|
||||||
|
error("at least one of -4 or -6 required") if not (options[:ipv4] or options[:ipv6])
|
||||||
|
|
||||||
|
if not File::readable?(options[:pw_file])
|
||||||
|
error("file does not exist or is not readable")
|
||||||
|
end
|
||||||
|
password = File::open(options[:pw_file]) { |f| f.gets.strip }
|
||||||
|
|
||||||
|
class XMPPClient
|
||||||
|
def initialize(domain, hostname, server, password)
|
||||||
|
@jid = "host-#{hostname}@#{server}"
|
||||||
|
@service_jid = "service-dns@#{server}"
|
||||||
|
@server = server
|
||||||
|
@domain = domain
|
||||||
|
@password = password
|
||||||
|
@responses = Queue.new
|
||||||
|
@responses_lock = Mutex.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect
|
||||||
|
disconnect if connected?
|
||||||
|
@client = Jabber::Client::new(@jid)
|
||||||
|
@client.connect # will use SRV records
|
||||||
|
error("failed to initialize TLS connection") if not @client.is_tls?
|
||||||
|
@client.auth(@password)
|
||||||
|
register_response_callback
|
||||||
|
end
|
||||||
|
|
||||||
|
def connected?
|
||||||
|
@client ||= nil
|
||||||
|
@client.respond_to?(:is_connected?) and @client.is_connected?
|
||||||
|
end
|
||||||
|
|
||||||
|
def disconnect
|
||||||
|
if @client.respond_to?(:is_connected?) && @client.is_connected?
|
||||||
|
begin
|
||||||
|
@client.close
|
||||||
|
rescue Errno::EPIPE, IOError => e
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@client = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def send(msg_content)
|
||||||
|
msg_id = SecureRandom::uuid
|
||||||
|
encoded_payload = payload(msg_content, msg_id).to_json
|
||||||
|
puts "payload: #{encoded_payload}"
|
||||||
|
msg = Jabber::Message.new(@service_jid, encoded_payload)
|
||||||
|
msg.type = :chat
|
||||||
|
@client.send(msg)
|
||||||
|
response = receive_response(msg_id)
|
||||||
|
puts "response: #{response}"
|
||||||
|
response and response["status"] == "OK"
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_ip(ip)
|
||||||
|
send(ip_payload(ip))
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_sshfp(fps)
|
||||||
|
send(sshfp_payload(fps))
|
||||||
|
end
|
||||||
|
|
||||||
|
def payload(req, msg_id)
|
||||||
|
{
|
||||||
|
version: 1,
|
||||||
|
service: :dns,
|
||||||
|
msgid: msg_id,
|
||||||
|
payload: req
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def ip_payload(ip)
|
||||||
|
{
|
||||||
|
request: ip.ipv4? ? :change_ipv4 : :change_ipv6,
|
||||||
|
domain: @domain,
|
||||||
|
ip: ip.to_s
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def sshfp_payload(fp)
|
||||||
|
{
|
||||||
|
request: :change_sshfp,
|
||||||
|
domain: @domain,
|
||||||
|
sshfp: fp
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_response_callback
|
||||||
|
@client.add_message_callback do |msg|
|
||||||
|
enqueue_message(JSON.parse(msg.body))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def enqueue_message(msg)
|
||||||
|
@responses << msg
|
||||||
|
end
|
||||||
|
|
||||||
|
def receive_response(msg_id)
|
||||||
|
msg = @responses.pop
|
||||||
|
return msg if (msg and (msg["msgid"] == msg_id.to_s))
|
||||||
|
raise "failed to receive message: #{msg}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RESERVED_V4_NETWORKS = [
|
||||||
|
"0.0.0.0/8",
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"100.64.0.0/10",
|
||||||
|
"127.0.0.0/8",
|
||||||
|
"169.254.0.0/16",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.0.0.0/24",
|
||||||
|
"192.0.2.0/24",
|
||||||
|
"192.88.99.0/24",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"198.18.0.0/15",
|
||||||
|
"198.51.100.0/24",
|
||||||
|
"203.0.113.0/24",
|
||||||
|
"224.0.0.0/4",
|
||||||
|
"240.0.0.0/4",
|
||||||
|
"255.255.255.255/32"
|
||||||
|
].map { |ip| IPAddr.new(ip) }
|
||||||
|
|
||||||
|
def public_ip?(ip)
|
||||||
|
if (ip.ipv4?)
|
||||||
|
not RESERVED_V4_NETWORKS.any? { |network| network.include? ip }
|
||||||
|
elsif (ip.ipv6?)
|
||||||
|
not (ip.link_local? or ip.loopback? or ip.private?)
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ipaddr(addrinfo)
|
||||||
|
if addrinfo.ipv4?
|
||||||
|
IPAddr.new addrinfo.ip_address
|
||||||
|
else
|
||||||
|
IPAddr.new(addrinfo.ip_address.split("%")[0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def local_addresses
|
||||||
|
Socket::ip_address_list.map do |addrinfo|
|
||||||
|
to_ipaddr(addrinfo)
|
||||||
|
end.select { |ip| public_ip?(ip) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def interface_addresses(interface)
|
||||||
|
Socket::getifaddrs.select do |ifaddr|
|
||||||
|
ifaddr.name == interface
|
||||||
|
end.select do |ifaddr|
|
||||||
|
ifaddr.addr.ip? and (ifaddr.flags & Socket::IFF_MULTICAST != 0)
|
||||||
|
end.map do |ifaddr|
|
||||||
|
to_ipaddr(ifaddr.addr)
|
||||||
|
end.filter do |ip|
|
||||||
|
public_ip? ip
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def host_sshfp
|
||||||
|
keys = `ssh-keygen -r hostname`.split("\n").map do |k|
|
||||||
|
k.match(/[0-9] [0-9] [a-fA-F0-9]{32,64}$/)[0]
|
||||||
|
end
|
||||||
|
keys.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def hostname
|
||||||
|
Socket.gethostname.split(".").first
|
||||||
|
end
|
||||||
|
|
||||||
|
client = XMPPClient::new(options[:domain],
|
||||||
|
hostname,
|
||||||
|
options[:server],
|
||||||
|
password)
|
||||||
|
|
||||||
|
success = true
|
||||||
|
|
||||||
|
begin
|
||||||
|
client.connect
|
||||||
|
|
||||||
|
addrs = if options[:interface]
|
||||||
|
interface_addresses(options[:interface])
|
||||||
|
else
|
||||||
|
local_addresses
|
||||||
|
end
|
||||||
|
|
||||||
|
if options[:ipv4]
|
||||||
|
ipv4 = addrs.find { |ip| ip.ipv4? }
|
||||||
|
if ipv4
|
||||||
|
puts "#{options[:server]}: #{hostname}.#{options[:domain]} IN A => #{ipv4.to_s}"
|
||||||
|
if client.send_ip(ipv4)
|
||||||
|
puts "OK"
|
||||||
|
else
|
||||||
|
puts "ERROR"
|
||||||
|
success = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "#{options[:server]}: no valid public IPv4 found on the local host"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if options[:ipv6]
|
||||||
|
ipv6 = addrs.find { |ip| ip.ipv6? }
|
||||||
|
if ipv6
|
||||||
|
puts "#{options[:server]}: #{hostname}.#{options[:domain]} IN AAAA => #{ipv6.to_s}"
|
||||||
|
if client.send_ip(ipv6)
|
||||||
|
puts "OK"
|
||||||
|
else
|
||||||
|
puts "ERROR"
|
||||||
|
success = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "#{options[:server]}: no valid public IPv6 found on the local host"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if options[:sshfp]
|
||||||
|
fps = host_sshfp
|
||||||
|
if not fps.empty?
|
||||||
|
puts "#{options[:server]}: #{hostname}.#{options[:domain]} IN SSHFP => #{fps}"
|
||||||
|
if client.send_sshfp(fps)
|
||||||
|
puts "OK"
|
||||||
|
else
|
||||||
|
puts "ERROR"
|
||||||
|
success = false
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "#{options[:server]}: no valid sshfps found"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
client.disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
exit success ? 0 : 1
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
xmpp4r = {
|
||||||
|
groups = ["default"];
|
||||||
|
platforms = [];
|
||||||
|
source = {
|
||||||
|
remotes = ["https://rubygems.org"];
|
||||||
|
sha256 = "15ls2yqjvflxrc8chv5pcdh2p1p9fjsky74yc8y7wvw90wz0izrb";
|
||||||
|
type = "gem";
|
||||||
|
};
|
||||||
|
version = "0.5.6";
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
name = "Niten";
|
||||||
|
email = "niten@fudo.org";
|
||||||
|
|
||||||
|
in {
|
||||||
|
programs = {
|
||||||
|
git = {
|
||||||
|
enable = true;
|
||||||
|
userName = name;
|
||||||
|
userEmail = email;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
xresources.properties = {
|
||||||
|
"Xft.antialias" = 1;
|
||||||
|
"Xft.autohint" = 0;
|
||||||
|
"Xft.dpi" = 192;
|
||||||
|
"Xft.hinting" = 1;
|
||||||
|
"Xft.hintstyle" = "hintfull";
|
||||||
|
"Xft.lcdfilter" = "lcddefault";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gpg-agent.enable = true;
|
||||||
|
|
||||||
|
# services.redshift = {
|
||||||
|
# enable = true;
|
||||||
|
# latitude = "51.0";
|
||||||
|
# longitude = "47.0";
|
||||||
|
# brightness.day = "1";
|
||||||
|
# brightness.night = "0.5";
|
||||||
|
# tray = true;
|
||||||
|
# };
|
||||||
|
|
||||||
|
home.file = {
|
||||||
|
".doom.d" = {
|
||||||
|
source = pkgs.doom-emacs-config;
|
||||||
|
recursive = true;
|
||||||
|
onChange = "${pkgs.doomEmacsInit}/bin/doom-emacs-init.sh";
|
||||||
|
};
|
||||||
|
|
||||||
|
".k5login" = {
|
||||||
|
source = pkgs.writeText "niten-k5login" ''
|
||||||
|
niten@FUDO.ORG
|
||||||
|
niten/root@FUDO.ORG
|
||||||
|
niten@INFORMIS.LAND
|
||||||
|
niten/root@INFORMIS.LAND
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
name = "Root";
|
||||||
|
email = "root@fudo.org";
|
||||||
|
|
||||||
|
in {
|
||||||
|
programs = {
|
||||||
|
git = {
|
||||||
|
enable = true;
|
||||||
|
userName = name;
|
||||||
|
userEmail = email;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gpg-agent.enable = true;
|
||||||
|
|
||||||
|
home.file = {
|
||||||
|
".doom.d" = {
|
||||||
|
source = pkgs.doom-emacs-config;
|
||||||
|
recursive = true;
|
||||||
|
onChange = "${pkgs.doomEmacsInit}/bin/doom-emacs-init.sh";
|
||||||
|
};
|
||||||
|
|
||||||
|
".k5login" = {
|
||||||
|
source = pkgs.writeText "niten-k5login" ''
|
||||||
|
niten@FUDO.ORG
|
||||||
|
niten/root@FUDO.ORG
|
||||||
|
niten@INFORMIS.LAND
|
||||||
|
niten/root@INFORMIS.LAND
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue