nixos/cloudflared: add option for cert.pem and use dynamic user (#383499)

Changed files
+63 -30
nixos
doc
manual
release-notes
modules
services
networking
+2
nixos/doc/manual/release-notes/rl-2505.section.md
···
- hddfancontrol has been updated to major release 2. See the [migration guide](https://github.com/desbma/hddfancontrol/tree/master?tab=readme-ov-file#migrating-from-v1x), as there are breaking changes.
- The Home Assistant module has new options {option}`services.home-assistant.blueprints.automation`, `services.home-assistant.blueprints.script`, and {option}`services.home-assistant.blueprints.template` that allow for the declarative installation of [blueprints](https://www.home-assistant.io/docs/blueprint/) into the appropriate configuration directories.
- For matrix homeserver Synapse we are now following the upstream recommendation to enable jemalloc as the memory allocator by default.
···
- hddfancontrol has been updated to major release 2. See the [migration guide](https://github.com/desbma/hddfancontrol/tree/master?tab=readme-ov-file#migrating-from-v1x), as there are breaking changes.
+
- `services.cloudflared` now uses a dynamic user, and its `user` and `group` options have been removed. If the user or group is still necessary, they can be created manually.
+
- The Home Assistant module has new options {option}`services.home-assistant.blueprints.automation`, `services.home-assistant.blueprints.script`, and {option}`services.home-assistant.blueprints.template` that allow for the declarative installation of [blueprints](https://www.home-assistant.io/docs/blueprint/) into the appropriate configuration directories.
- For matrix homeserver Synapse we are now following the upstream recommendation to enable jemalloc as the memory allocator by default.
+61 -30
nixos/modules/services/networking/cloudflared.nix
···
let
cfg = config.services.cloudflared;
originRequest = {
connectTimeout = lib.mkOption {
type = with lib.types; nullOr str;
···
};
in
{
options.services.cloudflared = {
enable = lib.mkEnableOption "Cloudflare Tunnel client daemon (formerly Argo Tunnel)";
-
user = lib.mkOption {
-
type = lib.types.str;
-
default = "cloudflared";
-
description = "User account under which Cloudflared runs.";
-
};
-
-
group = lib.mkOption {
-
type = lib.types.str;
-
default = "cloudflared";
-
description = "Group under which cloudflared runs.";
-
};
-
package = lib.mkPackageOption pkgs "cloudflared" { };
tunnels = lib.mkOption {
···
{ name, ... }:
{
options = {
-
inherit originRequest;
credentialsFile = lib.mkOption {
-
type = lib.types.str;
description = ''
Credential file.
···
};
config = lib.mkIf cfg.enable {
systemd.targets = lib.mapAttrs' (
name: tunnel:
lib.nameValuePair "cloudflared-tunnel-${name}" {
···
fullConfig = filterConfig {
tunnel = name;
-
"credentials-file" = tunnel.credentialsFile;
warp-routing = filterConfig tunnel.warp-routing;
originRequest = filterConfig tunnel.originRequest;
ingress =
···
};
mkConfigFile = pkgs.writeText "cloudflared.yml" (builtins.toJSON fullConfig);
in
-
lib.nameValuePair "cloudflared-tunnel-${name}" ({
after = [
"network.target"
"network-online.target"
···
];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
-
User = cfg.user;
-
Group = cfg.group;
ExecStart = "${cfg.package}/bin/cloudflared tunnel --config=${mkConfigFile} --no-autoupdate run";
Restart = "on-failure";
};
-
})
-
) config.services.cloudflared.tunnels;
-
users.users = lib.mkIf (cfg.user == "cloudflared") {
-
cloudflared = {
-
group = cfg.group;
-
isSystemUser = true;
-
};
-
};
-
-
users.groups = lib.mkIf (cfg.group == "cloudflared") {
-
cloudflared = { };
-
};
};
meta.maintainers = with lib.maintainers; [
···
let
cfg = config.services.cloudflared;
+
certificateFile = lib.mkOption {
+
type = with lib.types; nullOr path;
+
description = ''
+
Cert.pem file.
+
+
See [Cert.pem](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-useful-terms/#certpem).
+
'';
+
default = null;
+
};
+
originRequest = {
connectTimeout = lib.mkOption {
type = with lib.types; nullOr str;
···
};
in
{
+
imports = [
+
(lib.mkRemovedOptionModule
+
[
+
"services"
+
"cloudflared"
+
"user"
+
]
+
''
+
Cloudflared now uses a dynamic user, and this option no longer has any effect.
+
+
If the user is still necessary, please define it manually using users.users.cloudflared.
+
''
+
)
+
+
(lib.mkRemovedOptionModule
+
[
+
"services"
+
"cloudflared"
+
"group"
+
]
+
''
+
Cloudflared now uses a dynamic user, and this option no longer has any effect.
+
+
If the group is still necessary, please define it manually using users.groups.cloudflared.
+
''
+
)
+
];
+
options.services.cloudflared = {
+
inherit certificateFile;
+
enable = lib.mkEnableOption "Cloudflare Tunnel client daemon (formerly Argo Tunnel)";
package = lib.mkPackageOption pkgs "cloudflared" { };
tunnels = lib.mkOption {
···
{ name, ... }:
{
options = {
+
inherit certificateFile originRequest;
credentialsFile = lib.mkOption {
+
type = lib.types.path;
description = ''
Credential file.
···
};
config = lib.mkIf cfg.enable {
+
assertions = lib.mapAttrsToList (name: tunnel: {
+
assertion =
+
tunnel.ingress == { } || (cfg.certificateFile != null || tunnel.certificateFile != null);
+
message = "Cloudflare Tunnel ${name} has a declarative configuration, but no certificate file was defined.";
+
}) cfg.tunnels;
+
systemd.targets = lib.mapAttrs' (
name: tunnel:
lib.nameValuePair "cloudflared-tunnel-${name}" {
···
fullConfig = filterConfig {
tunnel = name;
+
credentials-file = "/run/credentials/cloudflared-tunnel-${name}.service/credentials.json";
warp-routing = filterConfig tunnel.warp-routing;
originRequest = filterConfig tunnel.originRequest;
ingress =
···
};
mkConfigFile = pkgs.writeText "cloudflared.yml" (builtins.toJSON fullConfig);
+
certFile = if (tunnel.certificateFile != null) then tunnel.certificateFile else cfg.certificateFile;
in
+
lib.nameValuePair "cloudflared-tunnel-${name}" {
after = [
"network.target"
"network-online.target"
···
];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
+
RuntimeDirectory = "cloudflared-tunnel-${name}";
+
RuntimeDirectoryMode = "0400";
+
LoadCredential = [
+
"credentials.json:${tunnel.credentialsFile}"
+
] ++ (lib.optional (certFile != null) "cert.pem:certFile");
+
ExecStart = "${cfg.package}/bin/cloudflared tunnel --config=${mkConfigFile} --no-autoupdate run";
Restart = "on-failure";
+
DynamicUser = true;
};
+
environment.TUNNEL_ORIGIN_CERT = lib.mkIf (certFile != null) ''%d/cert.pem'';
+
}
+
) config.services.cloudflared.tunnels;
};
meta.maintainers = with lib.maintainers; [