diff --git a/conf-hooks.d/tailscale b/conf-hooks.d/tailscale new file mode 100644 index 0000000..f152492 --- /dev/null +++ b/conf-hooks.d/tailscale @@ -0,0 +1,3 @@ +# Set the umask for the generated initramfs since it may contain a tailscale +# authkey +UMASK=0077 diff --git a/config/config b/config/config new file mode 100644 index 0000000..90266b1 --- /dev/null +++ b/config/config @@ -0,0 +1,51 @@ +# +# Configuration options for the tailscale-initramfs boot scripts. +# You must run update-initramfs(8) to effect changes to this file (like +# for other files in the '/etc/tailscale/initramfs' directory). + +# +# Authkey to be used to authenticate to tailscale. Passed to "tailscale up" +# --authkey, so can also be file:/path/to/secret (the file will be copied into +# the initramfs). +# +# Note that the config (and any key) is stored in the initramfs, which is +# often outside of a cryptroot. +# - https://tailscale.com/kb/1068/acl-tags/#generate-an-auth-key-with-an-acl-tag +# - https://tailscale.com/kb/1111/ephemeral-nodes/ +# +TAILSCALE_AUTHKEY= + +# +# Hostname to pass to "tailscale up". +# Default: ${HOSTNAME}-initramfs. +# +#TAILSCALE_HOSTNAME= + +# +# Command-line options to pass to tailscale, in addition to +# --authkey"${TAILSCALE_AUTHKEY}" +# Default: none +# +#TAILSCALE_OPTIONS= + +# +# Command-line options to pass to tailscaled +# Default: none +# +#TAILSCALED_OPTIONS= + +# +# Set to any non-empty string to log out of tailscale before passing out of +# the initramfs. This is ineffective if some other package in the initramfs +# (dropbear-initramfs) brings down the external interfaces. See IFDOWN in +# dropbear-initramfs's config. +# Default: none +# +#TAILSCALE_LOGOUT= + +# +# Bring down interfaces matching this pattern before passing out of the +# initramfs. (Same behavior as dropbear-initramfs) +# Default: * +# +#IFDOWN=* diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..795b8c8 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +tailscale-initramfs (0.1) unstable; urgency=medium + + * Initial Release. + + -- Paul Aurich Fri, 14 Jan 2022 21:03:16 -0800 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..d1b3589 --- /dev/null +++ b/debian/control @@ -0,0 +1,20 @@ +Source: tailscale-initramfs +Section: net +Priority: optional +Maintainer: Paul Aurich +Build-Depends: debhelper-compat (= 13) +Standards-Version: 4.5.1 +Homepage: https://github.com/darkrain42/tailscale-initramfs +Vcs-Browser: https://github.com/darkrain42/tailscale-initramfs +Vcs-Git: https://github.com/darkrain42/tailscale-initramfs.git +Rules-Requires-Root: no + +Package: tailscale-initramfs +Architecture: all +Depends: initramfs-tools, tailscale, ${misc:Depends} +Recommends: ca-certificates +Suggests: dropbear-initramfs +Description: tailscale VPN - third-party initramfs integration + tailscale is a WireGuard VPN. This package provides initramfs integration, + intended to allow connectivity to/from a tailnet, e.g. to to allow remote + unlocking of a cryptroot. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..1bfba30 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,24 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: tailscale-initramfs +Upstream-Contact: Paul Aurich +Source: https://github.com/darkrain42/tailscale-initramfs + +Files: * +Copyright: 2022 Paul Aurich +License: GPL-2+ + +# Started from dropbear-initramfs scripts. +Files: scripts/* +Copyright: 2009 + 2015 Guilhem Moulin + 2022 Paul Aurich +License: GPL-2+ + +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + The full text of version 2 of the GPL is distributed in + /usr/share/common-licenses/GPL-2 on Debian systems. diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..98ac143 --- /dev/null +++ b/debian/install @@ -0,0 +1,5 @@ +conf-hooks.d/tailscale usr/share/initramfs-tools/conf-hooks.d +config/config etc/tailscale/initramfs +hooks/tailscale usr/share/initramfs-tools/hooks +scripts/init-bottom/tailscale usr/share/initramfs-tools/scripts/init-bottom +scripts/init-premount/tailscale usr/share/initramfs-tools/scripts/init-premount diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..e7c8830 --- /dev/null +++ b/debian/rules @@ -0,0 +1,14 @@ +#!/usr/bin/make -f + +#export DH_VERBOSE = 1 + +%: + dh $@ + +execute_after_dh_fixperms: + chmod 600 debian/tailscale-initramfs/etc/tailscale/initramfs/config + +override_dh_builddeb: + # Workaround for building on Ubuntu and installing on Debian (Ubuntu uses + # zstd). https://bugs.debian.org/892664 + dh_builddeb -- -Zxz diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/tailscale-initramfs.lintian-overrides b/debian/tailscale-initramfs.lintian-overrides new file mode 100644 index 0000000..a456594 --- /dev/null +++ b/debian/tailscale-initramfs.lintian-overrides @@ -0,0 +1 @@ +tailscale-initramfs: non-standard-file-perm etc/tailscale/initramfs/config 0600 != 0644 diff --git a/hooks/tailscale b/hooks/tailscale new file mode 100755 index 0000000..31b1b72 --- /dev/null +++ b/hooks/tailscale @@ -0,0 +1,65 @@ +#!/bin/sh + +PREREQ="" + +prereqs() +{ + echo "$PREREQ" +} + +case $1 in + prereqs) + prereqs + exit 0 + ;; +esac + +. /usr/share/initramfs-tools/hook-functions + +tailscale_warn() { + echo >&2 "tailscale: WARNING: $*" +} +tailscale_error() { + echo >&2 "tailscale: ERROR: $*" +} + +RV=0 + +copy_exec /usr/bin/tailscale bin +copy_exec /usr/sbin/tailscaled sbin + +copy_exec /bin/ip bin +copy_exec /usr/sbin/iptables sbin +copy_exec /usr/sbin/ip6tables sbin + +copy_modules_dir kernel/net/ipv4/netfilter +copy_modules_dir kernel/net/ipv6/netfilter +copy_modules_dir kernel/net/netfilter +manual_add_modules tun + +copy_file config /etc/ssl/certs/ca-certificates.crt +copy_file config /etc/hostname /etc/tailscale/initramfs/hostname + +if [ -e /etc/tailscale/initramfs/config ]; then + cp -pt "$DESTDIR/etc/tailscale/initramfs" /etc/tailscale/initramfs/config + . /etc/tailscale/initramfs/config + + case "${TAILSCALE_AUTHKEY-}" in + file:*) + AUTHKEY_FILE=${TAILSCALE_AUTHKEY#file:} + if [ -s "$AUTHKEY_FILE" ]; then + copy_file keyfile "$AUTHKEY_FILE" + else + tailscale_error "Auth key file '$AUTHKEY_FILE' does not exist or is empty." + RV=1 + fi + ;; + "") + tailscale_warn "\$TAILSCALE_AUTHKEY not set; logging into tailscale won't work!" + ;; + esac +else + tailscale_warn "Missing tailscale initramfs config; logging into tailscale won't work!" +fi + +exit $RV diff --git a/scripts/init-bottom/tailscale b/scripts/init-bottom/tailscale new file mode 100755 index 0000000..9b7da79 --- /dev/null +++ b/scripts/init-bottom/tailscale @@ -0,0 +1,77 @@ +#!/bin/sh + +#set -e + +PREREQ="" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in + prereqs) + prereqs + exit 0 + ;; +esac + +. /scripts/functions + +EXE="$(readlink -f /sbin/tailscaled)" && [ -f "$EXE" ] || exit 1 +PIDFILE="/run/tailscale.pid" +TAILSCALE_SHUTDOWN_TIMEOUT=60 +TAILSCALE_LOGOUT= +IFDOWN="*" + +if [ -e /etc/tailscale/initramfs/config ]; then + . /etc/tailscale/initramfs/config +fi + +wait_for_tailscaled() +{ + # shellcheck disable=SC2039 + # SC2039: In POSIX sh, 'local' is undefined. + local pid exe timer="$TAILSCALE_SHUTDOWN_TIMEOUT" + pid="$(cat "$PIDFILE" 2>/dev/null)" || return 1 + + while [ $timer -gt 0 ] && exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null)"; do + if [ "$exe" = "$EXE" ]; then + echo "$pid" + return 0 + fi + sleep 1 + timer=$(( timer - 1 )) + done + return 1 +} + + +if PID="$(wait_for_tailscaled)"; then + if [ -n "$TAILSCALE_LOGOUT" ]; then + log_begin_msg "Logging out of tailscale" + /bin/tailscale --socket=/run/tailscale/tailscaled.sock logout 2>>/run/initramfs/tailscale.log || true + log_end_msg + fi + + log_begin_msg "Stopping tailscale" + kill -TERM "$PID" + wait "$PID" || true + /sbin/tailscaled -cleanup 2>>/run/initramfs/tailscale.log + log_end_msg +fi + +rm -f "$PIDFILE" + +if [ "$BOOT" != nfs ] && [ "$IFDOWN" != none ]; then + for IFACE in /sys/class/net/$IFDOWN; do + [ -e "$IFACE" ] || continue + IFACE="${IFACE#/sys/class/net/}" + log_begin_msg "Bringing down $IFACE" + ip link set dev "$IFACE" down + ip address flush dev "$IFACE" + ip route flush dev "$IFACE" + log_end_msg + done +fi + +exit 0 diff --git a/scripts/init-premount/tailscale b/scripts/init-premount/tailscale new file mode 100755 index 0000000..6333193 --- /dev/null +++ b/scripts/init-premount/tailscale @@ -0,0 +1,64 @@ +#!/bin/sh + +#set -e + +PREREQ="udev" +prereqs() +{ + echo "$PREREQ" +} + +case $1 in + prereqs) + prereqs + exit 0 + ;; +esac + +[ -x /bin/tailscale ] || exit 0 + +. /scripts/functions + +if [ -e /etc/tailscale/initramfs/config ]; then + . /etc/tailscale/initramfs/config +fi + +if [ -z "${TAILSCALE_HOSTNAME-}" ]; then + if [ -f /etc/tailscale/initramfs/hostname ]; then + HOSTNAME=$(cat /etc/tailscale/initramfs/hostname) + else + HOSTNAME=$(hostname -s) + fi + + TAILSCALE_HOSTNAME=${HOSTNAME}-initramfs +fi + +# shellcheck disable=SC2039,SC2086 +run_tailscale() +{ + log_begin_msg "Starting tailscale" + + local options="--state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock" + + # FIXME: This races with dropbear-initramfs bringing up the network + # asynchronously + [ "$BOOT" = nfs ] || configure_networking + + # A little race-y to start the client before the daemon, but the client + # will attempt to connect to the socket for a while. + # https://github.com/tailscale/tailscale/blob/8cf1af8a0703c36256fc58e98ddb63b8907848f1/safesocket/safesocket.go#L119-L122 + /bin/tailscale --socket=/run/tailscale/tailscaled.sock up --authkey="${TAILSCALE_AUTHKEY}" --hostname="${TAILSCALE_HOSTNAME}" $TAILSCALE_OPTIONS & + + if [ "${debug:-}" != y ]; then + exec 2>/run/initramfs/tailscale.log + fi + exec /sbin/tailscaled $options $TAILSCALED_OPTIONS +} + +[ "$BOOT" = nfs ] && configure_networking + +modprobe tun +run_tailscale & +echo $! > /run/tailscale.pid + +exit 0