python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / openvpn.nix
blob492a0936fdbb6be82f88fc569ec9f08721b1f137
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg = config.services.openvpn;
9   inherit (pkgs) openvpn;
11   makeOpenVPNJob = cfg: name:
12     let
14       path = makeBinPath (getAttr "openvpn-${name}" config.systemd.services).path;
16       upScript = ''
17         #! /bin/sh
18         export PATH=${path}
20         # For convenience in client scripts, extract the remote domain
21         # name and name server.
22         for var in ''${!foreign_option_*}; do
23           x=(''${!var})
24           if [ "''${x[0]}" = dhcp-option ]; then
25             if [ "''${x[1]}" = DOMAIN ]; then domain="''${x[2]}"
26             elif [ "''${x[1]}" = DNS ]; then nameserver="''${x[2]}"
27             fi
28           fi
29         done
31         ${cfg.up}
32         ${optionalString cfg.updateResolvConf
33            "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
34       '';
36       downScript = ''
37         #! /bin/sh
38         export PATH=${path}
39         ${optionalString cfg.updateResolvConf
40            "${pkgs.update-resolv-conf}/libexec/openvpn/update-resolv-conf"}
41         ${cfg.down}
42       '';
44       configFile = pkgs.writeText "openvpn-config-${name}"
45         ''
46           errors-to-stderr
47           ${optionalString (cfg.up != "" || cfg.down != "" || cfg.updateResolvConf) "script-security 2"}
48           ${cfg.config}
49           ${optionalString (cfg.up != "" || cfg.updateResolvConf)
50               "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"}
51           ${optionalString (cfg.down != "" || cfg.updateResolvConf)
52               "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"}
53           ${optionalString (cfg.authUserPass != null)
54               "auth-user-pass ${pkgs.writeText "openvpn-credentials-${name}" ''
55                 ${cfg.authUserPass.username}
56                 ${cfg.authUserPass.password}
57               ''}"}
58         '';
60     in {
61       description = "OpenVPN instance ‘${name}’";
63       wantedBy = optional cfg.autoStart "multi-user.target";
64       after = [ "network.target" ];
66       path = [ pkgs.iptables pkgs.iproute2 pkgs.nettools ];
68       serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --suppress-timestamps --config ${configFile}";
69       serviceConfig.Restart = "always";
70       serviceConfig.Type = "notify";
71     };
76   imports = [
77     (mkRemovedOptionModule [ "services" "openvpn" "enable" ] "")
78   ];
80   ###### interface
82   options = {
84     services.openvpn.servers = mkOption {
85       default = {};
87       example = literalExpression ''
88         {
89           server = {
90             config = '''
91               # Simplest server configuration: https://community.openvpn.net/openvpn/wiki/StaticKeyMiniHowto
92               # server :
93               dev tun
94               ifconfig 10.8.0.1 10.8.0.2
95               secret /root/static.key
96             ''';
97             up = "ip route add ...";
98             down = "ip route del ...";
99           };
101           client = {
102             config = '''
103               client
104               remote vpn.example.org
105               dev tun
106               proto tcp-client
107               port 8080
108               ca /root/.vpn/ca.crt
109               cert /root/.vpn/alice.crt
110               key /root/.vpn/alice.key
111             ''';
112             up = "echo nameserver $nameserver | ''${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev";
113             down = "''${pkgs.openresolv}/sbin/resolvconf -d $dev";
114           };
115         }
116       '';
118       description = lib.mdDoc ''
119         Each attribute of this option defines a systemd service that
120         runs an OpenVPN instance.  These can be OpenVPN servers or
121         clients.  The name of each systemd service is
122         `openvpn-«name».service`,
123         where «name» is the corresponding
124         attribute name.
125       '';
127       type = with types; attrsOf (submodule {
129         options = {
131           config = mkOption {
132             type = types.lines;
133             description = lib.mdDoc ''
134               Configuration of this OpenVPN instance.  See
135               {manpage}`openvpn(8)`
136               for details.
138               To import an external config file, use the following definition:
139               `config = "config /path/to/config.ovpn"`
140             '';
141           };
143           up = mkOption {
144             default = "";
145             type = types.lines;
146             description = lib.mdDoc ''
147               Shell commands executed when the instance is starting.
148             '';
149           };
151           down = mkOption {
152             default = "";
153             type = types.lines;
154             description = lib.mdDoc ''
155               Shell commands executed when the instance is shutting down.
156             '';
157           };
159           autoStart = mkOption {
160             default = true;
161             type = types.bool;
162             description = lib.mdDoc "Whether this OpenVPN instance should be started automatically.";
163           };
165           updateResolvConf = mkOption {
166             default = false;
167             type = types.bool;
168             description = lib.mdDoc ''
169               Use the script from the update-resolv-conf package to automatically
170               update resolv.conf with the DNS information provided by openvpn. The
171               script will be run after the "up" commands and before the "down" commands.
172             '';
173           };
175           authUserPass = mkOption {
176             default = null;
177             description = lib.mdDoc ''
178               This option can be used to store the username / password credentials
179               with the "auth-user-pass" authentication method.
181               WARNING: Using this option will put the credentials WORLD-READABLE in the Nix store!
182             '';
183             type = types.nullOr (types.submodule {
185               options = {
186                 username = mkOption {
187                   description = lib.mdDoc "The username to store inside the credentials file.";
188                   type = types.str;
189                 };
191                 password = mkOption {
192                   description = lib.mdDoc "The password to store inside the credentials file.";
193                   type = types.str;
194                 };
195               };
196             });
197           };
198         };
200       });
202     };
204   };
207   ###### implementation
209   config = mkIf (cfg.servers != {}) {
211     systemd.services = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers);
213     environment.systemPackages = [ openvpn ];
215     boot.kernelModules = [ "tun" ];
217   };