From 62f28d30a069135f9c48678507203958adfc334f Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Thu, 29 Sep 2016 13:51:44 +0300 Subject: Moved everything into ./modules --- modules/system/default.nix | 11 +++ modules/system/firewall.nix | 52 ++++++++++++++ modules/system/raid0.nix | 134 +++++++++++++++++++++++++++++++++++ modules/system/sysops.nix | 35 +++++++++ modules/system/users.nix | 83 ++++++++++++++++++++++ modules/system/worldWritableDirs.nix | 25 +++++++ 6 files changed, 340 insertions(+) create mode 100644 modules/system/default.nix create mode 100644 modules/system/firewall.nix create mode 100644 modules/system/raid0.nix create mode 100644 modules/system/sysops.nix create mode 100644 modules/system/users.nix create mode 100644 modules/system/worldWritableDirs.nix (limited to 'modules/system') diff --git a/modules/system/default.nix b/modules/system/default.nix new file mode 100644 index 0000000..240d970 --- /dev/null +++ b/modules/system/default.nix @@ -0,0 +1,11 @@ +{lib, ... }: + +let + all = lib.filterAttrs + ( n: _: n != "default.nix" && ! lib.hasPrefix "." n ) + (builtins.readDir ./.); + +in { + imports = map (p: ./. + "/${p}") ( builtins.attrNames all ); +} + diff --git a/modules/system/firewall.nix b/modules/system/firewall.nix new file mode 100644 index 0000000..289f635 --- /dev/null +++ b/modules/system/firewall.nix @@ -0,0 +1,52 @@ +{ config, lib, ... }: + +let + inherit (builtins) length toString replaceStrings; + inherit (lib) flatten concatMapStringsSep optionalString splitString mkOption; + inherit (lib.types) listOf int either submodule enum str; + + inherit (config.nixsap.system.firewall) whitelist; + + iptablesAllow = { dport, protocol, source, comment, ... }: + let + ports = concatMapStringsSep "," toString (flatten [dport]); + iptables = if 1 < length (splitString ":" source) + then "ip6tables" else "iptables"; + in "${iptables} -w -A nixos-fw -m multiport " + + "-p ${protocol} --dport ${ports} -s ${source} -j nixos-fw-accept" + + optionalString (comment != "") + " -m comment --comment '${replaceStrings ["'"] ["'\\''"] comment} '"; + +in { + options.nixsap.system.firewall.whitelist = mkOption { + description = "Inbound connection rules (whitelist)"; + default = []; + type = listOf (submodule { + options = { + dport = mkOption { + description = "Destination port or list of ports"; + type = either int (listOf int); + }; + source = mkOption { + description = "Source specification: a network IP address (with optional /mask)"; + type = str; + }; + protocol = mkOption { + description = "The network protocol"; + type = enum [ "tcp" "udp" ]; + default = "tcp"; + }; + comment = mkOption { + description = "Free-form comment"; + type = str; + default = ""; + }; + }; + }); + }; + + config = { + networking.firewall.extraCommands = + concatMapStringsSep "\n" iptablesAllow whitelist; + }; +} diff --git a/modules/system/raid0.nix b/modules/system/raid0.nix new file mode 100644 index 0000000..d260e29 --- /dev/null +++ b/modules/system/raid0.nix @@ -0,0 +1,134 @@ +{ config, pkgs, lib, ... }: + +with lib; +with lib.types; +with builtins; + +let + groups = filterAttrs (n: _: n != "_module") config.nixsap.system.lvm.raid0; + + createLV = vg: lv: s: opts: + let + new = toString s; + stripes = toString opts.stripes; + sizeSpec = if opts.units == "%" + then "--extents ${new}%VG" + else "--size ${new}${opts.units}"; + scale = { + "%" = "* 100 / $(vgs --unit b --noheadings --nosuffix --options vg_size ${vg})"; + "M" = "/ ${toString (1000 * 1000)}"; + "m" = "/ ${toString (1024 * 1024)}"; + "G" = "/ ${toString (1000 * 1000 * 1000)}"; + "g" = "/ ${toString (1024 * 1024 * 1024)}"; + "T" = "/ ${toString (1000 * 1000 * 1000 * 1000)}"; + "t" = "/ ${toString (1024 * 1024 * 1024 * 1024)}"; + }; + in pkgs.writeBashScript "raid0-create-${vg}-${lv}" '' + set -eu + device=/dev/${vg}/${lv} + + lv_size=$(lvs --unit b --noheadings --nosuffix --options lv_size "$device" || echo 0) + old=$(( lv_size ${scale."${opts.units}"} )) + + if (( ${new} == old )) ; then + exit 0 + elif (( old == 0 )); then + lvcreate ${vg} --name ${lv} ${sizeSpec} --stripes ${stripes} + elif (( ${new} < old )) ; then + echo "Cannot shrink volume $device from $old ${opts.units} to ${new} ${opts.units}" >&2 + exit 1 + else + lvextend "$device" ${sizeSpec} + resize2fs "$device" + fi + ''; + + createVG = vg: pv: pkgs.writeBashScript "raid0-create-vg-${vg}" '' + set -eu + for pv in ${toString pv}; do + type=$(blkid -p -s TYPE -o value "$pv" || true) + if [ "$type" != LVM2_member ]; then + pvcreate "$pv" + if ! vgs ${vg}; then + vgcreate ${vg} "$pv" + else + vgextend ${vg} "$pv" + fi + fi + done + ''; + + mkRaidService = vg: opts: + let + ExecStart = pkgs.writeBashScript "raid0-${vg}" '' + set -eu + ${createVG vg opts.physical} + ${concatStringsSep "\n" ( + mapAttrsToList (v: s: + "${createLV vg (baseNameOf v) s opts}") + opts.fileSystems + )} + vgchange -ay ${vg} + udevadm trigger --action=add + ''; + + in nameValuePair "raid0-${vg}" rec { + wantedBy = map (v: "dev-${vg}-${baseNameOf v}.device") (attrNames opts.fileSystems); + requires = map (pv: replaceStrings ["/"] ["-"] (removePrefix "/" pv) + ".device") opts.physical; + after = requires; + before = wantedBy; + unitConfig.DefaultDependencies = false; + path = with pkgs; [ utillinux lvm2 e2fsprogs ]; + serviceConfig = { + inherit ExecStart; + RemainAfterExit = true; + Type = "oneshot"; + }; + }; + +in { + options.nixsap.system = { + lvm.raid0 = mkOption { + description = "Set of LVM2 volume groups"; + default = {}; + type = attrsOf (submodule { + options = { + stripes = mkOption { + description = "Number of stripes"; + type = int; + example = 2; + }; + physical = mkOption { + description = "List of physical devices (must be even for stripes)"; + example = [ "/dev/sdb" "/dev/sdc" ]; + type = listOf path; + }; + fileSystems = mkOption { + description = "Filesystems and their sizes"; + type = attrsOf int; + example = { "/mariadb/db" = 100; }; + }; + units = mkOption { + description = "Units of size"; + type = enum [ "%" "m" "g" "t" "M" "G" "T"]; + }; + }; + }); + }; + }; + + config = { + systemd.services = mapAttrs' mkRaidService groups; + + fileSystems = foldl (a: b: a//b) {} ( + mapAttrsToList (vg: opts: genAttrs (attrNames opts.fileSystems) + (fs: { + fsType = "ext4"; + autoFormat = true; + device = "/dev/${vg}/${baseNameOf fs}"; + }) + ) groups + ); + }; +} + diff --git a/modules/system/sysops.nix b/modules/system/sysops.nix new file mode 100644 index 0000000..ccf6d0b --- /dev/null +++ b/modules/system/sysops.nix @@ -0,0 +1,35 @@ +{ config, lib, ...}: +let + + inherit (lib) concatMapStringsSep concatStringsSep mkOption types; + inherit (types) str listOf; + + bindir = "/run/current-system/sw/bin"; + + commands = concatStringsSep ", " ( + [ + "${bindir}/du *" + "${bindir}/iftop" + "${bindir}/iotop" + "${bindir}/ip6tables -L*" + "${bindir}/ipsec *" + "${bindir}/iptables -L*" + "${bindir}/journalctl *" + "${bindir}/lsof *" + "${bindir}/mtr *" + "${bindir}/nix-collect-garbage *" + "${bindir}/nmap *" + "${bindir}/tcpdump *" + "${bindir}/traceroute *" + ] ++ map (c: "${bindir}/systemctl ${c} *") + [ "kill" "reload" "restart" "start" "status" "stop" ] + ); + +in { + + config = { + security.sudo.extraConfig = '' + %wheel ALL=(ALL) NOPASSWD: ${commands} + ''; + }; +} diff --git a/modules/system/users.nix b/modules/system/users.nix new file mode 100644 index 0000000..022a7e7 --- /dev/null +++ b/modules/system/users.nix @@ -0,0 +1,83 @@ +{ config, pkgs, lib, ... }: + +let + + inherit (builtins) + genList hashString mul substring ; + + inherit (lib) + foldl genAttrs imap mkOption stringToCharacters toLower + types unique ; + + inherit (types) + listOf str ; + + uid = name: + let + dec = { + "0" = 0; "1" = 1; "2" = 2; "3" = 3; + "4" = 4; "5" = 5; "6" = 6; "7" = 7; + "8" = 8; "9" = 9; "a" = 10; "b" = 11; + "c" = 12; "d" = 13; "e" = 14; "f" = 15; + }; + base = 1000000000; # 2^32 > base + 16^7 + hex = toLower (substring 0 7 (hashString "sha1" name)); + pow = b: n: foldl mul 1 (genList (_: b) n); + digits = imap (i: d: {m = pow 16 (i - 1); d = d;}) (stringToCharacters hex); + f = a: {m, d}: a + m * dec.${d}; + + in foldl f base digits; + + daemons = config.nixsap.system.users.daemons; + normal = config.nixsap.system.users.normal; + groups = config.nixsap.system.groups; + + mkGroup = name: { gid = uid name; }; + mkDaemonUser = name: + { + isNormalUser = false; + uid = uid name; + group = name; + }; + + mkNormalUser = name: + { + isNormalUser = true; + uid = uid name; + }; + +in { + options.nixsap.system = { + users.daemons = mkOption { + type = listOf str; + description = "List of system users with automatic UID and group"; + default = []; + }; + users.normal = mkOption { + type = listOf str; + description = "List of regular users with automatic UID"; + default = []; + }; + users.sysops = mkOption { + description = '' + List of local users with special roles in applications or system-wide. + The users in this list are not create automatically. + ''; + type = listOf str; + default = []; + }; + groups = mkOption { + type = listOf str; + description = "List of groups with automatic GID"; + default = []; + }; + }; + + # XXX: Modules for automatic unicity of user names: + imports = [ + { users.groups = genAttrs (unique (daemons ++ groups)) mkGroup; } + { users.users = genAttrs daemons mkDaemonUser; } + { users.users = genAttrs normal mkNormalUser; } + ]; +} + diff --git a/modules/system/worldWritableDirs.nix b/modules/system/worldWritableDirs.nix new file mode 100644 index 0000000..9899696 --- /dev/null +++ b/modules/system/worldWritableDirs.nix @@ -0,0 +1,25 @@ +{ config, pkgs, lib, ... }: +let + dirs = config.nixsap.system.worldWritableDirs; + +in { + options.nixsap.system.worldWritableDirs = lib.mkOption { + type = lib.types.listOf lib.types.path; + description = "These dirs will be chmod'ed 1777"; + default = [ "/tmp" "/var/tmp" ]; + }; + + config = lib.mkIf (dirs != []) { + systemd.services.chmod1777 = { + description = "Make some dirs world-writable"; + unitConfig.RequiresMountsFor = dirs; + before = [ "local-fs.target" ]; + wantedBy = [ "local-fs.target" ]; + serviceConfig = { + ExecStart = "${pkgs.coreutils}/bin/chmod -c 1777 ${lib.concatStringsSep " " dirs}"; + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + }; +} -- cgit v1.2.3