1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.networking.networkmanager;
9 toml = pkgs.formats.toml { };
10
11 enabled = (lib.length cfg.ensureProfiles.secrets.entries) > 0;
12
13 nmFileSecretAgentConfig = {
14 entry = builtins.map (
15 i:
16 {
17 key = i.key;
18 file = i.file;
19 }
20 // lib.optionalAttrs (i.matchId != null) { match_id = i.matchId; }
21 // lib.optionalAttrs (i.matchUuid != null) { match_uuid = i.matchUuid; }
22 // lib.optionalAttrs (i.matchType != null) { match_type = i.matchType; }
23 // lib.optionalAttrs (i.matchIface != null) { match_iface = i.matchIface; }
24 // lib.optionalAttrs (i.matchSetting != null) {
25 match_setting = i.matchSetting;
26 }
27 ) cfg.ensureProfiles.secrets.entries;
28 };
29 nmFileSecretAgentConfigFile = toml.generate "config.toml" nmFileSecretAgentConfig;
30in
31{
32 meta = {
33 maintainers = [ lib.maintainers.lilioid ];
34 };
35
36 ####### interface
37 options = {
38 networking.networkmanager.ensureProfiles.secrets = {
39 package = lib.mkPackageOption pkgs "nm-file-secret-agent" { };
40 entries = lib.mkOption {
41 description = ''
42 A list of secrets to provide to NetworkManager by reading their values from configured files.
43
44 Note that NetworkManager should be configured to read secrets from a secret agent.
45 This can be done for example through the `networking.networkmanager.ensureProfiles.profiles` options.
46 '';
47 default = [ ];
48 example = [
49 {
50 matchId = "My WireGuard VPN";
51 matchType = "wireguard";
52 matchSetting = "wireguard";
53 key = "private-key";
54 file = "/root/wireguard_key";
55 }
56 ];
57 type = lib.types.listOf (
58 lib.types.submodule {
59 options = {
60 matchId = lib.mkOption {
61 description = ''
62 connection id used by NetworkManager. Often displayed as name in GUIs.
63
64 NetworkManager describes this as a human readable unique identifier for the connection, like "Work Wi-Fi" or "T-Mobile 3G".
65 '';
66 type = lib.types.nullOr lib.types.str;
67 default = null;
68 example = "wifi1";
69 };
70 matchUuid = lib.mkOption {
71 description = ''
72 UUID of the connection profile
73
74 UUIDs are assigned once on connection creation and should never change as long as the connection still applies to the same network.
75 '';
76 type = lib.types.nullOr lib.types.str;
77 default = null;
78 example = "669ea4c9-4cb3-4901-ab52-f9606590976e";
79 };
80 matchType = lib.mkOption {
81 description = ''
82 NetworkManager connection type
83
84 The NetworkManager configuration settings reference roughly corresponds to connection types.
85 More might be available on your system depending on the installed plugins.
86
87 https://networkmanager.dev/docs/api/latest/ch01.html
88 '';
89 type = lib.types.nullOr lib.types.str;
90 default = null;
91 example = "wireguard";
92 };
93 matchIface = lib.mkOption {
94 description = "interface name of the NetworkManager connection";
95 type = lib.types.nullOr lib.types.str;
96 default = null;
97 };
98 matchSetting = lib.mkOption {
99 description = "name of the setting section for which secrets are requested";
100 type = lib.types.nullOr lib.types.str;
101 default = null;
102 };
103 key = lib.mkOption {
104 description = "key in the setting section for which this entry provides a value";
105 type = lib.types.str;
106 };
107 file = lib.mkOption {
108 description = "file from which the secret value is read";
109 type = lib.types.str;
110 };
111 };
112 }
113 );
114 };
115 };
116 };
117
118 ####### implementation
119 config = lib.mkIf enabled {
120 # start nm-file-secret-agent if required
121 systemd.services."nm-file-secret-agent" = {
122 description = "NetworkManager secret agent that responds with the content of preconfigured files";
123 documentation = [ "https://github.com/lilioid/nm-file-secret-agent/" ];
124 requires = [ "NetworkManager.service" ];
125 after = [ "NetworkManager.service" ];
126 wantedBy = [ "multi-user.target" ];
127 restartTriggers = [ nmFileSecretAgentConfigFile ];
128 script = "${lib.getExe cfg.ensureProfiles.secrets.package} --conf ${nmFileSecretAgentConfigFile}";
129 };
130 };
131}