diff options
author | tv <tv@krebsco.de> | 2015-03-05 13:01:05 +0100 |
---|---|---|
committer | tv <tv@krebsco.de> | 2015-05-19 23:10:57 +0200 |
commit | f52e3eb5b94b8cffcc2b57f4604aac2e9402be39 (patch) | |
tree | e34e330c04beb0822d59da3f43b0a1e32c06b582 /modules |
initial commit
Diffstat (limited to 'modules')
-rw-r--r-- | modules/base.nix | 17 | ||||
-rw-r--r-- | modules/exim.nix | 122 | ||||
-rw-r--r-- | modules/hosts.nix | 25 | ||||
-rw-r--r-- | modules/iptables.nix | 69 | ||||
-rw-r--r-- | modules/nginx.nix | 30 | ||||
-rw-r--r-- | modules/retiolum.nix | 224 | ||||
-rw-r--r-- | modules/tools.nix | 101 | ||||
-rw-r--r-- | modules/urxvt.nix | 24 | ||||
-rw-r--r-- | modules/users.nix | 226 | ||||
-rw-r--r-- | modules/xserver.nix | 51 |
10 files changed, 889 insertions, 0 deletions
diff --git a/modules/base.nix b/modules/base.nix new file mode 100644 index 0000000..76c8b89 --- /dev/null +++ b/modules/base.nix @@ -0,0 +1,17 @@ +{ config, pkgs, ... }: + +{ + time.timeZone = "Europe/Berlin"; + + nix.maxJobs = 8; + nix.useChroot = true; + # TODO check if both are required: + nix.chrootDirs = [ "/etc/protocols" pkgs.iana_etc.outPath ]; + + nix.trustedBinaryCaches = [ + "https://cache.nixos.org" + "http://cache.nixos.org" + "http://hydra.nixos.org" + ]; + +} diff --git a/modules/exim.nix b/modules/exim.nix new file mode 100644 index 0000000..4a0232c --- /dev/null +++ b/modules/exim.nix @@ -0,0 +1,122 @@ +{ config, pkgs, ... }: + +{ + services.exim = + let + retiolumHostname = "wu.retiolum"; # TODO "${networking.hostName}.retiolum"; + in + { enable = true; + config = '' + primary_hostname = ${retiolumHostname} + domainlist local_domains = @ : localhost + domainlist relay_to_domains = *.retiolum + hostlist relay_from_hosts = <; 127.0.0.1 ; ::1 + + acl_smtp_rcpt = acl_check_rcpt + acl_smtp_data = acl_check_data + + host_lookup = * + rfc1413_hosts = * + rfc1413_query_timeout = 5s + + log_file_path = syslog + syslog_timestamp = false + syslog_duplication = false + + begin acl + + acl_check_rcpt: + accept hosts = : + control = dkim_disable_verify + + deny message = Restricted characters in address + domains = +local_domains + local_parts = ^[.] : ^.*[@%!/|] + + deny message = Restricted characters in address + domains = !+local_domains + local_parts = ^[./|] : ^.*[@%!] : ^.*/\\.\\./ + + accept local_parts = postmaster + domains = +local_domains + + #accept + # hosts = *.retiolum + # domains = *.retiolum + # control = dkim_disable_verify + + #require verify = sender + + accept hosts = +relay_from_hosts + control = submission + control = dkim_disable_verify + + accept authenticated = * + control = submission + control = dkim_disable_verify + + require message = relay not permitted + domains = +local_domains : +relay_to_domains + + require verify = recipient + + accept + + + acl_check_data: + accept + + + begin routers + + retiolum: + driver = manualroute + domains = ! ${retiolumHostname} : *.retiolum + transport = remote_smtp + route_list = ^.* $0 byname + no_more + + nonlocal: + debug_print = "R: nonlocal for $local_part@$domain" + driver = redirect + domains = ! +local_domains + allow_fail + data = :fail: Mailing to remote domains not supported + no_more + + local_user: + # debug_print = "R: local_user for $local_part@$domain" + driver = accept + check_local_user + # local_part_suffix = +* : -* + # local_part_suffix_optional + transport = home_maildir + cannot_route_message = Unknown user + + + begin transports + + remote_smtp: + driver = smtp + + home_maildir: + driver = appendfile + maildir_format + directory = $home/Maildir + directory_mode = 0700 + delivery_date_add + envelope_to_add + return_path_add + # group = mail + # mode = 0660 + + begin retry + *.retiolum * F,42d,1m + * * F,2h,15m; G,16h,1h,1.5; F,4d,6h + + begin rewrite + + begin authenticators + ''; + }; +} diff --git a/modules/hosts.nix b/modules/hosts.nix new file mode 100644 index 0000000..f59f87c --- /dev/null +++ b/modules/hosts.nix @@ -0,0 +1,25 @@ +{ config, pkgs, ... }: + +{ + networking.extraHosts = + '' + 192.168.1.1 wrt.gg23 wrt + 192.168.1.11 mors.gg23 + 192.168.1.12 uriel.gg23 + 192.168.1.23 raspi.gg23 raspi + 192.168.1.37 wu.gg23 + 192.168.1.110 nomic.gg23 + 192.168.1.124 schnabeldrucker.gg23 schnabeldrucker + + 127.0.0.1 dev.zalora.sg www.dev.zalora.sg bob.dev.zalora.sg static.dev.zalora.sg + 127.0.0.1 dev.zalora.com.my www.dev.zalora.com.my bob.dev.zalora.com.my static.dev.zalora.com.my + 127.0.0.1 dev.zalora.com.ph www.dev.zalora.com.ph bob.dev.zalora.com.ph static.dev.zalora.com.ph + 127.0.0.1 dev.zalora.vn www.dev.zalora.vn bob.dev.zalora.vn static.dev.zalora.vn + 127.0.0.1 dev.zalora.co.id www.dev.zalora.co.id bob.dev.zalora.co.id static.dev.zalora.co.id + 127.0.0.1 dev.zalora.co.th www.dev.zalora.co.th bob.dev.zalora.co.th static.dev.zalora.co.th + 127.0.0.1 dev.zalora.com.hk www.dev.zalora.com.hk bob.dev.zalora.com.hk static.dev.zalora.com.hk + + 54.93.104.95 eu-dev.hk.zalora.net www.eu-dev.hk.zalora.net bob.eu-dev.hk.zalora.net static.eu-dev.hk.zalora.net + 54.93.104.95 eu-dev.sg.zalora.net www.eu-dev.sg.zalora.net bob.eu-dev.sg.zalora.net static.eu-dev.sg.zalora.net + ''; +} diff --git a/modules/iptables.nix b/modules/iptables.nix new file mode 100644 index 0000000..ee40343 --- /dev/null +++ b/modules/iptables.nix @@ -0,0 +1,69 @@ +{ config, pkgs, ... }: + +{ + # + # iptables + # + networking.firewall.enable = false; + system.activationScripts.iptables = + let + log = false; + when = c: f: if c then f else ""; + in + '' + ip4tables() { ${pkgs.iptables}/sbin/iptables "$@"; } + ip6tables() { ${pkgs.iptables}/sbin/ip6tables "$@"; } + ipXtables() { ip4tables "$@"; ip6tables "$@"; } + + # + # nat + # + + # reset tables + ipXtables -t nat -F + ipXtables -t nat -X + + # + ipXtables -t nat -A PREROUTING -j REDIRECT ! -i retiolum -p tcp --dport ssh --to-ports 0 + ipXtables -t nat -A PREROUTING -j REDIRECT -p tcp --dport 11423 --to-ports ssh + + # + # filter + # + + # reset tables + ipXtables -P INPUT DROP + ipXtables -P FORWARD DROP + ipXtables -F + ipXtables -X + + # create custom chains + ipXtables -N Retiolum + + # INPUT + ipXtables -A INPUT -j ACCEPT -m conntrack --ctstate RELATED,ESTABLISHED + ipXtables -A INPUT -j ACCEPT -i lo + ipXtables -A INPUT -j ACCEPT -p tcp --dport ssh -m conntrack --ctstate NEW + ipXtables -A INPUT -j ACCEPT -p tcp --dport http -m conntrack --ctstate NEW + ipXtables -A INPUT -j ACCEPT -p tcp --dport tinc -m conntrack --ctstate NEW + ipXtables -A INPUT -j ACCEPT -p tcp --dport smtp -m conntrack --ctstate NEW + ipXtables -A INPUT -j Retiolum -i retiolum + ${when log "ipXtables -A INPUT -j LOG --log-level info --log-prefix 'INPUT DROP '"} + + # FORWARD + ${when log "ipXtables -A FORWARD -j LOG --log-level info --log-prefix 'FORWARD DROP '"} + + # Retiolum + ip4tables -A Retiolum -j ACCEPT -p icmp --icmp-type echo-request + ip6tables -A Retiolum -j ACCEPT -p ipv6-icmp -m icmp6 --icmpv6-type echo-request + + + ${when log "ipXtables -A Retiolum -j LOG --log-level info --log-prefix 'REJECT '"} + ipXtables -A Retiolum -j REJECT -p tcp --reject-with tcp-reset + ip4tables -A Retiolum -j REJECT -p udp --reject-with icmp-port-unreachable + ip4tables -A Retiolum -j REJECT --reject-with icmp-proto-unreachable + ip6tables -A Retiolum -j REJECT -p udp --reject-with icmp6-port-unreachable + ip6tables -A Retiolum -j REJECT + + ''; +} diff --git a/modules/nginx.nix b/modules/nginx.nix new file mode 100644 index 0000000..8b42061 --- /dev/null +++ b/modules/nginx.nix @@ -0,0 +1,30 @@ +{ config, pkgs, ... }: + +{ + services.nginx = + let + name = config.networking.hostName; + qname = "${name}.retiolum"; + in + { + enable = true; + httpConfig = '' + sendfile on; + server { + listen 80; + server_name ${name} ${qname} localhost; + root /srv/http/${name}; + location ~ ^/~(.+?)(/.*)?$ { + alias /home/$1/public_html$2; + } + } + types { + text/css css; + text/html html; + image/svg+xml svg; + } + default_type text/html; + charset utf-8; + ''; + }; +} diff --git a/modules/retiolum.nix b/modules/retiolum.nix new file mode 100644 index 0000000..4011216 --- /dev/null +++ b/modules/retiolum.nix @@ -0,0 +1,224 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + + ###### interface + + options = { + services.retiolum = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable tinc daemon for Retiolum."; + }; + + name = mkOption { + type = types.string; + default = config.networking.hostName; + # Description stolen from tinc.conf(5). + description = '' + This is the name which identifies this tinc daemon. It must + be unique for the virtual private network this daemon will + connect to. The Name may only consist of alphanumeric and + underscore characters. If Name starts with a $, then the + contents of the environment variable that follows will be + used. In that case, invalid characters will be converted to + underscores. If Name is $HOST, but no such environment + variable exist, the hostname will be read using the + gethostnname() system call This is the name which identifies + the this tinc daemon. + ''; + }; + + generateEtcHosts = mkOption { + type = types.string; + default = "both"; + description = '' + If set to <literal>short</literal>, <literal>long</literal>, or <literal>both</literal>, + then generate entries in <filename>/etc/hosts</filename> from subnets. + ''; + }; + + network = mkOption { + type = types.string; + default = "retiolum"; + description = '' + The tinc network name. + It is used to generate long host entries, + derive the name of the user account under which tincd runs, + and name the TUN device. + ''; + }; + + tincPackage = mkOption { + type = types.package; + default = pkgs.tinc; + description = "Tincd package to use."; + }; + + hosts = mkOption { + default = null; + description = '' + Hosts package or path to use. + If a path is given, then it will be used to generate an ad-hoc package. + ''; + }; + + iproutePackage = mkOption { + type = types.package; + default = pkgs.iproute; + description = "Iproute2 package to use."; + }; + + + privateKeyFile = mkOption { + # TODO if it's types.path then it gets copied to /nix/store with + # bad unsafe permissions... + type = types.string; + default = "/etc/tinc/retiolum/rsa_key.priv"; + description = "Generate file with <literal>tincd -K</literal>."; + }; + + connectTo = mkOption { + type = types.listOf types.string; + default = [ "fastpoke" "pigstarter" "kheurop" ]; + description = "TODO describe me"; + }; + + }; + }; + + + ###### implementation + + config = + let + cfg = config.services.retiolum; + tinc = cfg.tincPackage; + hostsType = builtins.typeOf cfg.hosts; + hosts = + if hostsType == "package" then + # use package as is + cfg.hosts + else if hostsType == "path" then + # use path to generate a package + pkgs.stdenv.mkDerivation { + name = "custom-retiolum-hosts"; + src = cfg.hosts; + installPhase = '' + mkdir $out + find . -name .git -prune -o -type f -print0 | xargs -0 cp --target-directory $out + ''; + } + else + abort "The option `services.retiolum.hosts' must be set to a package or a path" + ; + iproute = cfg.iproutePackage; + + retiolumExtraHosts = import (pkgs.runCommand "retiolum-etc-hosts" + { } + '' + generate() { + (cd ${hosts} + printf \'\' + for i in `ls`; do + sed -En ' + s|^ *Subnet *= *([^ /]*)(/[0-9]*)? *$|\1 '"$(hostnames $i)"'|p + ' $i + done | sort + printf \'\' + ) + } + + case ${cfg.generateEtcHosts} in + short) + hostnames() { echo "$1"; } + generate + ;; + long) + hostnames() { echo "$1.${cfg.network}"; } + generate + ;; + both) + hostnames() { echo "$1.${cfg.network} $1"; } + generate + ;; + *) + echo '""' + ;; + esac > $out + ''); + + + confDir = pkgs.runCommand "retiolum" { + # TODO text + executable = true; + preferLocalBuild = true; + } '' + set -euf + + mkdir -p $out + + ln -s ${hosts} $out/hosts + + cat > $out/tinc.conf <<EOF + Name = ${cfg.name} + Device = /dev/net/tun + Interface = ${cfg.network} + ${concatStrings (map (c : "ConnectTo = " + c + "\n") cfg.connectTo)} + PrivateKeyFile = ${cfg.privateKeyFile} + EOF + + # source: krebscode/painload/retiolum/scripts/tinc_setup/tinc-up + cat > $out/tinc-up <<EOF + host=$out/hosts/${cfg.name} + ${iproute}/sbin/ip link set \$INTERFACE up + + addr4=\$(sed -n 's|^ *Subnet *= *\(10[.][^ ]*\) *$|\1|p' \$host) + if [ -n "\$addr4" ];then + ${iproute}/sbin/ip -4 addr add \$addr4 dev \$INTERFACE + ${iproute}/sbin/ip -4 route add 10.243.0.0/16 dev \$INTERFACE + fi + addr6=\$(sed -n 's|^ *Subnet *= *\(42[:][^ ]*\) *$|\1|p' \$host) + ${iproute}/sbin/ip -6 addr add \$addr6 dev \$INTERFACE + ${iproute}/sbin/ip -6 route add 42::/16 dev \$INTERFACE + EOF + + chmod +x $out/tinc-up + ''; + + + user = cfg.network + "-tinc"; + + in + + mkIf cfg.enable { + environment.systemPackages = [ tinc hosts iproute ]; + + networking.extraHosts = retiolumExtraHosts; + + systemd.services.retiolum = { + description = "Tinc daemon for Retiolum"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ tinc iproute ]; + serviceConfig = { + # TODO we cannot chroot (-R) b/c we use symlinks to hosts + # and the private key. + ExecStart = "${tinc}/sbin/tincd -c ${confDir} -d 0 -U ${user} -D"; + SyslogIdentifier = "retiolum-tincd"; + }; + restartIfChanged = true; + }; + + users.extraUsers = singleton { + name = user; + uid = 42; # TODO config.ids.uids.retiolum + }; + + }; + +} diff --git a/modules/tools.nix b/modules/tools.nix new file mode 100644 index 0000000..4be84a6 --- /dev/null +++ b/modules/tools.nix @@ -0,0 +1,101 @@ +{ config, pkgs, ... }: + +let + inherit (pkgs) lib stdenv; + inherit (lib.strings) concatStringsSep stringAsChars; + inherit (lib.attrsets) attrValues mapAttrs; + inherit (lib) makeSearchPath; + inherit (import ../lib { inherit pkgs; }) shell-escape; + + + # TODO make these scripts available in an maintenance shell + + + scripts = { + + # just so we don't reboot accidentally + reboot = + '' + echo no reboot >&2 + exit 23 + ''; + + rebuild = + '' + nixpkgs=''${nixpkgs-/home/tv/src/nixpkgs} + nixos-rebuild \ + --show-trace \ + -I nixpkgs="$nixpkgs" \ + switch \ + 2>&1 \ + | sed ${shell-escape '' + s|"\(/home/tv/src/config/[^":]*\)"|[31;1m\1[m| + s|^trace:\s*\(.*\)|[35;1m\1[m| + ''} + ''; + + }; + + wrap = script: + '' + #! /bin/sh + set -euf + ${script} + ''; + #lib=$lib + #export PATH=$bin:${makeSearchPath "bin" buildInputs} + + buildScript = name: script: + builtins.trace "building ${name}" + '' + echo ${shell-escape script} > $bin/${shell-escape name} + chmod +x $bin/${shell-escape name} + ''; + + + + tools = pkgs.stdenv.mkDerivation rec { + name = "tools"; + src = /var/empty; + + buildInputs = []; + + + buildPhase = + '' + mkdir $out + + bin=$out/bin + mkdir $bin + + ${concatStringsSep "\n" (attrValues (mapAttrs buildScript scripts))} + + ''; + #'' + #mkdir $out + + #lib=$out/lib + #cp -r lib $lib + + #bin=$out/bin + #mkdir $bin + #${concatStringsSep "\n" (attrValues (mapAttrs (name: script: + # '' + # { + # echo '#! /bin/sh' + # echo 'set -euf' + # echo "lib=$lib" + # echo "export PATH=$bin:${makeSearchPath "bin" buildInputs}" + # echo ${shell-escape script} + # } > $bin/${name} + # chmod +x $bin/${name} + # '') scripts))} + #''; + installPhase = ":"; + }; + +in + +{ + environment.systemPackages = [ tools ]; +} diff --git a/modules/urxvt.nix b/modules/urxvt.nix new file mode 100644 index 0000000..a975812 --- /dev/null +++ b/modules/urxvt.nix @@ -0,0 +1,24 @@ +{ pkgs, ... }: + + with builtins; + +let + users = [ "tv" ]; + urxvt = pkgs.rxvt_unicode; + mkService = user: { + description = "urxvt terminal daemon"; + wantedBy = [ "multi-user.target" ]; + restartIfChanged = false; + serviceConfig = { + Restart = "always"; + User = user; + ExecStart = "${urxvt}/bin/urxvtd"; + }; + }; + +in + +{ + environment.systemPackages = [ urxvt ]; + systemd.services = listToAttrs (map (u: { name = "${u}-urxvtd"; value = mkService u; }) users); +} diff --git a/modules/users.nix b/modules/users.nix new file mode 100644 index 0000000..eec1def --- /dev/null +++ b/modules/users.nix @@ -0,0 +1,226 @@ +{ config, pkgs, ... }: + +let + inherit (builtins) attrValues; + inherit (pkgs.lib) concatMap filterAttrs mapAttrs concatStringsSep; + + + users = { + tv = { + uid = 1337; + group = "users"; + extraGroups = [ + "audio" + "video" + "wheel" + ]; + }; + + ff = { + uid = 13378001; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + ]; + }; + + cr = { + uid = 13378002; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + "bumblebee" + ]; + }; + + vimb = { + uid = 13378003; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + "bumblebee" + ]; + }; + + fa = { + uid = 2300001; + group = "tv-sub"; + }; + + rl = { + uid = 2300002; + group = "tv-sub"; + }; + + btc-bitcoind = { + uid = 2301001; + group = "tv-sub"; + }; + + btc-electrum = { + uid = 2301002; + group = "tv-sub"; + }; + + ltc-litecoind = { + uid = 2301101; + group = "tv-sub"; + }; + + eth = { + uid = 2302001; + group = "tv-sub"; + }; + + emse-hsdb = { + uid = 4200101; + group = "tv-sub"; + }; + + wine = { + uid = 13370400; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + "bumblebee" + ]; + }; + + # dwarffortress + df = { + uid = 13370401; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + "bumblebee" + ]; + }; + + # XXX visudo: Warning: Runas_Alias `FTL' referenced but not defined + FTL = { + uid = 13370402; + #group = "tv-sub"; + extraGroups = [ + "audio" + "video" + "bumblebee" + ]; + }; + + freeciv = { + uid = 13370403; + group = "tv-sub"; + }; + + xr = { + uid = 13370061; + group = "tv-sub"; + extraGroups = [ + "audio" + "video" + ]; + }; + + "23" = { + uid = 13370023; + group = "tv-sub"; + }; + + electrum = { + uid = 13370102; + group = "tv-sub"; + }; + + Reaktor = { + uid = 4230010; + group = "tv-sub"; + }; + + gitolite = { + uid = 7700; + }; + + skype = { + uid = 6660001; + group = "tv-sub"; + extraGroups = [ + "audio" + ]; + }; + + onion = { + uid = 6660010; + group = "tv-sub"; + }; + + zalora = { + uid = 1000301; + group = "tv-sub"; + extraGroups = [ + "audio" + # TODO remove vboxusers when hardening is active + "vboxusers" + "video" + ]; + }; + + }; + + + extraUsers = + mapAttrs (name: user: user // { + inherit name; + home = "/home/${name}"; + createHome = true; + useDefaultShell = true; + }) users; + + + extraGroups = { + tv-sub.gid = 1337; + }; + + + sudoers = + let + inherit (builtins) filter hasAttr; + inherit (import ../lib { inherit pkgs; }) concat isSuffixOf removeSuffix setToList; + + hasMaster = { group ? "", ... }: + isSuffixOf "-sub" group; + + masterOf = user : removeSuffix "-sub" user.group; + in + concatStringsSep "\n" + (map (u: "${masterOf u} ALL=(${u.name}) NOPASSWD: ALL") + (filter hasMaster (attrValues extraUsers))); + +in + + +{ + imports = [ + <secrets/hashedPasswords.nix> + ]; + + users.defaultUserShell = "/run/current-system/sw/bin/bash"; + users.extraGroups = extraGroups; + users.extraUsers = extraUsers; + users.mutableUsers = false; + + #security.sudo.configFile = sudoers config.users.extraUsers; + security.sudo.configFile = + with builtins; trace + '' + OK + '' + sudoers; + security.sudo.extraConfig = '' + Defaults mailto="tv@wu.retiolum" + ''; +} diff --git a/modules/xserver.nix b/modules/xserver.nix new file mode 100644 index 0000000..c652018 --- /dev/null +++ b/modules/xserver.nix @@ -0,0 +1,51 @@ +{ config, pkgs, ... }: + +{ + services.xserver.enable = true; + + + #fonts.enableFontConfig = true; + #fonts.enableFontDir = true; + fonts.fonts = [ + pkgs.xlibs.fontschumachermisc + ]; + #services.xfs.enable = true; + #services.xserver.useXFS = "unix/:7100"; + + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; + + #services.xserver.display = 11; + #services.xserver.tty = 11; + # services.xserver.layout = "us"; + # services.xserver.xkbOptions = "eurosign:e"; + + # TODO this is host specific + services.xserver.synaptics = { + enable = true; + twoFingerScroll = true; + accelFactor = "0.035"; + additionalOptions = '' + Option "FingerHigh" "60" + Option "FingerLow" "60" + ''; + }; + + #services.xserver.multitouch.enable = true; + + services.xserver.windowManager.xmonad.extraPackages = hspkgs: with hspkgs; [ + X11-xshape + ]; + services.xserver.windowManager.xmonad.enable = true; + services.xserver.windowManager.xmonad.enableContribAndExtras = true; + services.xserver.windowManager.default = "xmonad"; + services.xserver.desktopManager.default = "none"; + services.xserver.desktopManager.xterm.enable = false; + + services.xserver.displayManager.slim.enable = true; + #services.xserver.displayManager.auto.enable = true; + #services.xserver.displayManager.auto.user = "tv"; + #services.xserver.displayManager.job.logsXsession = true; + + + services.xserver.vaapiDrivers = [ pkgs.vaapiIntel ]; +} |