From 864adfaa2b095ab4f4b58e23606ac4eed29b8737 Mon Sep 17 00:00:00 2001 From: "Dominique Martinet @ jormungand" Date: Sat, 31 Oct 2020 15:43:48 +0100 Subject: add matrirc --- machines/jormungand/configuration.nix | 1 + modules/services/stunnel.nix | 234 ++++++++++++++++++++++++++++++++++ pkgs/default.nix | 2 + pkgs/matrirc/default.nix | 25 ++++ profiles/common.nix | 3 + profiles/matrirc.nix | 51 ++++++++ 6 files changed, 316 insertions(+) create mode 100644 modules/services/stunnel.nix create mode 100644 pkgs/matrirc/default.nix create mode 100644 profiles/matrirc.nix diff --git a/machines/jormungand/configuration.nix b/machines/jormungand/configuration.nix index cc4c1c6..1fcd3b5 100644 --- a/machines/jormungand/configuration.nix +++ b/machines/jormungand/configuration.nix @@ -7,6 +7,7 @@ ./network.nix ../../profiles/ashuffle.nix ../../profiles/common.nix + ../../profiles/matrirc.nix ../../profiles/miniflux.nix ../../profiles/otp.nix ../../profiles/users.nix diff --git a/modules/services/stunnel.nix b/modules/services/stunnel.nix new file mode 100644 index 0000000..9dabcc5 --- /dev/null +++ b/modules/services/stunnel.nix @@ -0,0 +1,234 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.stunnel; + yesNo = val: if val then "yes" else "no"; + + verifyChainPathAssert = n: c: { + assertion = c.verifyHostname == null || (c.verifyChain || c.verifyPeer); + message = "stunnel: \"${n}\" client configuration - hostname verification " + + "is not possible without either verifyChain or verifyPeer enabled"; + }; + + serverConfig = { + options = { + accept = mkOption { + type = types.either types.str types.int; + description = "On which [host:]port stunnel should listen for incoming TLS connections."; + }; + + connect = mkOption { + type = types.int; + description = "To which port the decrypted connection should be forwarded."; + }; + + cert = mkOption { + type = types.path; + description = "File containing both the private and public keys."; + }; + }; + }; + + clientConfig = { + options = { + accept = mkOption { + type = types.str; + description = "IP:Port on which connections should be accepted."; + }; + + connect = mkOption { + type = types.str; + description = "IP:Port destination to connect to."; + }; + + verifyChain = mkOption { + type = types.bool; + default = true; + description = "Check if the provided certificate has a valid certificate chain (against CAPath)."; + }; + + verifyPeer = mkOption { + type = types.bool; + default = false; + description = "Check if the provided certificate is contained in CAPath."; + }; + + CAPath = mkOption { + type = types.nullOr types.path; + default = null; + description = "Path to a directory containing certificates to validate against."; + }; + + CAFile = mkOption { + type = types.nullOr types.path; + default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; + description = "Path to a file containing certificates to validate against."; + }; + + verifyHostname = mkOption { + type = with types; nullOr str; + default = null; + description = "If set, stunnel checks if the provided certificate is valid for the given hostname."; + }; + }; + }; + + +in + +{ + + ###### interface + + options = { + + services.stunnel = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the stunnel TLS tunneling service."; + }; + + user = mkOption { + type = with types; nullOr str; + default = "nobody"; + description = "The user under which stunnel runs."; + }; + + group = mkOption { + type = with types; nullOr str; + default = "nogroup"; + description = "The group under which stunnel runs."; + }; + + logLevel = mkOption { + type = types.enum [ "emerg" "alert" "crit" "err" "warning" "notice" "info" "debug" ]; + default = "info"; + description = "Verbosity of stunnel output."; + }; + + fipsMode = mkOption { + type = types.bool; + default = false; + description = "Enable FIPS 140-2 mode required for compliance."; + }; + + enableInsecureSSLv3 = mkOption { + type = types.bool; + default = false; + description = "Enable support for the insecure SSLv3 protocol."; + }; + + + servers = mkOption { + description = "Define the server configuations."; + type = with types; attrsOf (submodule serverConfig); + example = { + fancyWebserver = { + enable = true; + accept = 443; + connect = 8080; + cert = "/path/to/pem/file"; + }; + }; + default = { }; + }; + + clients = mkOption { + description = "Define the client configurations."; + type = with types; attrsOf (submodule clientConfig); + example = { + foobar = { + accept = "0.0.0.0:8080"; + connect = "nixos.org:443"; + verifyChain = false; + }; + }; + default = { }; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + assertions = concatLists [ + (singleton { + assertion = (length (attrValues cfg.servers) != 0) || ((length (attrValues cfg.clients)) != 0); + message = "stunnel: At least one server- or client-configuration has to be present."; + }) + + (mapAttrsToList verifyChainPathAssert cfg.clients) + ]; + + environment.systemPackages = [ pkgs.stunnel ]; + + environment.etc."stunnel.cfg".text = '' + ${ if cfg.user != null then "setuid = ${cfg.user}" else "" } + ${ if cfg.group != null then "setgid = ${cfg.group}" else "" } + + debug = ${cfg.logLevel} + + ${ optionalString cfg.fipsMode "fips = yes" } + ${ optionalString cfg.enableInsecureSSLv3 "options = -NO_SSLv3" } + + ; ----- SERVER CONFIGURATIONS ----- + ${ lib.concatStringsSep "\n" + (lib.mapAttrsToList + (n: v: '' + [${n}] + accept = ${toString v.accept} + connect = ${toString v.connect} + cert = ${v.cert} + + '') + cfg.servers) + } + + ; ----- CLIENT CONFIGURATIONS ----- + ${ lib.concatStringsSep "\n" + (lib.mapAttrsToList + (n: v: '' + [${n}] + client = yes + accept = ${v.accept} + connect = ${v.connect} + verifyChain = ${yesNo v.verifyChain} + verifyPeer = ${yesNo v.verifyPeer} + ${optionalString (v.CAPath != null) "CApath = ${v.CAPath}"} + ${optionalString (v.CAFile != null) "CAFile = ${v.CAFile}"} + ${optionalString (v.verifyHostname != null) "checkHost = ${v.verifyHostname}"} + OCSPaia = yes + + '') + cfg.clients) + } + ''; + + systemd.services.stunnel = { + description = "stunnel TLS tunneling service"; + after = [ "network.target" ]; + wants = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ config.environment.etc."stunnel.cfg".source ]; + serviceConfig = { + ExecStart = "${pkgs.stunnel}/bin/stunnel ${config.environment.etc."stunnel.cfg".source}"; + Type = "forking"; + }; + }; + + meta.maintainers = with maintainers; [ + # Server side + lschuermann + # Client side + das_j + ]; + }; + +} diff --git a/pkgs/default.nix b/pkgs/default.nix index 5e48de4..55bb45c 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -34,6 +34,8 @@ self: super: { ganesha = super.callPackage ./ganesha { }; + matrirc = super.callPackage ./matrirc { }; + robinhood-v3 = super.callPackage ./robinhood-v3 { }; robinhood = super.callPackage ./robinhood { }; diff --git a/pkgs/matrirc/default.nix b/pkgs/matrirc/default.nix new file mode 100644 index 0000000..6bde054 --- /dev/null +++ b/pkgs/matrirc/default.nix @@ -0,0 +1,25 @@ +{ stdenv, rustPlatform, fetchFromGitHub, + pkgconfig, openssl +}: + +rustPlatform.buildRustPackage rec { + pname = "matrirc"; + version = "0.0.0"; + src = fetchFromGitHub { + owner = "martinetd"; + repo = "matrirc"; + rev = "b286f39006435023d64cb31e78d5c87609aa57ec"; + sha256 = "0msl3y5pgx4nsj6z7xfxjfhgbpif55g02f91zvprqhf479aclm71"; + }; + cargoSha256 = "1ch48zcdkxz4sv4pmgmmx9s9cc6xsdmk058z1q8flj56xnwxq3fh"; + + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ openssl ]; + + meta = with stdenv.lib; { + description = "Yet another irc to matrix gateway"; + license = licenses.wtfpl; + maintainers = [ maintainers.asmadeus ]; + platforms = platforms.all; + }; +} diff --git a/profiles/common.nix b/profiles/common.nix index 55bca1e..07a6c61 100644 --- a/profiles/common.nix +++ b/profiles/common.nix @@ -22,6 +22,9 @@ in { imports = findFiles ".*\\.nix" ../modules ++ [ ./hardened.nix ]; + disabledModules = [ + "services/networking/stunnel.nix" + ]; # less locales supported i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ]; diff --git a/profiles/matrirc.nix b/profiles/matrirc.nix new file mode 100644 index 0000000..681cb97 --- /dev/null +++ b/profiles/matrirc.nix @@ -0,0 +1,51 @@ +{ config, pkgs, ... }: + +{ + users.users.matrirc.isSystemUser = true; + systemd.services.matrirc = { + description = "matrirc service"; + serviceConfig = { + BindReadOnlyPaths = [ + "/etc/ssl/certs/ca-certificates.crt" + ]; + Type = "simple"; + User = "matrirc"; + EnvironmentFile = "/etc/nixos/secrets/matrirc"; + StateDirectory = "matrirc"; + ExecStart = "${pkgs.matrirc}/bin/matrirc"; + Restart = "always"; + NoNewPrivileges = "yes"; + }; + wantedBy = [ "default.target" ]; + confinement = { + enable = true; + binSh = null; + mode = "chroot-only"; + }; + }; + + services.stunnel = { + enable = true; + servers = { + bitlbee = { + accept = ":::16697"; + connect = 16667; + cert = "/var/lib/acme/jormungand.codewreck.org/full.pem"; + }; + }; + }; + systemd.services.stunnel = { + serviceConfig.BindReadOnlyPaths = [ + "/var/lib/acme/jormungand.codewreck.org/full.pem" + "/dev/null" "/etc/passwd" "/etc/group" + ]; + confinement = { + enable = true; + binSh = null; + mode = "chroot-only"; + }; + }; + networking.firewall.extraCommands = '' + ip6tables -A nixos-fw -p tcp -m tcp --dport 16697 -s 2001:41d0:1:7a93::1 -j ACCEPT + ''; +} -- cgit v1.2.1-2-g3f67