hswaw/machines/customs: check in code.hackerspace.pl/vuko/customs
Change-Id: Ic698cce2ef0060a54b195cf90574696b8be1eb0f
Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1162
Reviewed-by: informatic <informatic@hackerspace.pl>
diff --git a/hswaw/machines/OWNERS b/hswaw/machines/OWNERS
new file mode 100644
index 0000000..c1ce290
--- /dev/null
+++ b/hswaw/machines/OWNERS
@@ -0,0 +1,4 @@
+inherited: false
+owners:
+ - informatic
+ - vuko
diff --git a/hswaw/machines/customs.hackerspace.pl/checkinator-repo.json b/hswaw/machines/customs.hackerspace.pl/checkinator-repo.json
new file mode 100644
index 0000000..d870142
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/checkinator-repo.json
@@ -0,0 +1,5 @@
+{
+ "url": "http://code.hackerspace.pl/checkinator",
+ "rev": "713c7e6c1a8fd6147522c1a5e3067898a1d8bf7a",
+ "sha256": "1vhz9jd0hfa0d1hihgkarf6w7z8yqvz4dzk42wzwk0rs25qlcavi"
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/checkinator-tracker.nix b/hswaw/machines/customs.hackerspace.pl/checkinator-tracker.nix
new file mode 100644
index 0000000..44ab46d
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/checkinator-tracker.nix
@@ -0,0 +1,71 @@
+{ pkgs, ... }:
+
+let
+ old-pkgs = import (fetchTarball {
+ sha256 = "0kdx3pz0l422d0vvvj3h8mnq65jcg2scb13dc1z1lg2a8cln842z";
+ url = https://api.github.com/repos/NixOS/nixpkgs/tarball/0bf298df24f721a7f85c580339fb7eeff64b927c;
+ }) { config = pkgs.config; };
+
+ repo = pkgs.fetchgit (builtins.fromJSON
+ (builtins.readFile ./checkinator-repo.json));
+ checkinator = old-pkgs.callPackage "${repo}/default.nix" {};
+
+ name = "checkinator-tracker";
+ user = name;
+ group = name;
+ socket_dir = "/run/${name}/";
+
+ prepare = pkgs.writeShellScriptBin "${name}-prepare" ''
+ rm -rf /mnt/secrets/${name}
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=500 --directory /mnt/secrets/${name}
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=400 -t /mnt/secrets/${name} \
+ /etc/nixos/secrets/${name}/ca.pem \
+ /etc/nixos/secrets/${name}/cert.pem \
+ /etc/nixos/secrets/${name}/key.pem
+
+ rm -rf ${socket_dir}
+ mkdir --mode=700 ${socket_dir}
+ ${pkgs.acl}/bin/setfacl -m "u:${user}:rwx" ${socket_dir}
+ ${pkgs.acl}/bin/setfacl -m "u:checkinator-web:rx" ${socket_dir}
+ '';
+ config = builtins.toFile "${name}-config.yaml" (pkgs.lib.generators.toYAML {} {
+ # path to dhcpd lease file
+ LEASE_FILE = "/var/lib/dhcp/dhcpd.leases";
+
+ # timeout for old leases
+ TIMEOUT = 1500;
+
+ # optional - local trusted socket
+ GRPC_UNIX_SOCKET = "${socket_dir}/checkinator.sock";
+
+ # optional - remote authenticated (TLS cert) socket
+ GRPC_TLS_CERT_DIR = "/mnt/secrets/checkinator-tracker";
+ GRPC_TLS_CA_CERT = "/mnt/secrets/checkinator-tracker/ca.pem";
+ GRPC_TLS_ADDRESS = "[::]:2847";
+ });
+in {
+ users.users."${user}" = {
+ group = "${group}";
+ useDefaultShell = true;
+ };
+ users.groups."${group}" = {};
+
+ systemd.services."${name}" = {
+ description = "Hackerspace Checkinator";
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig.User = "${user}";
+ serviceConfig.Type = "simple";
+
+ serviceConfig.ExecStartPre = [
+ ''!${prepare}/bin/${name}-prepare''
+ ];
+ serviceConfig.ExecStart = "${checkinator}/bin/checkinator-tracker ${config}";
+ serviceConfig.ExecStopPost = [
+ ''!${pkgs.coreutils}/bin/rm -rf /mnt/secrets/${name}''
+ ''!${pkgs.coreutils}/bin/rm -rf ${socket_dir}''
+ ];
+
+ };
+ environment.systemPackages = [ checkinator ];
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/checkinator-web.nix b/hswaw/machines/customs.hackerspace.pl/checkinator-web.nix
new file mode 100644
index 0000000..c8b2542
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/checkinator-web.nix
@@ -0,0 +1,134 @@
+{ pkgs, ... }:
+
+let
+ old-pkgs = import (fetchTarball {
+ sha256 = "0kdx3pz0l422d0vvvj3h8mnq65jcg2scb13dc1z1lg2a8cln842z";
+ url = https://api.github.com/repos/NixOS/nixpkgs/tarball/0bf298df24f721a7f85c580339fb7eeff64b927c;
+ }) { config = pkgs.config; };
+
+ repo = pkgs.fetchgit (builtins.fromJSON
+ (builtins.readFile ./checkinator-repo.json));
+ checkinator = old-pkgs.callPackage "${repo}/default.nix" {};
+
+ name = "checkinator-web";
+ user = name;
+ group = name;
+ socket_dir = "/run/${name}/";
+
+ python = old-pkgs.python3.withPackages (ppackages: with ppackages; [
+ checkinator
+ old-pkgs.python3Packages.gunicorn
+ ]);
+
+ prepare = pkgs.writeShellScriptBin "${name}-prepare" ''
+ rm -rf /mnt/secrets/${name}
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=500 --directory /mnt/secrets/${name}
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=400 -t /mnt/secrets/${name} \
+ /etc/nixos/secrets/${name}/secrets.yaml \
+ /etc/nixos/secrets/${name}/ca.pem \
+ /etc/nixos/secrets/${name}/cert.pem \
+ /etc/nixos/secrets/${name}/key.pem
+
+ ${pkgs.coreutils}/bin/mkdir -m 700 -p /var/checkinator-web/
+ ${pkgs.coreutils}/bin/chown ${user} /var/checkinator-web/
+
+ mkdir -p --mode=700 ${socket_dir}
+ chown ${user} ${socket_dir}
+ chmod 700 ${socket_dir}
+ ${pkgs.acl}/bin/setfacl -m "u:nginx:rx" ${socket_dir}
+ '';
+
+ config = builtins.toFile "${name}-config.yaml" (pkgs.lib.generators.toYAML {} {
+ # local sqlite db for storing user and MAC
+ DB = "/var/checkinator-web/at.db";
+
+ # debug option interpreted by flask app
+ DEBUG = false;
+
+ # url to member wiki page
+ # "${login}" string is replaced by member login (uid)
+ WIKI_URL = "https://wiki.hackerspace.pl/people:\${login}:start";
+
+ CLAIMABLE_PREFIXES = [
+ "10.8.0."
+ "2a0d:eb00:4242:0:"
+ ];
+ CLAIMABLE_EXCLUDE = [ ];
+
+ SPACEAUTH_CONSUMER_KEY = "checkinator";
+ SECRETS_FILE = "/mnt/secrets/checkinator-web/secrets.yaml";
+
+ SPECIAL_DEVICES = {
+ kektops = [ "90:e6:ba:84" ];
+ esps = [
+ "ec:fa:bc" "dc:4f:22" "d8:a0:1d" "b4:e6:2d" "ac:d0:74" "a4:7b:9d"
+ "a0:20:a6" "90:97:d5" "68:c6:3a" "60:01:94" "5c:cf:7f" "54:5a:a6"
+ "30:ae:a4" "2c:3a:e8" "24:b2:de" "24:0a:c4" "18:fe:34" "38:2b:78"
+ "bc:dd:c2" "cc:50:e3" "84:0d:8e"
+ ];
+ vms = [
+ "52:54:00" # craptrap VMs
+ ];
+ };
+
+ PROXY_FIX = true;
+
+ GRPC_TLS_CERT_DIR = "/mnt/secrets/checkinator-web";
+ GRPC_TLS_CA_CERT = "/mnt/secrets/checkinator-web/ca.pem";
+ GRPC_TLS_ADDRESS = "[::1]:2847";
+ });
+in {
+ users.users."${user}" = {
+ group = "${group}";
+ useDefaultShell = true;
+ };
+ users.groups."${group}" = {};
+
+ systemd.services."${name}" = {
+ description = "Hackerspace Checkinator web interface";
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig.User = "${user}";
+ serviceConfig.Type = "simple";
+
+ environment = {
+ CHECKINATOR_WEB_CONFIG=config;
+ };
+
+ serviceConfig.ExecStartPre = [
+ ''!${prepare}/bin/${name}-prepare''
+ "${pkgs.writeShellScript "checkinator-dbsetup" ''
+ if [ ! -e "/var/checkinator-web/at.db" ]
+ then
+ ${pkgs.sqlite}/bin/sqlite3 /var/checkinator-web/at.db < ${repo}/dbsetup.sql
+ fi
+ ''}"
+ ];
+ serviceConfig.workingDirectory = checkinator;
+ serviceConfig.ExecStart = "${python}/bin/gunicorn -b unix:${socket_dir}/web.sock at.webapp:app";
+ serviceConfig.ExecStopPost = [
+ ''!${pkgs.coreutils}/bin/rm -rf /mnt/secrets/${name}''
+ ];
+
+ };
+
+ services.nginx.virtualHosts."at.hackerspace.pl" = {
+ forceSSL = true;
+ enableACME = true;
+
+ locations."/static/" = {
+ alias = "${repo}/static/";
+ };
+ locations."/" = {
+ proxyPass = "http://unix://${socket_dir}/web.sock";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host $host:$server_port;
+ proxy_set_header X-Forwarded-Server $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ '';
+ };
+ };
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/configuration.nix b/hswaw/machines/customs.hackerspace.pl/configuration.nix
new file mode 100644
index 0000000..c00debb
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/configuration.nix
@@ -0,0 +1,578 @@
+{ config, pkgs, ... }:
+
+let
+ # hscloud checkout, hscloud.routing used to set up dynamic routing (OSPFv6 via bird)
+ hscloud = fetchGit {
+ url = "https://gerrit.hackerspace.pl/hscloud.git";
+ name = "hscloud";
+ rev = "e401735fdd241b25dac4cb82d828dcfa6f84b198";
+ };
+
+ hw = builtins.fromJSON (builtins.readFile ./hw.json);
+ fw = import ./fw-7535.nix;
+ vuko-pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhaCaC/CVYv6hphqmEdKaPrIn+Q946+myvL9SSnzFZk vuko@eagle";
+ q3k-pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG599UildOrAq+LIOQjKqtGMwjgjIxozI1jtQQRKHtCP q3k@mimeomia";
+ networks = {
+ uplink = {
+ description = "Hackerspace Internet Uplink";
+ hw_addr = builtins.elemAt fw.hw_addresses 0;
+ ipv4 = "185.236.240.5";
+ ipv6 = "2a0d:eb00:2137:1::3";
+ };
+ lan = {
+ description = "Hackerspace LAN";
+ hw_addr = builtins.elemAt fw.hw_addresses 1;
+ ipv4 = "10.8.1.2";
+ ipv6 = "2a0d:eb00:4242::1";
+ };
+ managment = {
+ description = "Management network (temporary routing)";
+ hw_addr = builtins.elemAt fw.hw_addresses 2;
+ };
+ lte = {
+ description = "temp LTE uplink";
+ hw_addr = builtins.elemAt fw.hw_addresses 3;
+ };
+ vpn = {
+ description = "Hackerspace members vpn";
+ ipv4 = "10.9.1.1";
+ };
+ };
+ hostname = "customs";
+ openvpn-auth = import ./openvpn-auth { inherit pkgs; };
+ secrets-path = "/etc/nixos/secrets/";
+ update_authorized_keys = pkgs.writeShellScriptBin "update_authorized_keys" ''
+ ${pkgs.python3.withPackages (pp: [ pp.ldap3 ])}/bin/python ${./update_authorized_keys.py} ${hostname} ${secrets-path}/ldap-password.txt
+ '';
+
+in {
+ imports =
+ [
+ ./ulogd2/service.nix
+ #./hardware-configuration.nix
+ <nixpkgs/nixos/modules/profiles/minimal.nix>
+ <nixpkgs/nixos/modules/profiles/all-hardware.nix>
+ "${hscloud}/bgpwtf/machines/modules/routing.nix"
+ ./checkinator-tracker.nix
+ ./checkinator-web.nix
+ ./mikrotik-exporter.nix
+ ./netboot.nix
+ ./laserproxy/service.nix
+ ];
+
+
+ boot.loader.grub.enable = true;
+ boot.loader.grub.version = 2;
+ boot.loader.grub.device = "nodev";
+ boot.loader.grub.extraConfig = ''
+ serial --unit=0 --speed=115200
+ terminal_input serial
+ terminal_output serial
+ '';
+ boot.kernelParams = ["console=tty0" "console=ttyS0,115200"];
+
+ time.timeZone = "Europe/Warsaw";
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-partuuid/${hw.rootUUID}";
+ fsType = "ext4";
+ };
+
+ services.postfix = let acme_dir = "/var/lib/acme"; in {
+ enable = true;
+ domain = "customs.hackerspace.pl";
+ hostname = "customs.hackerspace.pl";
+ destination = [ "localhost" ];
+ sslCert = "${acme_dir}/customs.hackerspace.pl/full.pem";
+ sslKey = "${acme_dir}/customs.hackerspace.pl/key.pem";
+ enableSmtp = true;
+ enableSubmission = false;
+ #relayHost = "hackerspace.pl";
+ extraConfig = ''
+ inet_interfaces = loopback-only
+ '';
+ };
+
+ fileSystems."/mnt/secrets" = {
+ fsType = "tmpfs";
+ options = [ "rw" "mode=755" "size=200M" "nosuid" "nodev" "relatime" "noexec" ];
+ };
+
+ networking.hostName = hostname;
+ networking.domain = "hackerspace.pl";
+
+ networking.useDHCP = false;
+ networking.vlans = {
+ laser = {
+ id = 4001;
+ interface = "lan";
+ };
+ bms = {
+ id = 4002;
+ interface = "lan";
+ };
+ };
+
+ systemd.services.secrets = {
+ enable = true;
+ description = "Copy secrets and fix permissions";
+ script = ''
+ ${pkgs.coreutils}/bin/install --owner=root --mode=700 --directory /mnt/secrets/nginx/
+ ${pkgs.coreutils}/bin/install --owner=root --mode=400 -t /mnt/secrets/nginx/ \
+ ${secrets-path}/nginx/at.hackerspace.pl.key \
+ ${secrets-path}/nginx/at.hackerspace.pl.crt
+ ${pkgs.acl}/bin/setfacl -m "u:nginx:rx" /mnt/secrets/nginx
+ ${pkgs.acl}/bin/setfacl -m "u:nginx:r" /mnt/secrets/nginx/*
+ '';
+ wantedBy = [ "nginx.service" ];
+ partOf = [ "nginx.service" ];
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = "true";
+ serviceConfig.User = "root";
+ };
+
+ services.prometheus.exporters.node = {
+ enable = true;
+ listenAddress = "[::1]";
+ port = 9100;
+ enabledCollectors = [ "systemd" ];
+ };
+
+ systemd.network.links = builtins.listToAttrs (map (
+ name: { name = "10-link-${name}"; value = {
+ enable = true;
+ matchConfig = {
+ MACAddress = networks."${name}".hw_addr;
+ };
+ linkConfig = {
+ Name = "${name}";
+ };
+ }; }
+ ) (builtins.filter (name: builtins.hasAttr "hw_addr" networks."${name}") (builtins.attrNames networks)));
+
+ #networking.interfaces.vpn = {
+ # virtual = true;
+ # name = "vpn";
+ # #ipv4.addresses = [ { address = 10.9.1.1; prefixlen = 16; } ];
+ #};
+
+ boot.kernel.sysctl = {
+ "net.ipv4.ip_forward" = true;
+ "net.ipv6.conf.all.forwarding" = true;
+ };
+
+ # using nftables so firewall has to be disabled
+ networking.firewall.enable = false;
+ networking.nftables.enable = true;
+ networking.nftables.ruleset = ''
+ table inet filter {
+ chain input {
+ type filter hook input priority 0;
+
+ # accept any localhost traffic
+ iifname lo accept
+
+ # accept traffic originated from us
+ ct state {established, related} accept
+
+ # ICMP
+ ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, nd-router-solicit } accept
+ ip protocol icmp icmp type { destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept
+
+ # allow "ping"
+ ip6 nexthdr icmpv6 icmpv6 type echo-request accept
+ ip protocol icmp icmp type echo-request accept
+
+ # allow OSPFv3
+ ip6 nexthdr 89 accept
+
+ tcp dport 22 accept
+ tcp dport 53 accept
+ udp dport 53 accept
+ tcp dport 80 accept
+ tcp dport 443 accept
+ udp dport tftp accept
+
+ iifname managment udp dport tftp accept
+ iifname lan tcp dport 8080 accept
+
+ # openvpn-members
+ udp dport 20001 accept
+ tcp dport 20001 accept
+
+ # laserproxy
+ udp dport 40200 accept
+ udp dport 50200 accept
+
+ counter drop
+ }
+
+ # Allow all outgoing connections.
+ chain output {
+ type filter hook output priority 0; policy accept;
+ }
+
+ chain forward {
+ type filter hook forward priority 0; policy drop;
+ ct state {established, related} jump accepted
+ oifname "loop" jump accepted
+ ip saddr 10.8.0.0/16 iifname "lan" jump accepted
+ ip saddr 10.9.0.0/16 iifname "vpn" jump accepted
+ ip6 saddr 2a0d:eb00:4242::0/64 iifname "lan" jump accepted
+ ip6 saddr 2a0d:eb00:4242:1::0/64 iifname "vpn" jump accepted
+ ip6 saddr 2a0d:eb00:4242:1::1/128 iifname "loop" jump accepted
+ }
+
+ chain accepted {
+ # IMPORTANT
+ # Log all connections to the outside world from LAN interface, as we are
+ # required to do so
+ oifname != "uplink" accept
+ iifname "uplink" accept
+ ip daddr { 10.0.0.0/8, 225.225.225.225/32 } accept
+ ip6 daddr { 2a0d:eb00::/29, fe80::/8 } accept
+ log group 2 accept
+ }
+ }
+
+ table inet net {
+ chain postrouting {
+ type nat hook postrouting priority 100;
+ ip saddr 10.8.0.0/16 oifname uplink snat ${networks.uplink.ipv4}
+ ip saddr 10.9.0.0/16 oifname uplink snat ${networks.uplink.ipv4}
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority -100;
+
+ # Access to staszkecoin from Internet
+ ip version 4 iifname "uplink" tcp dport 8333 dnat 10.8.1.49
+ }
+ }
+ '';
+
+ systemd.services."loop-netdev" = let n = "loop"; in {
+ description = "Dummy interface: loop";
+ wantedBy = [ "network-setup.service" "sys-subsystem-net-devices-${n}.device" ];
+ partOf = [ "network-setup.service" ];
+ after = [ "network-pre.target" ];
+ before = [ "network-setup.service" ];
+ serviceConfig.Type = "oneshot";
+ serviceConfig.RemainAfterExit = true;
+ path = [ pkgs.iproute ];
+ script = ''
+ # Remove Dead Interfaces
+ ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+ ip link add "${n}" type dummy
+ ip link set "${n}" up
+ '';
+ postStop = ''
+ ip link delete "${n}"
+ '';
+ };
+
+
+ networking.interfaces = {
+ uplink = {
+ ipv4.addresses = [ { address = networks.uplink.ipv4; prefixLength = 31; } ];
+ ipv6.addresses = [
+ { address = networks.uplink.ipv6; prefixLength = 112; }
+ ];
+ };
+ lan = {
+ ipv4.addresses = [ { address = networks.lan.ipv4; prefixLength = 16; } ];
+ ipv6.addresses = [ { address = networks.lan.ipv6; prefixLength = 64; } ];
+ };
+ loop = {
+ ipv6.addresses = [ { address = "2a0d:eb00:4242:1::1"; prefixLength = 128; } ];
+ };
+ laser = {
+ ipv4.addresses = [ { address = "10.11.0.1"; prefixLength = 24; } ];
+ };
+ bms = {
+ ipv4.addresses = [ { address = "10.11.1.1"; prefixLength = 24; } ];
+ };
+ managment = {
+ ipv4.addresses = [ { address = "10.10.1.1"; prefixLength = 24; } ];
+ };
+ lte = {
+ ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ];
+ };
+ };
+
+ networking.defaultGateway = {
+ address = "185.236.240.4";
+ interface = "uplink";
+ };
+ networking.defaultGateway6 = {
+ address = "2a0d:eb00:2137:1::1";
+ interface = "uplink";
+ };
+
+
+ networking.nameservers = [ "1.0.0.1" "8.8.8.8" ];
+
+ services.openssh = {
+ enable = true;
+ passwordAuthentication = false;
+ logLevel = "INFO";
+ };
+
+ users.users.root.openssh.authorizedKeys.keys = [ vuko-pubkey q3k-pubkey ];
+
+ services.dhcpd4 = {
+ enable = true;
+ configFile = ./dhcpd.conf;
+ interfaces = ["lan"];
+ };
+
+ hscloud.routing = {
+ enable = true;
+ # TODO(q3k): make this optional in upstream
+ extra = "";
+ routerID = "185.236.240.5";
+ tables.master.program = true;
+ pipe.v6.aggregate_to_kernel = {
+ table = "master";
+ peerTable = "aggregate";
+ filterIn = ''
+ if source = RTS_OSPF then accept;
+ if source = RTS_OSPF_EXT2 then accept;
+ reject;
+ '';
+ };
+ ospf.v6.upstream = {
+ table = "aggregate";
+ area."0.0.0.0" = {
+ interfaces.uplink = { type = "bcast"; };
+ interfaces.lan = { type = "bcast"; stub = true; };
+ interfaces.loop = { type = "ptp"; stub = true; };
+ };
+ };
+ };
+
+ services.radvd = {
+ enable = true;
+ config = ''
+ interface lan {
+ AdvSendAdvert on;
+ prefix 2a0d:eb00:4242::/64 {
+ };
+ route 0::/0 { };
+ };
+ interface vpn {
+ AdvSendAdvert on;
+ prefix 2a0d:eb00:4242:1::/64 {
+ AdvRouterAddr on;
+ };
+ route 0::/0 { };
+ };
+ '';
+ };
+
+ services.logrotate = {
+ enable = true;
+ paths = {
+ ulogd = {
+ enable = true;
+ frequency = "weekly";
+ path = "/var/log/ulogd.pcap";
+ extraConfig = ''
+ postrotate
+ ${pkgs.killall}/bin/killall -HUP ulogd
+ endscript
+ '';
+ keep = 55;
+ };
+ };
+ };
+
+ services.cron = let
+ log-neigh = pkgs.writeShellScript "log-neigh" ''
+ mkdir -p /var/log/arptables
+ chmod 700 /var/log/arptables
+
+ # Larger than 10MB? rotate.
+ if [[ $(find /var/log/arptables/arptables.log -type f -size +10485760c 2>/dev/null) ]]; then
+ f=/var/log/arptables/$(date "+%s").log
+ cp /var/log/arptables/arptables.log $f
+ gzip -9 $f
+ rm /var/log/arptables/arptables.log
+ fi
+
+ ip neigh >> /var/log/arptables/arptables.log
+ date --iso-8601=seconds >> /var/log/arptables/arptables.log
+ '';
+ in {
+ mailto = "vuko@hackerspace.pl";
+ enable = true;
+ systemCronJobs = [
+ "*/5 * * * * root ${log-neigh}"
+ "0 3 * * * root ${update_authorized_keys}/bin/update_authorized_keys"
+ ];
+ };
+
+ services.knot = {
+ enable = true;
+ extraConfig = ''
+ server:
+ listen: ${networks.uplink.ipv4}@53
+ listen: ${networks.uplink.ipv6}@53
+
+ zone:
+ - domain: waw.hackerspace.pl
+ storage: ${./zones}
+ file: waw.hackerspace.pl
+ - domain: i
+ storage: ${./zones}
+ file: i
+ - domain: api.ustream.tv
+ storage: ${./zones}
+ file: api.ustream.tv
+ - domain: api.eye.fi
+ storage: ${./zones}
+ file: api.eye.fi
+ log:
+ - target: syslog
+ any: info
+ '';
+ };
+
+ services.nginx.enable = true;
+ services.nginx.mapHashBucketSize = 64;
+ services.nginx.appendHttpConfig = ''
+ server_names_hash_bucket_size 64;
+ '';
+
+ security.acme = {
+ email = "bofh@hackerspace.pl";
+ acceptTerms = true;
+ };
+
+ services.nginx.virtualHosts."customs.hackerspace.pl" = {
+ default = true;
+ enableACME = true;
+
+ locations."/" = {
+ extraConfig = ''
+ return 302 https://isztar.mf.gov.pl;
+ '';
+ };
+ locations."/metrics/luftdaten" = {
+ proxyPass = "http://10.8.0.146";
+ };
+ locations."/metrics/spejsiot" = {
+ proxyPass = "http://spejsiot.waw.hackerspace.pl/metrics";
+ };
+ locations."/metrics/apm" = {
+ proxyPass = "http://10.8.1.40:5000/metrics";
+ };
+ locations."/metrics/vending" = {
+ proxyPass = "http://10.8.1.32:8000/";
+ };
+ locations."/metrics/sztancarka" = {
+ proxyPass = "http://10.8.0.96:8888/";
+ };
+ locations."/metrics/mikrotik" = {
+ proxyPass = "http://127.0.0.1:9436/metrics";
+ extraConfig = ''
+ allow 209.250.231.127;
+ deny all;
+ '';
+ };
+ locations."/metrics/node" = {
+ proxyPass = "http://[::1]:9100/metrics";
+ extraConfig = ''
+ allow 209.250.231.127;
+ deny all;
+ '';
+ };
+ locations."/stats/sztancarka-ppm" = {
+ proxyPass = "http://10.8.0.96:9090/api/v1/query?query=rate%28cut_count_total%5B15m%5D%29+*+60";
+ };
+ locations."/stats/sztancarka-last-24h" = {
+ proxyPass = "http://10.8.0.96:9090/api/v1/query?query=round(increase(cut_count_total[24h]))";
+ };
+ };
+
+ services.unbound = {
+ enable = true;
+ interfaces = [
+ networks.lan.ipv4
+ "127.0.0.1"
+ "::1"
+ # networks.lan.ipv6 TODO
+ ];
+ allowedAccess = [
+ "127.0.0.1/8"
+ "10.0.0.0/8"
+ ];
+ extraConfig = builtins.concatStringsSep "\n" ((map (
+ name: ''
+ stub-zone:
+ name: ${name}
+ stub-addr: ${networks.uplink.ipv4}
+ ''
+ ) [ "waw.hackerspace.pl" "api.eye.fi" "api.ustream.tv" "i"]) ++ [''
+ forward-zone:
+ name: "."
+ forward-addr: 185.236.240.1
+ '']);
+ };
+
+
+
+ # Public VPN access for Hackerspace members
+ services.openvpn.servers.members.config = ''
+ script-security 3
+ auth-user-pass-verify ${openvpn-auth}/bin/openvpn-auth-member via-env
+ verify-client-cert none
+ username-as-common-name
+
+ #user _openvpn
+ #group _openvpn
+ multihome
+
+ port 20001
+ proto udp
+ proto udp6
+ dev vpn
+ dev-type tun
+ ca ${secrets-path}/openvpn-public/ca.crt
+ cert ${secrets-path}/openvpn-public/server.crt
+ key ${secrets-path}/openvpn-public/server.key
+ dh ${secrets-path}/openvpn-public/dh.pem
+ server 10.9.1.0 255.255.255.0
+
+ push "route 10.8.0.0 255.255.0.0"
+ push "route 10.9.0.0 255.255.0.0"
+ push "route 10.10.0.0 255.255.0.0"
+ push "route 10.11.0.0 255.255.0.0"
+ push "dhcp-option DNS ${networks.lan.ipv4}"
+ push "dhcp-option DOMAIN waw.hackerspace.pl"
+
+ ifconfig-pool-persist /var/lib/openvpn-public/ipp.txt
+ #client-config-dir /var/lib/openvpn-public/ccd
+ client-to-client
+ keepalive 10 120
+ comp-lzo
+ persist-key
+ persist-tun
+ '';
+
+ environment.systemPackages = with pkgs; [
+ vim tcpdump htop nmon tmux git file procps parted dmidecode ack utillinux nmap mosh ncdu tree lz4 bind
+ rxvt_unicode.terminfo update_authorized_keys
+ ];
+ programs.mtr.enable = true;
+
+ environment.variables = {
+ EDITOR = "vim";
+ };
+
+ system.stateVersion = "20.03";
+
+ boot.vesa = false;
+ boot.loader.grub.splashImage = null;
+}
+
diff --git a/hswaw/machines/customs.hackerspace.pl/dhcpd.conf b/hswaw/machines/customs.hackerspace.pl/dhcpd.conf
new file mode 100644
index 0000000..0ce071e
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/dhcpd.conf
@@ -0,0 +1,175 @@
+option domain-search "waw.hackerspace.pl";
+option domain-name-servers 10.8.1.2;
+default-lease-time 600;
+max-lease-time 600;
+one-lease-per-client true;
+
+option cisco-ip-phone-tftp code 150 = ip-address;
+
+subnet 10.8.0.0 netmask 255.255.0.0 {
+
+ option routers 10.8.1.2;
+ range 10.8.0.20 10.8.0.199;
+ authoritative;
+ allow bootp;
+
+ if substring (option vendor-class-identifier, 15, 5) = "00000" {
+ filename "netboot.xyz.kpxe";
+ } else {
+ filename "netboot.xyz.efi";
+ }
+
+ next-server 10.8.1.2;
+
+ host laser {
+ hardware ethernet 00:0e:35:1d:a1:a4;
+ fixed-address 10.8.1.18;
+ }
+ host oki {
+ hardware ethernet 00:25:36:de:27:56;
+ fixed-address 10.8.1.20;
+ }
+ host brother {
+ hardware ethernet 00:1b:a9:24:96:e2;
+ fixed-address 10.8.1.21;
+ }
+ host zebra {
+ hardware ethernet 00:07:4d:4d:71:e4;
+ fixed-address 10.8.1.22;
+ }
+ host lj2100 {
+ hardware ethernet 00:30:C1:62:61:23;
+ fixed-address 10.8.1.23;
+ }
+ host dht21 {
+ hardware ethernet 5c:cf:7f:06:9a:3e;
+ fixed-address 10.8.1.25;
+ }
+ host ledpanel {
+ hardware ethernet 00:0A:35:00:01:22;
+ fixed-address 10.8.1.26;
+ }
+ host bridgeport {
+ hardware ethernet 90:1b:0e:1d:23:09;
+ fixed-address 10.8.1.29;
+ }
+ host 3printers1cups {
+ hardware ethernet 02:20:f5:20:6a:2d;
+ fixed-address 10.8.1.30;
+ }
+
+ host telelele {
+ hardware ethernet fe:77:d6:83:26:b1;
+ fixed-address 10.8.1.31;
+ }
+
+ # vending
+ host vending {
+ #hardware ethernet b8:27:eb:71:e4:0e;
+ #hardware ethernet b8:27:eb:3d:ba:fe;
+ hardware ethernet b8:27:eb:03:69:01;
+ fixed-address 10.8.1.32;
+ }
+
+ host transcend {
+ hardware ethernet b0:38:29:2e:5d:c9;
+ fixed-address 10.8.1.33;
+ }
+
+ host welcomer {
+ hardware ethernet b8:27:eb:37:9e:6e;
+ fixed-address 10.8.1.34;
+ }
+
+ host arcade {
+ hardware ethernet 20:e5:17:0c:31:23;
+ fixed-address 10.8.1.35;
+ }
+
+ host inventory {
+ hardware ethernet 90:e6:ba:84:b6:e0;
+ fixed-address 10.8.1.38;
+ }
+
+ host camera {
+ hardware ethernet 52:54:00:1f:63:1b;
+ fixed-address 10.8.1.39;
+ }
+
+ # Cisco IP Phone
+ host SEPA40CC394DB0C {
+ hardware ethernet a4:0c:c3:94:db:0c;
+ next-server 10.8.1.2;
+ # managed by dfgg/drozdziak
+ #option cisco-ip-phone-tftp 10.8.0.190;
+ option cisco-ip-phone-tftp 10.8.1.2;
+ fixed-address 10.8.1.42;
+ }
+
+ # RIPE Atlas Probe
+ host ripeatlas {
+ hardware ethernet c0:25:e9:99:fb:e8;
+ fixed-address 10.8.1.43;
+ }
+
+ host chromecast {
+ hardware ethernet 6c:ad:f8:52:4c:a7;
+ fixed-address 10.8.1.47;
+ }
+
+ # craptrap VM
+ host winbox {
+ hardware ethernet 52:54:00:D9:DB:42;
+ fixed-address 10.8.1.48;
+ }
+
+ host staszkecoin {
+ hardware ethernet 02:42:24:75:eb:19;
+ fixed-address 10.8.1.49;
+ }
+
+
+ host blitzloop {
+ hardware ethernet 00:23:14:b0:ec:c8;
+ fixed-address 10.8.1.51;
+ }
+
+ host tronxy {
+ hardware ethernet 00:1f:16:1c:47:df;
+ fixed-address 10.8.1.52;
+ }
+
+}
+
+# Printer subnet (10.10.7.0/24) has ip-helper 10.8.1.2 set on hs-core01.
+# Make DHCP happen.
+subnet 10.10.7.0 netmask 255.255.255.0 {
+ option routers 10.10.7.1;
+ range 10.10.7.100 10.10.7.200;
+ authoritative;
+ allow bootp;
+}
+
+# Listen for relayed requests on the interface from core01
+# (even though we're not serving anything there directly)
+subnet 172.16.1.0 netmask 255.255.255.250 {
+}
+
+subnet 10.10.5.0 netmask 255.255.255.0 {
+ option routers 10.10.5.1;
+ range 10.10.5.100 10.10.5.200;
+ authoritative;
+ allow bootp;
+ filename "elilo.efi";
+ next-server 10.8.1.16;
+# option pxelinux.configfile "elilo.conf"
+}
+# itanic ilo gnuj
+subnet 10.10.1.0 netmask 255.255.255.0 {
+ option routers 10.10.1.1;
+ range 10.10.1.150 10.10.1.200;
+ authoritative;
+ next-server 10.8.1.16;
+}
+
+
diff --git a/hswaw/machines/customs.hackerspace.pl/fw-7535.nix b/hswaw/machines/customs.hackerspace.pl/fw-7535.nix
new file mode 100644
index 0000000..f628a72
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/fw-7535.nix
@@ -0,0 +1,13 @@
+
+{
+ model = "FW-7535";
+ hw_addresses = [
+ "00:90:0b:25:bd:e0"
+ "00:90:0b:25:bd:e1"
+ "00:90:0b:25:bd:e2"
+ "00:90:0b:25:bd:e3"
+ "00:90:0b:25:bd:e4"
+ "00:90:0b:25:bd:e5"
+ ];
+}
+
diff --git a/hswaw/machines/customs.hackerspace.pl/hardware-configuration.nix b/hswaw/machines/customs.hackerspace.pl/hardware-configuration.nix
new file mode 100644
index 0000000..1ba16f7
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/hardware-configuration.nix
@@ -0,0 +1,17 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, ... }:
+
+{
+ imports =
+ [ <nixpkgs/nixos/modules/installer/scan/not-detected.nix>
+ ];
+
+ boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ata_piix" "ahci" "usb_storage" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ ];
+ boot.extraModulePackages = [ ];
+
+ nix.maxJobs = lib.mkDefault 4;
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/hw.json b/hswaw/machines/customs.hackerspace.pl/hw.json
new file mode 100644
index 0000000..dc648c4
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/hw.json
@@ -0,0 +1 @@
+{"rootUUID": "2c7be07a-aebf-bb41-9a21-9a8dda8fe8a9"}
\ No newline at end of file
diff --git a/hswaw/machines/customs.hackerspace.pl/laserproxy/service.nix b/hswaw/machines/customs.hackerspace.pl/laserproxy/service.nix
new file mode 100644
index 0000000..c82ef5b
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/laserproxy/service.nix
@@ -0,0 +1,45 @@
+{ pkgs, workspace, ... }:
+
+let
+ name = "laserproxy";
+ user = name;
+ group = name;
+in {
+ users.users."${user}" = {
+ group = "${group}";
+ useDefaultShell = true;
+ };
+ users.groups."${group}" = {};
+
+ systemd.services."${name}" = {
+ description = "Logging packet log from nftables";
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig.User = "${user}";
+ serviceConfig.Type = "simple";
+
+ serviceConfig.ExecStart = "${workspace.hswaw.laserproxy}/bin/laserproxy -logtostderr -hspki_disable -web_address 127.0.0.1:2137";
+ };
+
+ services.nginx.virtualHosts."laser.waw.hackerspace.pl" = {
+ listen = [
+ { addr = "10.8.1.2"; port=80; ssl=false; }
+ #{ addr = "10.8.1.2"; port=433; ssl=true; }
+ ];
+ locations."/" = {
+ proxyPass = "http://127.0.0.1:2137/";
+ extraConfig = ''
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host $host:$server_port;
+ proxy_set_header X-Forwarded-Server $host;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ allow 10.0.0.0/8;
+ deny all;
+ '';
+ };
+ };
+
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/mikrotik-exporter.nix b/hswaw/machines/customs.hackerspace.pl/mikrotik-exporter.nix
new file mode 100644
index 0000000..26399f3
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/mikrotik-exporter.nix
@@ -0,0 +1,32 @@
+{ pkgs, ... }:
+
+let
+ unstable = import (fetchTarball {
+ sha256 = "0ww70kl08rpcsxb9xdx8m48vz41dpss4hh3vvsmswll35l158x0v";
+ url = "https://api.github.com/repos/NixOS/nixpkgs-channels/tarball/84d74ae9c9cbed73274b8e4e00be14688ffc93fe";
+ }) {config = pkgs.config; };
+
+ name = "mikrotik-exporter";
+ user = name;
+ group = name;
+
+ prepare-secrets = pkgs.writeShellScript "${name}-secrets" ''
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=500 --directory /mnt/secrets/${name}
+ ${pkgs.coreutils}/bin/install --owner=${user} --mode=400 -t /mnt/secrets/${name} \
+ /etc/nixos/secrets/${name}/ap.yml
+ '';
+in {
+ users.users."${user}" = {
+ group = "${group}";
+ useDefaultShell = true;
+ };
+ users.groups."${group}" = {};
+
+ systemd.services."${name}" = {
+ description = "Mikrotik prometheus exporter";
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig.Type = "simple";
+ serviceConfig.ExecStartPre = [ "!${prepare-secrets}" ];
+ serviceConfig.ExecStart = "${unstable.prometheus-mikrotik-exporter}/bin/mikrotik-exporter -config-file /mnt/secrets/${name}/ap.yml -port 127.0.0.1:9436";
+ };
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/netboot.nix b/hswaw/machines/customs.hackerspace.pl/netboot.nix
new file mode 100644
index 0000000..f232ce8
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/netboot.nix
@@ -0,0 +1,22 @@
+{ config, pkgs, lib, ... }:
+
+{
+ services.tftpd.enable = true;
+ services.tftpd.path = pkgs.linkFarm "netboot" [
+ {
+ name = "netboot.xyz.efi";
+ path = pkgs.fetchurl {
+ url = "https://github.com/netbootxyz/netboot.xyz/releases/download/2.0.48/netboot.xyz.efi";
+ sha256 = "1ch8ngryyr2abbrzpf0xb888a5d3rmnvfj8v0frfykhgs607666f";
+ #3b2de54224963ee17857a9737b65d49edc423e06ad7e9c9b85d9f69ca923676a";
+ };
+ }
+ {
+ name = "netboot.xyz.kpxe";
+ path = pkgs.fetchurl {
+ url = "https://github.com/netbootxyz/netboot.xyz/releases/download/2.0.48/netboot.xyz.kpxe";
+ sha256 = "0p3qcdiialzbqjmiss6qay7qdz6b8mdsx5lk4hf75rlkwjh3yhax";
+ };
+ }
+ ];
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/openvpn-auth/default.nix b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/default.nix
new file mode 100644
index 0000000..1a8d825
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/default.nix
@@ -0,0 +1,11 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+pkgs.python3Packages.buildPythonPackage {
+ pname = "openvpn-auth";
+ version = "1.0";
+
+ src = ./.;
+
+ propagatedBuildInputs = with pkgs; [ python3Packages.ldap3 ];
+}
+
diff --git a/hswaw/machines/customs.hackerspace.pl/openvpn-auth/openvpn_auth/__init__.py b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/openvpn_auth/__init__.py
new file mode 100755
index 0000000..927b94f
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/openvpn_auth/__init__.py
@@ -0,0 +1,61 @@
+import ldap3
+import os
+import sys
+import ssl
+from ldap3.utils.conv import escape_filter_chars
+
+class NotActiveMember(Exception):
+ "Person is not an active hackerspace member"
+
+def check_member(uid: str, password: str):
+ escaped_uid = escape_filter_chars(uid)
+ user_dn = f"uid={escaped_uid},ou=People,dc=hackerspace,dc=pl"
+
+ tls_configuration = ldap3.Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1)
+ server = ldap3.Server("ldap.hackerspace.pl", use_ssl=True, tls=tls_configuration)
+ with ldap3.Connection(server, user=user_dn, password=password, raise_exceptions=True) as conn:
+ filterstr = (
+ "(&"
+ f"(uid={escaped_uid})"
+ "(objectClass=hsMember)"
+ "(|"
+ "(memberOf=cn=starving,ou=Group,dc=hackerspace,dc=pl)"
+ "(memberOf=cn=fatty,ou=Group,dc=hackerspace,dc=pl)"
+ "(memberOf=cn=potato,ou=Group,dc=hackerspace,dc=pl)"
+ ")"
+ ")")
+ conn.search('ou=People,dc=hackerspace,dc=pl',
+ filterstr,
+ search_scope = ldap3.LEVEL,
+ attributes = ['uid'])
+ for e in conn.entries:
+ if e['uid'] == uid:
+ break
+ else:
+ NotActiveMember(f'Member {uid} not found in active members groups')
+
+def member_auth():
+ import argparse
+ import getpass
+
+ uid = os.environ.get('username', None)
+ password = os.environ.get('password', None)
+
+ if uid is None and password is None:
+ print('"username" and "password" not found in environment')
+ parser = argparse.ArgumentParser()
+ parser.add_argument("uid", nargs='?', default=getpass.getuser(), help="user id")
+ args = parser.parse_args()
+
+ uid = args.uid
+ password = getpass.getpass()
+
+ try:
+ check_member(uid, password)
+ sys.exit(0)
+ except Exception:
+ sys.exit(1)
+
+if __name__ == "__main__":
+ member_auth()
+
diff --git a/hswaw/machines/customs.hackerspace.pl/openvpn-auth/setup.py b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/setup.py
new file mode 100644
index 0000000..ec50fe7
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/openvpn-auth/setup.py
@@ -0,0 +1,17 @@
+from setuptools import setup
+
+setup(
+ name="openvpn_auth",
+ classifiers=[
+ "License :: OSI Approved :: zlib/libpng License",
+ "Programming Language :: Python :: 3.7",
+ ],
+ packages=["openvpn_auth"],
+ install_requires=["ldap3"],
+ python_requires=">=3.7,",
+ entry_points={
+ "console_scripts": [
+ "openvpn-auth-member=openvpn_auth:member_auth",
+ ]
+ },
+)
diff --git a/hswaw/machines/customs.hackerspace.pl/scripts/wipe-install.py b/hswaw/machines/customs.hackerspace.pl/scripts/wipe-install.py
new file mode 100755
index 0000000..05c04b0
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/scripts/wipe-install.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p grub2 rsync utillinux shadow utillinux e2fsprogs
+from subprocess import run
+from pathlib import Path
+from tempfile import TemporaryDirectory
+import argparse
+import json
+import os
+import sys
+import time
+
+root_device = Path('/dev/disk/by-id/ata-Crucial_CT250MX200SSD1_1537108FC44F')
+bios_boot_part_type = '21686148-6449-6E6F-744E-656564454649'
+config_dir = Path(__file__).parent.parent.absolute()
+
+if os.getlogin() != 'root':
+ print("ERROR: must be run as root", file=sys.stderr)
+ sys.exit(1)
+
+if not root_device.exists():
+ print(f"ERROR: {root_device} not found", file=sys.stderr)
+ sys.exit(1)
+
+print(f"WARNING: this script will WIPE all data on {root_device}")
+if input('Write "Yes" to continue:') != 'Yes':
+ sys.exit(1)
+
+with TemporaryDirectory() as tmp_path:
+ tmp = Path(tmp_path)
+ print(f"Created temporary directory {tmp}")
+
+ parts = (
+ 'label: gpt\n'
+ f'name=grub start=2MiB size=10MiB type={bios_boot_part_type}\n'
+ 'name=root size=100GiB\n'
+ )
+ run(['sfdisk', root_device], input=parts.encode())
+
+ parts_info = json.loads(run(['sfdisk', '--json', root_device], capture_output=True, check=True).stdout.decode())
+ root_part = Path(parts_info["partitiontable"]["partitions"][1]['node']).resolve()
+
+ for i in range(40):
+ if root_part.exists():
+ break
+ time.sleep(0.2)
+ else:
+ print(f"ERROR: create partition not exists: {root_part}", file=sys.stderr)
+ sys.exit(1)
+
+ run(['mkfs.ext4', root_part])
+
+ root = tmp.joinpath('root')
+ root.mkdir()
+
+ try:
+ run(['mount', root_part, root], check=True)
+
+ run(['mkdir', '-p', root.joinpath('etc', 'nixos')], check=True)
+ run(['rsync', '-r', '--progress', f'{config_dir!s}/', root.joinpath('etc', 'nixos')], check=True)
+
+ root_uuid = parts_info["partitiontable"]["partitions"][1]['uuid'].lower()
+ root.joinpath('etc', 'nixos', 'hw.json').write_text(json.dumps({
+ "rootUUID": f'{root_uuid}',
+ }))
+
+ run(['nixos-install', '--no-root-passwd', '--root', root], check=True)
+ run(['grub-install', f'--root-directory={root!s}', f'--boot-directory={root.joinpath("boot")!s}', root_device], check=False)
+ run(['chpasswd', '--root', root], input=b'root:toor')
+
+ finally:
+ run(['umount', root])
diff --git a/hswaw/machines/customs.hackerspace.pl/ulogd2/default.nix b/hswaw/machines/customs.hackerspace.pl/ulogd2/default.nix
new file mode 100644
index 0000000..01157fd
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/ulogd2/default.nix
@@ -0,0 +1,27 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+pkgs.stdenv.mkDerivation {
+ name = "ulogd2";
+
+ buildInputs = with pkgs; [
+ gnumake libnetfilter_acct libnetfilter_conntrack libnetfilter_log libmnl
+ libnfnetlink automake autoconf autogen libtool pkg-config libpcap
+ ];
+
+ # hack to capture TCP and UDP port numbers (first 8 bytes) but omit rest of payload
+ patches = [ ./onlyports.patch ];
+
+ preConfigure = ''
+ echo running autogen
+ ./autogen.sh
+ autoheader
+ automake --force-missing --add-missing
+ ./configure --help
+ '';
+
+ src = pkgs.fetchgit {
+ url = "https://git.netfilter.org/ulogd2/";
+ rev = "63135e73fd878cb71b1eebf8e877c4d4c34feba7";
+ sha256 = "1ccfb8l7q9k4fy9s0sgab49ma9xphr4x4ap0v52xfrnwx57h87s2";
+ };
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/ulogd2/onlyports.patch b/hswaw/machines/customs.hackerspace.pl/ulogd2/onlyports.patch
new file mode 100644
index 0000000..c89b80c
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/ulogd2/onlyports.patch
@@ -0,0 +1,23 @@
+diff --git a/output/pcap/ulogd_output_PCAP.c b/output/pcap/ulogd_output_PCAP.c
+index e7798f2..51c4ceb 100644
+--- a/output/pcap/ulogd_output_PCAP.c
++++ b/output/pcap/ulogd_output_PCAP.c
+@@ -154,9 +154,15 @@ static int interp_pcap(struct ulogd_pluginstance *upi)
+ switch (ikey_get_u8(&res[5])) {
+ case 2: /* INET */
+ pchdr.len = ikey_get_u16(&res[2]);
++ if (pchdr.caplen > 20 + 8) {
++ pchdr.caplen = 20 + 8;
++ }
+ break;
+ case 10: /* INET6 -- payload length + header length */
+ pchdr.len = ikey_get_u16(&res[6]) + 40;
++ if (pchdr.caplen > 40 + 8) {
++ pchdr.caplen = 40 + 8;
++ }
+ break;
+ default:
+ pchdr.len = pchdr.caplen;
+--
+2.25.4
+
diff --git a/hswaw/machines/customs.hackerspace.pl/ulogd2/service.nix b/hswaw/machines/customs.hackerspace.pl/ulogd2/service.nix
new file mode 100644
index 0000000..e50d92b
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/ulogd2/service.nix
@@ -0,0 +1,32 @@
+{ pkgs, ... }:
+
+let
+ ulogd2 = import ./default.nix { pkgs = pkgs; };
+ name = "ulogd2";
+ config = pkgs.writeText "ulogd.conf" ''
+ [global]
+ logfile="/var/log/ulogd.log"
+
+ stack=log1:NFLOG,base1:BASE,pcap1:PCAP
+
+ [log1]
+ group=2
+
+ [pcap1]
+ file="/var/log/ulogd.pcap"
+ sync=1
+ '';
+in {
+
+ systemd.services."${name}" = {
+ description = "Logging packet log from nftables";
+ wantedBy = [ "multi-user.target" ];
+
+ serviceConfig.User = "root";
+ serviceConfig.Type = "simple";
+
+ path = [ ulogd2 ];
+
+ serviceConfig.ExecStart = "${ulogd2}/bin/ulogd -c ${config}";
+ };
+}
diff --git a/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py b/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py
new file mode 100755
index 0000000..2b336f2
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/update_authorized_keys.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p python3Packages.ldap3
+
+from ldap3 import Server, Connection, LEVEL
+from ldap3.utils.dn import escape_rdn
+import getpass
+import logging
+from pathlib import Path
+import filecmp
+import os
+
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument("hostname", help="hostname")
+parser.add_argument("ldap_pass_file", type=Path, help="file containing lap password")
+
+header_warning = """
+################################### WARNING ####################################
+# This file was created automatically from LDAP database and *WILL* be
+# overwritten. If you need to add / remove keys make changes to
+# {}-admin group / members sshPublicKey attributes in LDAP and rerun
+# update_authorized_keys script
+################################################################################
+""".lstrip()
+
+def get_keys(connection: Connection, group: str):
+ c = connection
+
+ c.search(
+ search_base="ou=People,dc=hackerspace,dc=pl",
+ search_filter=(
+ "(&"
+ "(objectClass=hsMember)"
+ f"(memberOf=cn={escape_rdn(group)},ou=Group,dc=hackerspace,dc=pl)"
+ ")"
+ ),
+ search_scope=LEVEL,
+ attributes=["sshPublicKey"],
+ )
+
+ admin_keys = []
+ for entry in c.response:
+ attributes = entry["attributes"]
+ for key in entry["attributes"]["sshPublicKey"]:
+ yield key.strip()
+
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ args = parser.parse_args()
+
+ user = f"cn={escape_rdn(args.hostname)},ou=Boxen,dc=hackerspace,dc=pl"
+ password = args.ldap_pass_file.read_text().strip()
+
+ s = Server("ldap.hackerspace.pl", use_ssl=True)
+ with Connection(s, user=user, password=password, raise_exceptions=True) as c:
+ keys = list(get_keys(c, f"{args.hostname}-admin"))
+ if len(keys) < 2:
+ raise Exception("Less then two keys found - aborting")
+
+ ssh_dir = Path("/", "root", ".ssh")
+ ssh_dir.mkdir(mode=700, exist_ok=True)
+ ssh_dir.chmod(0o700)
+ new_file = ssh_dir.joinpath("authorized_keys_new")
+ old_file = ssh_dir.joinpath("authorized_keys")
+ try:
+ new_file.unlink()
+ except FileNotFoundError:
+ pass
+ new_file.write_bytes(
+ header_warning.format(args.hostname).encode() + b"\n".join(keys)
+ )
+ if not old_file.exists():
+ logging.info('Creating new "authorized_keys" file')
+ os.rename(new_file, old_file)
+ elif filecmp.cmp(new_file, old_file, shallow=False):
+ logging.info('Nothing changed - "authorized_keys" file is up to date')
+ new_file.unlink()
+ else:
+ logging.info('Keys changed - overwriting "authorized_keys" file')
+ os.rename(new_file, old_file)
diff --git a/hswaw/machines/customs.hackerspace.pl/zones/api.eye.fi b/hswaw/machines/customs.hackerspace.pl/zones/api.eye.fi
new file mode 100644
index 0000000..e4fae9a
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/zones/api.eye.fi
@@ -0,0 +1,15 @@
+$ORIGIN .
+$TTL 180
+api.eye.fi IN SOA customs.waw.hackerspace.pl. bofh.hackerspace.pl. (
+ 1474143278 ; serial
+ 1800 ; refresh (30 minutes)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 10800 ; minimum (3 hours)
+ )
+ NS customs.waw.hackerspace.pl.
+
+$ORIGIN api.eye.fi.
+$TTL 300
+
+@ IN A 10.10.3.10
diff --git a/hswaw/machines/customs.hackerspace.pl/zones/api.ustream.tv b/hswaw/machines/customs.hackerspace.pl/zones/api.ustream.tv
new file mode 100644
index 0000000..33e88f3
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/zones/api.ustream.tv
@@ -0,0 +1,15 @@
+$ORIGIN .
+$TTL 180
+api.ustream.tv IN SOA customs.waw.hackerspace.pl. bofh.hackerspace.pl. (
+ 1474143278 ; serial
+ 1800 ; refresh (30 minutes)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 10800 ; minimum (3 hours)
+ )
+ NS customs.waw.hackerspace.pl.
+
+$ORIGIN api.ustream.tv.
+$TTL 300
+
+@ IN A 10.8.0.151
diff --git a/hswaw/machines/customs.hackerspace.pl/zones/i b/hswaw/machines/customs.hackerspace.pl/zones/i
new file mode 100644
index 0000000..f77bcd2
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/zones/i
@@ -0,0 +1,15 @@
+$ORIGIN .
+$TTL 180
+i IN SOA customs.waw.hackerspace.pl. bofh.hackerspace.pl. (
+ 1474143278 ; serial
+ 1800 ; refresh (30 minutes)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 10800 ; minimum (3 hours)
+ )
+ NS customs.waw.hackerspace.pl.
+
+$ORIGIN i.
+$TTL 300
+
+@ IN A 10.8.1.38
diff --git a/hswaw/machines/customs.hackerspace.pl/zones/waw.hackerspace.pl b/hswaw/machines/customs.hackerspace.pl/zones/waw.hackerspace.pl
new file mode 100644
index 0000000..430ab75
--- /dev/null
+++ b/hswaw/machines/customs.hackerspace.pl/zones/waw.hackerspace.pl
@@ -0,0 +1,110 @@
+$ORIGIN .
+$TTL 180
+waw.hackerspace.pl IN SOA customs.hackerspace.pl. bofh.hackerspace.pl. (
+ 1621022198; serial
+ 1800 ; refresh (30 minutes)
+ 1800 ; retry (30 minutes)
+ 604800 ; expire (1 week)
+ 10800 ; minimum (3 hours)
+ )
+ NS customs.hackerspace.pl.
+
+$ORIGIN waw.hackerspace.pl.
+$TTL 300
+
+zbigniew A 10.8.1.1
+graphite CNAME zbigniew
+
+customs A 10.8.1.2
+customs AAAA 2a0d:eb00:4242::1
+at CNAME customs
+nat CNAME customs
+laser A 10.8.1.2
+
+craptrap A 10.8.1.15
+klangsmaschine A 10.8.1.16
+music CNAME klangsmaschine
+sound CNAME klangsmaschine
+mqtt CNAME klangsmaschine
+iot CNAME klangsmaschine
+spejsiot CNAME klangsmaschine
+wojtylexx CNAME klangsmaschine
+ac A 10.8.1.40 ; vuko's access control
+lights A 10.8.1.40 ; vuko's lights web interface
+parts A 10.8.1.40 ; vuko's electronics inventory
+printmaster A 10.8.1.17
+octoprint CNAME printmaster
+label CNAME printmaster
+ploter A 10.8.1.19
+papiez A 10.8.1.20
+dank A 10.8.1.21
+assbox A 10.8.1.22
+pap A 10.8.1.23
+dht01 A 10.8.1.25
+led A 10.8.1.26
+bridgeport A 10.8.1.29
+cnc CNAME bridgeport
+printers A 10.8.1.30
+telelele A 10.8.1.31
+vending A 10.8.1.32
+mate CNAME vending
+transcend A 10.8.1.33
+welcomer A 10.8.1.34
+inventory A 10.8.1.38
+i CNAME inventory
+camera A 10.8.1.39
+franciszek A 10.8.0.205
+
+freebsd A 10.8.1.41 ; mpts freebsd workshops
+ciscovoip A 10.8.1.42
+ripeatlas A 10.8.1.43
+ap01 A 10.8.1.44
+ap02 A 10.8.1.45
+ap03 A 10.8.1.46
+
+winbox A 10.8.1.48
+staszkecoin A 10.8.1.49
+sokul A 10.8.1.50
+blitzloop A 10.8.1.51
+tronxy A 10.8.1.52
+
+
+dht01api A 94.240.35.98
+
+ap1 A 10.8.3.11
+ap2 A 10.8.3.12
+ap3 A 10.8.3.13
+ap4 A 10.8.3.14
+
+voldemort A 10.8.0.204
+printer CNAME voldemort
+
+core01 A 10.10.1.10
+bladerunner A 10.10.1.12
+core02 A 10.10.1.13
+core03 A 10.10.1.14
+
+; wieloryb A 10.10.3.10
+wieloryb A 185.236.240.9
+ipxe CNAME wieloryb
+cluster CNAME wieloryb
+eyefi CNAME wieloryb
+home CNAME wieloryb
+kubernetes CNAME wieloryb
+
+; led A 94.240.35.98
+
+wh01.prod A 10.10.3.20
+wh02.prod A 10.10.3.21
+wh03.prod A 10.10.3.22
+
+ganeti A 10.10.4.10
+node1.ganeti A 10.10.4.11
+node2.ganeti A 10.10.4.12
+node3.ganeti A 10.10.4.13
+node4.ganeti A 10.10.4.14
+node5.ganeti A 10.10.4.15
+
+monitoring.vm A 10.10.3.11
+
+obsd.viq A 10.10.4.101
diff --git a/ops/machines.nix b/ops/machines.nix
index d0e6ae3..0a97bcd 100644
--- a/ops/machines.nix
+++ b/ops/machines.nix
@@ -52,6 +52,14 @@
sha256 = "1ak7jqx94fjhc68xh1lh35kh3w3ndbadprrb762qgvcfb8351x8v";
}) {};
+ # customs.hackerspace.pl migration temporary checkout
+ nixpkgsCustoms = import (pkgs.fetchFromGitHub {
+ owner = "nixos";
+ repo = "nixpkgs";
+ rev = "d12178b1c4a6ef1232c8c677573ba9db204e66ff";
+ sha256 = "0p7df7yzi35kblxr5ks0rxxp9cfh269g88xpj60sdhdjvfnn6cp7";
+ }) {};
+
# Stopgap measure to import //cluster/nix machine definitions into new
# //ops/ infrastructure.
#
@@ -143,4 +151,8 @@
../bgpwtf/machines/edge01.waw.bgp.wtf.nix
../bgpwtf/machines/edge01.waw.bgp.wtf-hardware.nix
];
+
+ "customs.hackerspace.pl" = mkMachine nixpkgsCustoms [
+ ../hswaw/machines/customs.hackerspace.pl/configuration.nix
+ ];
}