services: wireguard: New service.
* gnu/services/vpn.scm (wireguard-peer, wireguard-configuration): New records. (wireguard-service-type): New variable. * doc/guix.texi (VPN Services): Document it.
This commit is contained in:
		
							parent
							
								
									6591e184f0
								
							
						
					
					
						commit
						43b2e440c3
					
				
					 2 changed files with 207 additions and 4 deletions
				
			
		| 
						 | 
					@ -26336,9 +26336,12 @@ Defaults to @samp{()}.
 | 
				
			||||||
@cindex virtual private network (VPN)
 | 
					@cindex virtual private network (VPN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The @code{(gnu services vpn)} module provides services related to
 | 
					The @code{(gnu services vpn)} module provides services related to
 | 
				
			||||||
@dfn{virtual private networks} (VPNs).  It provides a @emph{client} service for
 | 
					@dfn{virtual private networks} (VPNs).
 | 
				
			||||||
your machine to connect to a VPN, and a @emph{server} service for your machine
 | 
					
 | 
				
			||||||
to host a VPN@.  Both services use @uref{https://openvpn.net/, OpenVPN}.
 | 
					@subsubheading OpenVPN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It provides a @emph{client} service for your machine to connect to a
 | 
				
			||||||
 | 
					VPN, and a @emph{server} service for your machine to host a VPN@.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@deffn {Scheme Procedure} openvpn-client-service @
 | 
					@deffn {Scheme Procedure} openvpn-client-service @
 | 
				
			||||||
       [#:config (openvpn-client-configuration)]
 | 
					       [#:config (openvpn-client-configuration)]
 | 
				
			||||||
| 
						 | 
					@ -26717,6 +26720,70 @@ Defaults to @samp{#f}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@c %end of automatic openvpn-server documentation
 | 
					@c %end of automatic openvpn-server documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@subsubheading Wireguard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@defvr {Scheme Variable} wireguard-service-type
 | 
				
			||||||
 | 
					A service type for a Wireguard tunnel interface.  Its value must be a
 | 
				
			||||||
 | 
					@code{wireguard-configuration} record as in this example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@lisp
 | 
				
			||||||
 | 
					(service wireguard-service-type
 | 
				
			||||||
 | 
					         (wireguard-configuration
 | 
				
			||||||
 | 
					          (peers
 | 
				
			||||||
 | 
					           (list
 | 
				
			||||||
 | 
					            (wireguard-peer
 | 
				
			||||||
 | 
					             (name "my-peer")
 | 
				
			||||||
 | 
					             (endpoint "my.wireguard.com:51820")
 | 
				
			||||||
 | 
					             (public-key "hzpKg9X1yqu1axN6iJp0mWf6BZGo8m1wteKwtTmDGF4=")
 | 
				
			||||||
 | 
					             (allowed-ips '("10.0.0.2/32")))))))
 | 
				
			||||||
 | 
					@end lisp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end defvr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@deftp {Data Type} wireguard-configuration
 | 
				
			||||||
 | 
					Data type representing the configuration of the Wireguard service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@table @asis
 | 
				
			||||||
 | 
					@item @code{wireguard}
 | 
				
			||||||
 | 
					The wireguard package to use for this service.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{interface} (default: @code{"wg0"})
 | 
				
			||||||
 | 
					The interface name for the VPN.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{addresses} (default: @code{'("10.0.0.1/32")})
 | 
				
			||||||
 | 
					The IP addresses to be assigned to the above interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{private-key} (default: @code{"/etc/wireguard/private.key"})
 | 
				
			||||||
 | 
					The private key file for the interface.  It is automatically generated if
 | 
				
			||||||
 | 
					the file does not exist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{peers} (default: @code{'()})
 | 
				
			||||||
 | 
					The authorized peers on this interface.  This is a list of
 | 
				
			||||||
 | 
					@var{wireguard-peer} records.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end table
 | 
				
			||||||
 | 
					@end deftp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@deftp {Data Type} wireguard-peer
 | 
				
			||||||
 | 
					Data type representing a Wireguard peer attached to a given interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@table @asis
 | 
				
			||||||
 | 
					@item @code{name}
 | 
				
			||||||
 | 
					The peer name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{endpoint} (default: @code{#f})
 | 
				
			||||||
 | 
					The optional endpoint for the peer, such as
 | 
				
			||||||
 | 
					@code{"demo.wireguard.com:51820"}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{public-key}
 | 
				
			||||||
 | 
					The peer public-key represented as a base64 string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@item @code{allowed-ips}
 | 
				
			||||||
 | 
					A list of IP addresses from which incoming traffic for this peer is
 | 
				
			||||||
 | 
					allowed and to which incoming traffic for this peer is directed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@end table
 | 
				
			||||||
 | 
					@end deftp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@node Network File System
 | 
					@node Network File System
 | 
				
			||||||
@subsection Network File System
 | 
					@subsection Network File System
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,24 @@
 | 
				
			||||||
            openvpn-remote-configuration
 | 
					            openvpn-remote-configuration
 | 
				
			||||||
            openvpn-ccd-configuration
 | 
					            openvpn-ccd-configuration
 | 
				
			||||||
            generate-openvpn-client-documentation
 | 
					            generate-openvpn-client-documentation
 | 
				
			||||||
            generate-openvpn-server-documentation))
 | 
					            generate-openvpn-server-documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            wireguard-peer
 | 
				
			||||||
 | 
					            wireguard-peer?
 | 
				
			||||||
 | 
					            wireguard-peer-name
 | 
				
			||||||
 | 
					            wireguard-peer-endpoint
 | 
				
			||||||
 | 
					            wireguard-peer-allowed-ips
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            wireguard-configuration
 | 
				
			||||||
 | 
					            wireguard-configuration?
 | 
				
			||||||
 | 
					            wireguard-configuration-wireguard
 | 
				
			||||||
 | 
					            wireguard-configuration-interface
 | 
				
			||||||
 | 
					            wireguard-configuration-addresses
 | 
				
			||||||
 | 
					            wireguard-configuration-port
 | 
				
			||||||
 | 
					            wireguard-configuration-private-key
 | 
				
			||||||
 | 
					            wireguard-configuration-peers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            wireguard-service-type))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
;;;
 | 
					;;;
 | 
				
			||||||
;;; OpenVPN.
 | 
					;;; OpenVPN.
 | 
				
			||||||
| 
						 | 
					@ -507,3 +524,122 @@ is truncated and rewritten every minute.")
 | 
				
			||||||
      (remote openvpn-remote-configuration))
 | 
					      (remote openvpn-remote-configuration))
 | 
				
			||||||
     (openvpn-remote-configuration ,openvpn-remote-configuration-fields))
 | 
					     (openvpn-remote-configuration ,openvpn-remote-configuration-fields))
 | 
				
			||||||
   'openvpn-client-configuration))
 | 
					   'openvpn-client-configuration))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					;;;
 | 
				
			||||||
 | 
					;;; Wireguard.
 | 
				
			||||||
 | 
					;;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define-record-type* <wireguard-peer>
 | 
				
			||||||
 | 
					  wireguard-peer make-wireguard-peer
 | 
				
			||||||
 | 
					  wireguard-peer?
 | 
				
			||||||
 | 
					  (name              wireguard-peer-name)
 | 
				
			||||||
 | 
					  (endpoint          wireguard-peer-endpoint
 | 
				
			||||||
 | 
					                     (default #f))     ;string
 | 
				
			||||||
 | 
					  (public-key        wireguard-peer-public-key)   ;string
 | 
				
			||||||
 | 
					  (allowed-ips       wireguard-peer-allowed-ips)) ;list of strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define-record-type* <wireguard-configuration>
 | 
				
			||||||
 | 
					  wireguard-configuration make-wireguard-configuration
 | 
				
			||||||
 | 
					  wireguard-configuration?
 | 
				
			||||||
 | 
					  (wireguard          wireguard-configuration-wireguard ;<package>
 | 
				
			||||||
 | 
					                      (default wireguard-tools))
 | 
				
			||||||
 | 
					  (interface          wireguard-configuration-interface ;string
 | 
				
			||||||
 | 
					                      (default "wg0"))
 | 
				
			||||||
 | 
					  (addresses          wireguard-configuration-addresses ;string
 | 
				
			||||||
 | 
					                      (default '("10.0.0.1/32")))
 | 
				
			||||||
 | 
					  (port               wireguard-configuration-port ;integer
 | 
				
			||||||
 | 
					                      (default 51820))
 | 
				
			||||||
 | 
					  (private-key        wireguard-configuration-private-key ;string
 | 
				
			||||||
 | 
					                      (default "/etc/wireguard/private.key"))
 | 
				
			||||||
 | 
					  (peers              wireguard-configuration-peers ;list of <wiregard-peer>
 | 
				
			||||||
 | 
					                      (default '())))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (wireguard-configuration-file config)
 | 
				
			||||||
 | 
					  (define (peer->config peer)
 | 
				
			||||||
 | 
					    (let ((name (wireguard-peer-name peer))
 | 
				
			||||||
 | 
					          (public-key (wireguard-peer-public-key peer))
 | 
				
			||||||
 | 
					          (endpoint (wireguard-peer-endpoint peer))
 | 
				
			||||||
 | 
					          (allowed-ips (wireguard-peer-allowed-ips peer)))
 | 
				
			||||||
 | 
					      (format #f "[Peer] #~a
 | 
				
			||||||
 | 
					PublicKey = ~a
 | 
				
			||||||
 | 
					AllowedIPs = ~a
 | 
				
			||||||
 | 
					~a"
 | 
				
			||||||
 | 
					              name
 | 
				
			||||||
 | 
					              public-key
 | 
				
			||||||
 | 
					              (string-join allowed-ips ",")
 | 
				
			||||||
 | 
					              (if endpoint
 | 
				
			||||||
 | 
					                  (format #f "Endpoint = ~a\n" endpoint)
 | 
				
			||||||
 | 
					                  "\n"))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (match-record config <wireguard-configuration>
 | 
				
			||||||
 | 
					    (wireguard interface addresses port private-key peers)
 | 
				
			||||||
 | 
					    (let* ((config-file (string-append interface ".conf"))
 | 
				
			||||||
 | 
					           (peers (map peer->config peers))
 | 
				
			||||||
 | 
					           (config
 | 
				
			||||||
 | 
					            (computed-file
 | 
				
			||||||
 | 
					             "wireguard-config"
 | 
				
			||||||
 | 
					             #~(begin
 | 
				
			||||||
 | 
					                 (mkdir #$output)
 | 
				
			||||||
 | 
					                 (chdir #$output)
 | 
				
			||||||
 | 
					                 (call-with-output-file #$config-file
 | 
				
			||||||
 | 
					                   (lambda (port)
 | 
				
			||||||
 | 
					                     (let ((format (@ (ice-9 format) format)))
 | 
				
			||||||
 | 
					                       (format port "[Interface]
 | 
				
			||||||
 | 
					Address = ~a
 | 
				
			||||||
 | 
					PostUp = ~a set %i private-key ~a
 | 
				
			||||||
 | 
					~a
 | 
				
			||||||
 | 
					~{~a~^~%~}"
 | 
				
			||||||
 | 
					                               #$(string-join addresses ",")
 | 
				
			||||||
 | 
					                               #$(file-append wireguard "/bin/wg")
 | 
				
			||||||
 | 
					                               #$private-key
 | 
				
			||||||
 | 
					                               #$(if port
 | 
				
			||||||
 | 
					                                     (format #f "ListenPort = ~a" port)
 | 
				
			||||||
 | 
					                                     "")
 | 
				
			||||||
 | 
					                               (list #$@peers)))))))))
 | 
				
			||||||
 | 
					      (file-append config "/" config-file))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (wireguard-activation config)
 | 
				
			||||||
 | 
					  (match-record config <wireguard-configuration>
 | 
				
			||||||
 | 
					    (private-key)
 | 
				
			||||||
 | 
					    #~(begin
 | 
				
			||||||
 | 
					        (use-modules (guix build utils)
 | 
				
			||||||
 | 
					                     (ice-9 popen)
 | 
				
			||||||
 | 
					                     (ice-9 rdelim))
 | 
				
			||||||
 | 
					        (mkdir-p (dirname #$private-key))
 | 
				
			||||||
 | 
					        (unless (file-exists? #$private-key)
 | 
				
			||||||
 | 
					          (let* ((pipe
 | 
				
			||||||
 | 
					                  (open-input-pipe (string-append
 | 
				
			||||||
 | 
					                                    #$(file-append wireguard-tools "/bin/wg")
 | 
				
			||||||
 | 
					                                    " genkey")))
 | 
				
			||||||
 | 
					                 (key (read-line pipe)))
 | 
				
			||||||
 | 
					            (call-with-output-file #$private-key
 | 
				
			||||||
 | 
					              (lambda (port)
 | 
				
			||||||
 | 
					                (display key port)))
 | 
				
			||||||
 | 
					            (chmod #$private-key #o400)
 | 
				
			||||||
 | 
					            (close-pipe pipe))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (wireguard-shepherd-service config)
 | 
				
			||||||
 | 
					  (match-record config <wireguard-configuration>
 | 
				
			||||||
 | 
					    (wireguard interface)
 | 
				
			||||||
 | 
					    (let ((wg-quick (file-append wireguard "/bin/wg-quick"))
 | 
				
			||||||
 | 
					          (config (wireguard-configuration-file config)))
 | 
				
			||||||
 | 
					      (list (shepherd-service
 | 
				
			||||||
 | 
					             (requirement '(networking))
 | 
				
			||||||
 | 
					             (provision (list
 | 
				
			||||||
 | 
					                         (symbol-append 'wireguard-
 | 
				
			||||||
 | 
					                                        (string->symbol interface))))
 | 
				
			||||||
 | 
					             (start #~(lambda _
 | 
				
			||||||
 | 
					                       (invoke #$wg-quick "up" #$config)))
 | 
				
			||||||
 | 
					             (stop #~(lambda _
 | 
				
			||||||
 | 
					                       (invoke #$wg-quick "down" #$config)))
 | 
				
			||||||
 | 
					             (documentation "Run the Wireguard VPN tunnel"))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define wireguard-service-type
 | 
				
			||||||
 | 
					  (service-type
 | 
				
			||||||
 | 
					   (name 'wireguard)
 | 
				
			||||||
 | 
					   (extensions
 | 
				
			||||||
 | 
					    (list (service-extension shepherd-root-service-type
 | 
				
			||||||
 | 
					                             wireguard-shepherd-service)
 | 
				
			||||||
 | 
					          (service-extension activation-service-type
 | 
				
			||||||
 | 
					                             wireguard-activation)))))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue