nixpkgs/nixos/modules/services/web-apps/dex.nix
Eduard Bachmakov cb10fe8aaf treewide: Remove ineffective capability grants.
Systemd units with `PrivateUsers` set get their capabilities within the user namespace only [1].
As a result they do cannot bind to privileged ports even though they *appear* like they should be able to.

The units in this commit [2] set `PrivateUsers` unconditionally so binding to privileged ports is currently impossible.
Granting them CAP_NET_BIND_SERVICE is useless and misleading any reader of those modules.
Technically, this commit also hardens these modules ever so slightly.

(There are corner cases where this could make sense (e.g. across units, using `JoinsNamspaceOf`) but this is arcane enough to not to be present in nixpkgs.)

[1]: systemd.exec(5): PrivateUsers
[2]: found using `rg -e 'PrivateUsers.?=\s+[^f][^a]' -l | xargs rg -e '\bCAP_' -l`
2024-08-09 23:10:30 +02:00

131 lines
4.5 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.dex;
fixClient = client: if client ? secretFile then ((builtins.removeAttrs client [ "secretFile" ]) // { secret = client.secretFile; }) else client;
filteredSettings = mapAttrs (n: v: if n == "staticClients" then (builtins.map fixClient v) else v) cfg.settings;
secretFiles = flatten (builtins.map (c: optional (c ? secretFile) c.secretFile) (cfg.settings.staticClients or []));
settingsFormat = pkgs.formats.yaml {};
configFile = settingsFormat.generate "config.yaml" filteredSettings;
startPreScript = pkgs.writeShellScript "dex-start-pre"
(concatStringsSep "\n" (map (file: ''
replace-secret '${file}' '${file}' /run/dex/config.yaml
'')
secretFiles));
in
{
options.services.dex = {
enable = mkEnableOption "the OpenID Connect and OAuth2 identity provider";
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Environment file (see `systemd.exec(5)`
"EnvironmentFile=" section for the syntax) to define variables for dex.
This option can be used to safely include secret keys into the dex configuration.
'';
};
settings = mkOption {
type = settingsFormat.type;
default = {};
example = literalExpression ''
{
# External url
issuer = "http://127.0.0.1:5556/dex";
storage = {
type = "postgres";
config.host = "/var/run/postgres";
};
web = {
http = "127.0.0.1:5556";
};
enablePasswordDB = true;
staticClients = [
{
id = "oidcclient";
name = "Client";
redirectURIs = [ "https://example.com/callback" ];
secretFile = "/etc/dex/oidcclient"; # The content of `secretFile` will be written into to the config as `secret`.
}
];
}
'';
description = ''
The available options can be found in
[the example configuration](https://github.com/dexidp/dex/blob/v${pkgs.dex-oidc.version}/config.yaml.dist).
It's also possible to refer to environment variables (defined in [services.dex.environmentFile](#opt-services.dex.environmentFile))
using the syntax `$VARIABLE_NAME`.
'';
};
};
config = mkIf cfg.enable {
systemd.services.dex = {
description = "dex identity provider";
wantedBy = [ "multi-user.target" ];
after = [ "networking.target" ] ++ (optional (cfg.settings.storage.type == "postgres") "postgresql.service");
path = with pkgs; [ replace-secret ];
serviceConfig = {
ExecStart = "${pkgs.dex-oidc}/bin/dex serve /run/dex/config.yaml";
ExecStartPre = [
"${pkgs.coreutils}/bin/install -m 600 ${configFile} /run/dex/config.yaml"
"+${startPreScript}"
];
RuntimeDirectory = "dex";
BindReadOnlyPaths = [
"/nix/store"
"-/etc/dex"
"-/etc/hosts"
"-/etc/localtime"
"-/etc/nsswitch.conf"
"-/etc/resolv.conf"
"-/etc/ssl/certs/ca-certificates.crt"
];
BindPaths = optional (cfg.settings.storage.type == "postgres") "/var/run/postgresql";
# ProtectClock= adds DeviceAllow=char-rtc r
DeviceAllow = "";
DynamicUser = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateMounts = true;
# Port needs to be exposed to the host network
#PrivateNetwork = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectHome = true;
ProtectHostname = true;
ProtectSystem = "strict";
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged @setuid @keyring" ];
UMask = "0066";
} // optionalAttrs (cfg.environmentFile != null) {
EnvironmentFile = cfg.environmentFile;
};
};
};
# uses attributes of the linked package
meta.buildDocsInSandbox = false;
}