From fe1cd098d2b83737e96f19438612291f5a9316e4 Mon Sep 17 00:00:00 2001 From: raingloom Date: Thu, 11 Jun 2020 14:09:57 +0200 Subject: [PATCH] services: Add yggdrasil-service-type. * gnu/services/networking.scm (yggdrasil-configuration) (yggdrasil-configuration?, yggdrasil-configuration-package) (yggdrasil-configuration-auto-conf, yggdrasil-configuration-log-level) (yggdrasil-configuration-log-to): New procedures. (yggdrasil-service-type): New variable. * doc/guix.texi: Document it. * gnu/system/examples/yggdrasil.tmpl: Provide example. Signed-off-by: Julien Lepiller --- doc/guix.texi | 96 +++++++++++++++++++++++ gnu/services/networking.scm | 117 ++++++++++++++++++++++++++++- gnu/system/examples/yggdrasil.tmpl | 60 +++++++++++++++ 3 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 gnu/system/examples/yggdrasil.tmpl diff --git a/doc/guix.texi b/doc/guix.texi index b7f1bc1f00..217ed7a8a8 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -82,6 +82,7 @@ Copyright @copyright{} 2020 Pierre Langlois@* Copyright @copyright{} 2020 pinoaffe@* Copyright @copyright{} 2020 André Batista@* Copyright @copyright{} 2020 Alexandru-Sergiu Marton@* +Copyright @copyright{} 2020 raingloom@* Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -16848,6 +16849,101 @@ Use this to add additional options and manage shared secrets out-of-band. @end table @end deftp +@defvr {Scheme Variable} yggdrasil-service-type +The service type for connecting to the @uref{https://yggdrasil-network.github.io/, +Yggdrasil network}, an early-stage implementation of a fully end-to-end +encrypted IPv6 network. + +@quotation +Yggdrasil provides name-independent routing with cryptographically generated +addresses. Static addressing means you can keep the same address as long as +you want, even if you move to a new location, or generate a new address (by +generating new keys) whenever you want. +@uref{https://yggdrasil-network.github.io/2018/07/28/addressing.html} +@end quotation + +Pass it a value of @code{yggdrasil-configuration} to connect it to public +peers and/or local peers. + +Here is an example using public peers and a static address. The static +signing and encryption keys are defined in @file{/etc/yggdrasil-private.conf} +(the default value for @code{config-file}). + +@lisp +;; part of the operating-system declaration +(service yggdrasil-service-type + (yggdrasil-configuration + (autoconf? #f) ;; use only the public peers + (json-config + ;; choose one from + ;; https://github.com/yggdrasil-network/public-peers + '((peers . #("tcp://1.2.3.4:1337")))) + ;; /etc/yggdrasil-private.conf is the default value for config-file + )) +@end lisp +@example +# sample content for /etc/yggdrasil-private.conf +@{ + # Your public encryption key. Your peers may ask you for this to put + # into their AllowedEncryptionPublicKeys configuration. + EncryptionPublicKey: 378dc5... + + # Your private encryption key. DO NOT share this with anyone! + EncryptionPrivateKey: 0777... + + # Your public signing key. You should not ordinarily need to share + # this with anyone. + SigningPublicKey: e1664... + + # Your private signing key. DO NOT share this with anyone! + SigningPrivateKey: 0589d... +@} +@end example +@end defvr + +@deftp {Data Type} yggdrasil-configuration +Data type representing the configuration of Yggdrasil. + +@table @asis +@item @code{package} (default: @code{yggdrasil}) +Package object of Yggdrasil. + +@item @code{json-config} (default: @code{'()}) +Contents of @file{/etc/yggdrasil.conf}. Will be merged with +@file{/etc/yggdrasil-private.conf}. Note that these settings are stored in +the Guix store, which is readable to all users. @strong{Do not store your +private keys in it}. See the output of @code{yggdrasil -genconf} for a +quick overview of valid keys and their default values. + +@item @code{autoconf?} (default: @code{#f}) +Whether to use automatic mode. Enabling it makes Yggdrasil use adynamic IP +and peer with IPv6 neighbors. + +@item @code{log-level} (default: @code{'info}) +How much detail to include in logs. Use @code{'debug} for more detail. + +@item @code{log-to} (default: @code{'stdout}) +Where to send logs. By default, the service logs standard output to +@file{/var/log/yggdrasil.log}. The alternative is @code{'syslog}, which +sends output to the running syslog service. + +@item @code{config-file} (default: @code{"/etc/yggdrasil-private.conf"}) +What HJSON file to load sensitive data from. This is where private keys +should be stored, which are necessary to specify if you don't want a +randomized address after each restart. Use @code{#f} to disable. Options +defined in this file take precedence over @code{json-config}. Use the output +of @code{yggdrasil -genconf} as a starting point. To configure a static +address, delete everything except these options: + +@itemize +@item @code{EncryptionPublicKey} +@item @code{EncryptionPrivateKey} +@item @code{SigningPublicKey} +@item @code{SigningPrivateKey} +@end itemize +@end table +@end deftp + @node Unattended Upgrades @subsection Unattended Upgrades diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index 64f54e787f..9ec0f6a9ca 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -61,7 +61,9 @@ (define-module (gnu services networking) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-43) #:use-module (ice-9 match) + #:use-module (json) #:re-export (static-networking-service static-networking-service-type) #:export (%facebook-host-aliases @@ -180,7 +182,17 @@ (define-module (gnu services networking) pagekite-configuration-kitesecret pagekite-configuration-frontend pagekite-configuration-kites - pagekite-configuration-extra-file)) + pagekite-configuration-extra-file + + yggdrasil-service-type + yggdrasil-configuration + yggdrasil-configuration? + yggdrasil-configuration-autoconf? + yggdrasil-configuration-config-file + yggdrasil-configuration-log-level + yggdrasil-configuration-log-to + yggdrasil-configuration-json-config + yggdrasil-configuration-package)) ;;; Commentary: ;;; @@ -1750,4 +1762,107 @@ (define pagekite-service-type "Run @url{https://pagekite.net/,PageKite}, a tunneling solution to make local servers publicly accessible on the web, even behind NATs and firewalls."))) + +;;; +;;; Yggdrasil +;;; + +(define-record-type* + yggdrasil-configuration + make-yggdrasil-configuration + yggdrasil-configuration? + (package yggdrasil-configuration-package + (default yggdrasil)) + (json-config yggdrasil-configuration-json-config + (default '())) + (config-file yggdrasil-config-file + (default "/etc/yggdrasil-private.conf")) + (autoconf? yggdrasil-configuration-autoconf? + (default #f)) + (log-level yggdrasil-configuration-log-level + (default 'info)) + (log-to yggdrasil-configuration-log-to + (default 'stdout))) + +(define (yggdrasil-configuration-file config) + (define (scm->yggdrasil-json x) + (define key-value? + dotted-list?) + (define (param->camel str) + (string-concatenate + (map + string-capitalize + (string-split str (cut eqv? <> #\-))))) + (cond + ((key-value? x) + (let ((k (car x)) + (v (cdr x))) + (cons + (if (symbol? k) + (param->camel (symbol->string k)) + k) + v))) + ((list? x) (map scm->yggdrasil-json x)) + ((vector? x) (vector-map scm->yggdrasil-json x)) + (else x))) + (computed-file + "yggdrasil.conf" + #~(call-with-output-file #$output + (lambda (port) + ;; it's HJSON, so comments are a-okay + (display "# Generated by yggdrasil-service\n" port) + (display #$(scm->json-string + (scm->yggdrasil-json + (yggdrasil-configuration-json-config config))) + port))))) + +(define (yggdrasil-shepherd-service config) + "Return a for yggdrasil with CONFIG." + (define yggdrasil-command + #~(append + (list (string-append + #$(yggdrasil-configuration-package config) + "/bin/yggdrasil") + "-useconffile" + #$(yggdrasil-configuration-file config)) + (if #$(yggdrasil-configuration-autoconf? config) + '("-autoconf") + '()) + (let ((extraconf #$(yggdrasil-config-file config))) + (if extraconf + (list "-extraconffile" extraconf) + '())) + (list "-loglevel" + #$(symbol->string + (yggdrasil-configuration-log-level config)) + "-logto" + #$(symbol->string + (yggdrasil-configuration-log-to config))))) + (list (shepherd-service + (documentation "Connect to the Yggdrasil mesh network") + (provision '(yggdrasil)) + (requirement '(networking)) + (start #~(make-forkexec-constructor + #$yggdrasil-command + #:log-file "/var/log/yggdrasil.log" + #:group "yggdrasil")) + (stop #~(make-kill-destructor))))) + +(define %yggdrasil-accounts + (list (user-group (name "yggdrasil") (system? #t)))) + +(define yggdrasil-service-type + (service-type + (name 'yggdrasil) + (description + "Connect to the Yggdrasil mesh network. +See yggdrasil -genconf for config options.") + (extensions + (list (service-extension shepherd-root-service-type + yggdrasil-shepherd-service) + (service-extension account-service-type + (const %yggdrasil-accounts)) + (service-extension profile-service-type + (compose list yggdrasil-configuration-package)))))) + ;;; networking.scm ends here diff --git a/gnu/system/examples/yggdrasil.tmpl b/gnu/system/examples/yggdrasil.tmpl new file mode 100644 index 0000000000..be80bf4de9 --- /dev/null +++ b/gnu/system/examples/yggdrasil.tmpl @@ -0,0 +1,60 @@ +;; This is an operating system configuration template +;; for a "bare bones" setup, with no X11 display server. + +(use-modules (gnu)) +(use-service-modules networking ssh) +(use-package-modules admin curl networking screen) + +(operating-system + (host-name "ruby-guard-5545") + (timezone "Europe/Budapest") + (locale "en_US.utf8") + + ;; Boot in "legacy" BIOS mode, assuming /dev/sdX is the + ;; target hard disk, and "my-root" is the label of the target + ;; root file system. + (bootloader (bootloader-configuration + (bootloader grub-bootloader) + (target "/dev/sdX"))) + (file-systems (cons (file-system + (device (file-system-label "my-root")) + (mount-point "/") + (type "ext4")) + %base-file-systems)) + (users (cons (user-account + (name "alice") + (comment "Bob's sister") + (group "users") + ;; adding her to the yggdrasil group means she can use + ;; yggdrasilctl to modify the configuration + (supplementary-groups '("wheel" "yggdrasil"))) + %base-user-accounts)) + + ;; Globally-installed packages. + (packages (cons* screen curl %base-packages)) + + ;; Add services to the baseline: a DHCP client and + ;; an SSH server. + ;; If you add an /etc/yggdrasil-private.conf, you can log in to ssh + ;; using your Yggdrasil IPv6 address from another machine running Yggdrasil. + ;; Alternatively, the client can sit behind a router that has Yggdrasil. + ;; That file is specifically _not_ handled by Guix, because we don't want its + ;; contents to sit in the world-readable /gnu/store. + (services + (append + (list + (service dhcp-client-service-type) + (service yggdrasil-service-type + (yggdrasil-configuration + (log-to 'stdout) + (log-level 'debug) + (autoconf? #f) + (json-config + ;; choose a few from + ;; https://github.com/yggdrasil-network/public-peers + '((peers . #("tcp://1.2.3.4:1337")))) + (config-file #f))) + (service openssh-service-type + (openssh-configuration + (port-number 2222)))) + %base-services)))