diff --git a/hosts/ward/guests/kanidm.nix b/hosts/ward/guests/kanidm.nix index 595c847..b991077 100644 --- a/hosts/ward/guests/kanidm.nix +++ b/hosts/ward/guests/kanidm.nix @@ -169,14 +169,8 @@ in "openid" "email" "profile" + "groups" ]; - claimMaps.groups = { - joinType = "array"; - valuesByGroup = { - "mealie.access" = [ "user" ]; - "mealie.admins" = [ "admin" ]; - }; - }; }; # Paperless diff --git a/hosts/ward/guests/mealie.nix b/hosts/ward/guests/mealie.nix index a0cdad0..8db50a8 100644 --- a/hosts/ward/guests/mealie.nix +++ b/hosts/ward/guests/mealie.nix @@ -52,24 +52,24 @@ in services.mealie = { enable = true; settings = rec { - ALLOW_SIGNUP = "false"; BASE_URL = "https://${mealieDomain}"; TZ = config.time.timeZone; TOKEN_TIME = 87600; # 10 years session time - this is only internal so who cares + ALLOW_SIGNUP = "false"; OIDC_AUTH_ENABLED = "true"; OIDC_SIGNUP_ENABLED = "true"; OIDC_AUTO_REDIRECT = "true"; OIDC_REMEMBER_ME = "true"; OIDC_CLIENT_ID = "mealie"; - OIDC_SIGNING_ALGORITHM = "ES256"; OIDC_USER_CLAIM = "preferred_username"; OIDC_PROVIDER_NAME = "Kanidm"; OIDC_CONFIGURATION_URL = "https://${globals.services.kanidm.domain}/oauth2/openid/${OIDC_CLIENT_ID}/.well-known/openid-configuration"; - OIDC_USER_GROUP = "user"; - OIDC_ADMIN_GROUP = "admin"; + OIDC_USER_GROUP = "mealie.access@${globals.services.kanidm.domain}"; + OIDC_ADMIN_GROUP = "mealie.admins@${globals.services.kanidm.domain}"; }; + trustedProxies = [ nodes.ward-web-proxy.config.wireguard.proxy-home.ipv4 ]; credentialsFile = config.age.secrets.oauth2-client-secret.path; }; diff --git a/modules/default.nix b/modules/default.nix index a1176f9..d1cac02 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,4 +1,7 @@ { + disabledModules = [ + "services/web-apps/mealie.nix" + ]; imports = [ ./acme-wildcard.nix ./backups.nix @@ -6,6 +9,7 @@ ./distributed-config.nix ./ente.nix ./globals.nix + ./mealie.nix ./meta.nix ./nginx-upstream-monitoring.nix ./oauth2-proxy.nix diff --git a/modules/mealie.nix b/modules/mealie.nix new file mode 100644 index 0000000..0fc0b60 --- /dev/null +++ b/modules/mealie.nix @@ -0,0 +1,128 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.mealie; + pkg = cfg.package; +in +{ + options.services.mealie = { + enable = lib.mkEnableOption "Mealie, a recipe manager and meal planner"; + + package = lib.mkPackageOption pkgs "mealie" { }; + + listenAddress = lib.mkOption { + type = lib.types.str; + default = "0.0.0.0"; + description = "Address on which the service should listen."; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 9000; + description = "Port on which to serve the Mealie service."; + }; + + settings = lib.mkOption { + type = with lib.types; attrsOf anything; + default = { }; + description = '' + Configuration of the Mealie service. + + See [the mealie documentation](https://nightly.mealie.io/documentation/getting-started/installation/backend-config/) for available options and default values. + ''; + example = { + ALLOW_SIGNUP = "false"; + }; + }; + + extraOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "--forwarded-allow-ips=10.44.0.11" ]; + description = '' + Specifies extra command line arguments to pass to mealie (Gunicorn). + ''; + }; + + credentialsFile = lib.mkOption { + type = with lib.types; nullOr path; + default = null; + example = "/run/secrets/mealie-credentials.env"; + description = '' + File containing credentials used in mealie such as {env}`POSTGRES_PASSWORD` + or sensitive LDAP options. + + Expects the format of an `EnvironmentFile=`, as described by {manpage}`systemd.exec(5)`. + ''; + }; + + database = { + createLocally = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Configure local PostgreSQL database server for Mealie. + ''; + }; + }; + + trustedProxies = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "A list of trusted proxies. You must set this when you are using OIDC behind https, otherwise the generated redirect url will have the wrong url scheme."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.mealie = { + description = "Mealie, a self hosted recipe manager and meal planner"; + + after = [ "network-online.target" ] ++ lib.optional cfg.database.createLocally "postgresql.service"; + requires = lib.optional cfg.database.createLocally "postgresql.service"; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + PRODUCTION = "true"; + API_PORT = toString cfg.port; + BASE_URL = "http://localhost:${toString cfg.port}"; + DATA_DIR = "/var/lib/mealie"; + NLTK_DATA = pkgs.nltk-data.averaged_perceptron_tagger_eng; + } // (builtins.mapAttrs (_: toString) cfg.settings); + + serviceConfig = { + DynamicUser = true; + User = "mealie"; + ExecStartPre = "${pkg}/libexec/init_db"; + ExecStart = "${lib.getExe pkg} -b ${cfg.listenAddress}:${builtins.toString cfg.port} ${lib.escapeShellArgs cfg.extraOptions}"; + EnvironmentFile = lib.mkIf (cfg.credentialsFile != null) cfg.credentialsFile; + StateDirectory = "mealie"; + StandardOutput = "journal"; + }; + }; + + services.mealie.settings = lib.mkIf cfg.database.createLocally { + DB_ENGINE = "postgres"; + POSTGRES_URL_OVERRIDE = "postgresql://mealie:@/mealie?host=/run/postgresql"; + }; + + services.mealie.extraOptions = lib.mkIf (cfg.trustedProxies != [ ]) [ + "--forwarded-allow-ips=${lib.concatStringsSep "," cfg.trustedProxies}" + ]; + + services.postgresql = lib.mkIf cfg.database.createLocally { + enable = true; + ensureDatabases = [ "mealie" ]; + ensureUsers = [ + { + name = "mealie"; + ensureDBOwnership = true; + } + ]; + }; + }; +}