diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index 155c6fdd0ab0..904a3db493b7 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -20,10 +20,16 @@ let
++ optional cfg.scanOnLowSignal ''bgscan="simple:30:-70:3600"''
++ optional (cfg.extraConfig != "") cfg.extraConfig);
+ configIsGenerated = with cfg;
+ networks != {} || extraConfig != "" || userControlled.enable;
+
+ # the original configuration file
configFile =
- if cfg.networks != {} || cfg.extraConfig != "" || cfg.userControlled.enable
+ if configIsGenerated
then pkgs.writeText "wpa_supplicant.conf" generatedConfig
else "/etc/wpa_supplicant.conf";
+ # the config file with environment variables replaced
+ finalConfig = ''"$RUNTIME_DIRECTORY"/wpa_supplicant.conf'';
# Creates a network block for wpa_supplicant.conf
mkNetwork = ssid: opts:
@@ -56,8 +62,8 @@ let
let
deviceUnit = optional (iface != null) "sys-subsystem-net-devices-${utils.escapeSystemdPath iface}.device";
configStr = if cfg.allowAuxiliaryImperativeNetworks
- then "-c /etc/wpa_supplicant.conf -I ${configFile}"
- else "-c ${configFile}";
+ then "-c /etc/wpa_supplicant.conf -I ${finalConfig}"
+ else "-c ${finalConfig}";
in {
description = "WPA Supplicant instance" + optionalString (iface != null) " for interface ${iface}";
@@ -69,12 +75,25 @@ let
stopIfChanged = false;
path = [ package ];
+ serviceConfig.RuntimeDirectory = "wpa_supplicant";
+ serviceConfig.RuntimeDirectoryMode = "700";
+ serviceConfig.EnvironmentFile = mkIf (cfg.environmentFile != null)
+ (builtins.toString cfg.environmentFile);
script =
''
- if [ -f /etc/wpa_supplicant.conf -a "/etc/wpa_supplicant.conf" != "${configFile}" ]; then
- echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead."
- fi
+ ${optionalString configIsGenerated ''
+ if [ -f /etc/wpa_supplicant.conf ]; then
+ echo >&2 "<3>/etc/wpa_supplicant.conf present but ignored. Generated ${configFile} is used instead."
+ fi
+ ''}
+
+ # substitute environment variables
+ ${pkgs.gawk}/bin/awk '{
+ for(varname in ENVIRON)
+ gsub("@"varname"@", ENVIRON[varname])
+ print
+ }' "${configFile}" > "${finalConfig}"
iface_args="-s ${optionalString cfg.dbusControlled "-u"} -D${cfg.driver} ${configStr}"
@@ -155,6 +174,44 @@ in {
'';
};
+ environmentFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ example = "/run/secrets/wireless.env";
+ description = ''
+ File consisting of lines of the form varname=value
+ to define variables for the wireless configuration.
+
+ See section "EnvironmentFile=" in
+ systemd.exec5
+ for a syntax reference.
+
+ Secrets (PSKs, passwords, etc.) can be provided without adding them to
+ the world-readable Nix store by defining them in the environment file and
+ referring to them in option
+ with the syntax @varname@. Example:
+
+
+ # content of /run/secrets/wireless.env
+ PSK_HOME=mypassword
+ PASS_WORK=myworkpassword
+
+
+
+ # wireless-related configuration
+ networking.wireless.environmentFile = "/run/secrets/wireless.env";
+ networking.wireless.networks = {
+ home.psk = "@PSK_HOME@";
+ work.auth = '''
+ eap=PEAP
+ identity="my-user@example.com"
+ password="@PASS_WORK@"
+ ''';
+ };
+
+ '';
+ };
+
networks = mkOption {
type = types.attrsOf (types.submodule {
options = {
@@ -165,10 +222,14 @@ in {
The network's pre-shared key in plaintext defaulting
to being a network without any authentication.
- Be aware that these will be written to the nix store
- in plaintext!
+
+ Be aware that this will be written to the nix store
+ in plaintext! Use an environment variable instead.
+
- Mutually exclusive with pskRaw.
+
+ Mutually exclusive with pskRaw.
+
'';
};
@@ -179,7 +240,14 @@ in {
The network's pre-shared key in hex defaulting
to being a network without any authentication.
- Mutually exclusive with psk.
+
+ Be aware that this will be written to the nix store
+ in plaintext! Use an environment variable instead.
+
+
+
+ Mutually exclusive with psk.
+
'';
};
@@ -231,7 +299,7 @@ in {
example = ''
eap=PEAP
identity="user@example.com"
- password="secret"
+ password="@EXAMPLE_PASSWORD@"
'';
description = ''
Use this option to configure advanced authentication methods like EAP.
@@ -242,7 +310,15 @@ in {
for example configurations.
- Mutually exclusive with psk and pskRaw.
+
+ Be aware that this will be written to the nix store
+ in plaintext! Use an environment variable for secrets.
+
+
+
+ Mutually exclusive with psk and
+ pskRaw.
+
'';
};
@@ -303,11 +379,17 @@ in {
default = {};
example = literalExample ''
{ echelon = { # SSID with no spaces or special characters
- psk = "abcdefgh";
+ psk = "abcdefgh"; # (password will be written to /nix/store!)
};
+
+ echelon = { # safe version of the above: read PSK from the
+ psk = "@PSK_ECHELON@"; # variable PSK_ECHELON, defined in environmentFile,
+ }; # this won't leak into /nix/store
+
"echelon's AP" = { # SSID with spaces and/or special characters
- psk = "ijklmnop";
+ psk = "ijklmnop"; # (password will be written to /nix/store!)
};
+
"free.wifi" = {}; # Public wireless network
}
'';