summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--machines/jormungand/configuration.nix1
-rw-r--r--modules/services/stunnel.nix234
-rw-r--r--pkgs/default.nix2
-rw-r--r--pkgs/matrirc/default.nix25
-rw-r--r--profiles/common.nix3
-rw-r--r--profiles/matrirc.nix51
6 files changed, 316 insertions, 0 deletions
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
+ '';
+}