From d3c4de5aebf938c4889d440cd53a5c0dec53da4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tristan=20Dani=C3=ABl=20Maat?= Date: Wed, 12 Oct 2022 19:58:09 +0100 Subject: [PATCH] webserver: Use a hardened systemd unit instead of a container --- configuration/default.nix | 16 -- configuration/services/webserver.nix | 57 ++----- flake.lock | 39 +---- flake.nix | 10 +- modules/virtualisation/pods.nix | 222 --------------------------- 5 files changed, 17 insertions(+), 327 deletions(-) delete mode 100644 modules/virtualisation/pods.nix diff --git a/configuration/default.nix b/configuration/default.nix index 7e94105..24f9ac7 100644 --- a/configuration/default.nix +++ b/configuration/default.nix @@ -66,22 +66,6 @@ recommendedProxySettings = true; clientMaxBodySize = "10G"; domain = "tlater.net"; - - virtualHosts = let - proxyPassToPort = port: extra: - lib.recursiveUpdate { - forceSSL = true; - enableACME = true; - locations."/".proxyPass = "http://127.0.0.1:${toString port}"; - extraConfig = '' - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - ''; - } - extra; - domain = config.services.nginx.domain; - in { - "${domain}" = proxyPassToPort 3002 {serverAliases = ["www.${domain}"];}; - }; }; security.acme = { diff --git a/configuration/services/webserver.nix b/configuration/services/webserver.nix index 093da3d..818ec7d 100644 --- a/configuration/services/webserver.nix +++ b/configuration/services/webserver.nix @@ -1,47 +1,20 @@ -{ - config, - pkgs, - ... -}: { - users = { - extraUsers.webserver = { - uid = config.ids.uids.webserver; - group = config.users.extraGroups.webserver.name; - isSystemUser = true; - description = "tlater.net web server user"; - }; - extraGroups.webserver = {gid = config.ids.gids.webserver;}; - }; +{config, ...}: let + domain = config.services.nginx.domain; +in { + services.tlaternet-webserver.enable = true; - virtualisation.oci-containers.containers.webserver = { - image = "tlaternet/webserver"; + # Set up SSL + services.nginx.virtualHosts."${domain}" = let + inherit (config.services.tlaternet-webserver.listen) addr port; + in { + serverAliases = ["www.${domain}"]; - imageFile = pkgs.dockerTools.buildImage { - name = "tlaternet/webserver"; - tag = "latest"; - contents = pkgs.tlaternet-webserver.webserver; + forceSSL = true; + enableACME = true; + extraConfig = '' + add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; + ''; - config = let - uid = toString config.users.extraUsers.webserver.uid; - gid = toString config.users.extraGroups.webserver.gid; - in { - Cmd = ["tlaternet-webserver"]; - Volumes = {"/srv/mail" = {};}; - Env = [ - "ROCKET_PORT=3002" - "ROCKET_TEMPLATE_DIR=${pkgs.tlaternet-templates.templates}/browser/" - ]; - ExposedPorts = {"3002" = {};}; - User = "${uid}:${gid}"; - }; - }; - - ports = ["3002:3002"]; - volumes = ["tlaternet-mail:/srv/mail"]; - extraOptions = [ - "--hostname=tlater.net" - # Rocket 0.4 doesn't support SIGTERM anyway, so SIGKILL is the cleanest exit possible. - "--stop-signal=SIGKILL" - ]; + locations."/".proxyPass = "http://${addr}:${toString port}"; }; } diff --git a/flake.lock b/flake.lock index c6f9923..2b15a85 100644 --- a/flake.lock +++ b/flake.lock @@ -15,21 +15,6 @@ "type": "github" } }, - "flake-utils_2": { - "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "naersk": { "inputs": { "nixpkgs": [ @@ -88,7 +73,6 @@ "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "sops-nix": "sops-nix", - "tlaternet-templates": "tlaternet-templates", "tlaternet-webserver": "tlaternet-webserver" } }, @@ -137,30 +121,9 @@ "type": "github" } }, - "tlaternet-templates": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1633432574, - "narHash": "sha256-IjGaJAQuFIJ1Is9gtHXsryPOnTDE6tlA61PUKuS8dzw=", - "ref": "master", - "rev": "555a2949bdf643c74b535bd0c623d98f99d33628", - "revCount": 61, - "type": "git", - "url": "https://gitea.tlater.net/tlaternet/tlaternet-templates.git" - }, - "original": { - "type": "git", - "url": "https://gitea.tlater.net/tlaternet/tlaternet-templates.git" - } - }, "tlaternet-webserver": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "naersk": "naersk", "nixpkgs": [ "nixpkgs" diff --git a/flake.nix b/flake.nix index 5ff0a51..ed94531 100644 --- a/flake.nix +++ b/flake.nix @@ -13,10 +13,6 @@ url = "git+https://gitea.tlater.net/tlaternet/tlaternet.git"; inputs.nixpkgs.follows = "nixpkgs"; }; - tlaternet-templates = { - url = "git+https://gitea.tlater.net/tlaternet/tlaternet-templates.git"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; outputs = { @@ -25,16 +21,11 @@ nixos-hardware, sops-nix, tlaternet-webserver, - tlaternet-templates, }: let system = "x86_64-linux"; overlays = [ (final: prev: { - tlaternet-webserver = - tlaternet-webserver.legacyPackages.${prev.system}.packages; - tlaternet-templates = - tlaternet-templates.legacyPackages.${prev.system}.packages; local = import ./pkgs { pkgs = prev; }; @@ -59,6 +50,7 @@ (import ./configuration/linode.nix) (import ./configuration/hardware-configuration.nix) sops-nix.nixosModules.sops + tlaternet-webserver.nixosModules.default ]; }; diff --git a/modules/virtualisation/pods.nix b/modules/virtualisation/pods.nix deleted file mode 100644 index 5a96cc8..0000000 --- a/modules/virtualisation/pods.nix +++ /dev/null @@ -1,222 +0,0 @@ -{ - lib, - config, - options, - ... -}: -with lib; let - cfg = config.virtualisation.pods; - list-to-args = arg: list: - concatStringsSep " " (map (e: "--${arg}=${escapeShellArg e}") list); - possibly-unset-arg = arg: val: (optionalString (val != null) "--${arg}=${escapeShellArg val}"); - - mkPod = name: pod: rec { - path = [config.virtualisation.podman.package]; - - wants = ["network.target"]; - after = ["network-online.target"]; - wantedBy = ["multi-user.target" "default.target"]; - - environment.PODMAN_SYSTEMD_UNIT = "%n"; - - preStart = concatStringsSep " " [ - "mkdir -p /run/podman/pods/ ;" - "podman pod create" - "--infra-conmon-pidfile=${escapeShellArg "/run/podman/pods/${name}.pid"}" - "--name=${escapeShellArg name}" - "--replace" - (list-to-args "add-host" pod.added-hosts) - (possibly-unset-arg "cgroup-parent" pod.cgroup-parent) - (list-to-args "dns" pod.dns) - (list-to-args "dns-opt" pod.dns-opt) - (list-to-args "dns-search" pod.dns-search) - (possibly-unset-arg "hostname" pod.hostname) - (possibly-unset-arg "infra" pod.infra) - (possibly-unset-arg "infra-command" pod.infra-command) - (possibly-unset-arg "infra-image" pod.infra-image) - (possibly-unset-arg "ip" pod.ip) - (possibly-unset-arg "mac-address" pod.mac-address) - (possibly-unset-arg "network" pod.network) - (possibly-unset-arg "network-alias" pod.network-alias) - (possibly-unset-arg "no-hosts" pod.no-hosts) - (list-to-args "publish" pod.publish) - (list-to-args "share" pod.share) - ]; - - script = "podman pod start ${escapeShellArg name}"; - preStop = "podman pod stop ${escapeShellArg name}"; - # `podman generate systemd` generates a second stop after the - # first; not sure why but clearly it's recommended. - postStop = preStop; - - serviceConfig = rec { - Type = "forking"; - TimeoutStopSec = 70; - Restart = "on-failure"; - PIDFile = "/run/podman/pods/${name}.pid"; - }; - }; -in { - options.virtualisation.pods = mkOption { - type = with types; - attrsOf (submodule { - options = { - added-hosts = mkOption { - type = listOf str; - default = []; - description = "Additional hosts to add to /etc/hosts for each container."; - example = literalExample '' - [ "database:10.0.0.1" ] - ''; - }; - - cgroup-parent = mkOption { - type = nullOr str; - default = null; - description = "The cgroups path under which the pod cgroup will be created."; - }; - - dns = mkOption { - type = listOf str; - default = []; - description = "The dns servers to set in /etc/resolv.conf."; - }; - - dns-opt = mkOption { - type = listOf str; - default = []; - description = "dns options to set in /etc/resolv.conf."; - }; - - dns-search = mkOption { - type = listOf str; - default = []; - description = "Search domains to set in /etc/resolv.conf."; - }; - - hostname = mkOption { - type = nullOr str; - default = null; - description = "The pod hostname."; - }; - - infra = mkOption { - type = nullOr bool; - default = null; - description = "Whether to create the infra container for the pod."; - }; - - infra-command = mkOption { - type = nullOr str; - default = null; - description = "The command to run in the infra container."; - }; - - infra-image = mkOption { - type = nullOr str; - default = null; - description = "The image to use for the infra container."; - }; - - ip = mkOption { - type = nullOr str; - default = null; - description = "A static IP address for the pod network."; - }; - - # TODO: set up label file stuff. - # - # labels = mkOption {}; - - mac-address = mkOption { - type = nullOr str; - default = null; - description = "A static mac address for the pod network."; - }; - - network = mkOption { - type = nullOr str; - default = null; - description = "Network configuration for the pod."; - }; - - network-alias = mkOption { - type = nullOr str; - default = null; - description = "DNS alias for the pod."; - }; - - no-hosts = mkOption { - type = nullOr bool; - default = null; - description = "Whether to disable /etc/hosts creation for the pod."; - }; - - publish = mkOption { - type = listOf str; - default = []; - description = "List of ports to publish from the pod."; - }; - - share = mkOption { - type = listOf str; - default = []; - description = "List of kernel namespaces to share."; - }; - - containers = options.virtualisation.oci-containers.containers; - }; - }); - default = {}; - description = "Podman pods to run as systemd services."; - }; - - config = let - # Merge a list of attribute sets together - # - # TODO: See if there's a generic version for this somewhere in the - # pkgs lib? - mergeAttrs = attrList: foldr (a: b: a // b) {} attrList; - - # Create services for all defined pods - pod-services = mapAttrs' (n: v: nameValuePair "pod-${n}" (mkPod n v)) cfg; - - # Override the systemd-specific settings of containers defined in - # pods. - # - # I.e., make a systemd unit dependency on the pod service. - pod-container-services = mergeAttrs (mapAttrsToList (pname: pod: - mapAttrs' (cname: container: - nameValuePair "podman-${pname}-${cname}" rec { - after = ["pod-${pname}.service"]; - requires = after; - }) - pod.containers) - cfg); - - # Override the oci-container settings for containers defined in pods. - # - # I.e., set the --pod=podname setting, and update the dependsOn so - # it points to containers in the same pod. - podifyContainer = container: podname: - container - // { - dependsOn = - map (dependency: "${podname}-${dependency}") container.dependsOn; - extraOptions = container.extraOptions ++ ["--pod=${podname}"]; - }; - in - lib.mkIf (cfg != {}) { - virtualisation.podman.enable = true; - virtualisation.oci-containers.backend = "podman"; - - systemd.services = pod-services // pod-container-services; - - virtualisation.oci-containers.containers = mergeAttrs (mapAttrsToList - (pname: pod: - mapAttrs' (cname: container: - nameValuePair "${pname}-${cname}" (podifyContainer container pname)) - pod.containers) - cfg); - }; -}