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)
 | 
			
		||||
 | 
			
		||||
The @code{(gnu services vpn)} module provides services related to
 | 
			
		||||
@dfn{virtual private networks} (VPNs).  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@.  Both services use @uref{https://openvpn.net/, OpenVPN}.
 | 
			
		||||
@dfn{virtual private networks} (VPNs).
 | 
			
		||||
 | 
			
		||||
@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 @
 | 
			
		||||
       [#:config (openvpn-client-configuration)]
 | 
			
		||||
| 
						 | 
				
			
			@ -26717,6 +26720,70 @@ Defaults to @samp{#f}.
 | 
			
		|||
 | 
			
		||||
@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
 | 
			
		||||
@subsection Network File System
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,24 @@
 | 
			
		|||
            openvpn-remote-configuration
 | 
			
		||||
            openvpn-ccd-configuration
 | 
			
		||||
            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.
 | 
			
		||||
| 
						 | 
				
			
			@ -507,3 +524,122 @@ is truncated and rewritten every minute.")
 | 
			
		|||
      (remote openvpn-remote-configuration))
 | 
			
		||||
     (openvpn-remote-configuration ,openvpn-remote-configuration-fields))
 | 
			
		||||
   '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