Ported rest of scripts for use by linux-template-builder

This commit is contained in:
Antoine Martin 2023-08-25 17:44:09 -04:00
parent cd96dcb95a
commit c97f16d5ba
Signed by: forge
GPG key ID: D62A472A4AA7D541
10 changed files with 95 additions and 206 deletions

View file

@ -1,4 +1,4 @@
# Makefile for Archlinux packages build
# Makefile for Alpine Linux packages build
#
# For "API" documentation check Makefile.generic
#
@ -113,23 +113,23 @@ endif
# BUILDER_REPO_DIR
dist-copy-out: pkg_list_path = $(ORIG_SRC)/$(OUTPUT_DIR)/$(notdir $(PACKAGE)).list
dist-copy-out:
@echo "--> Archlinux dist-copy-out (makefile)"
@echo "--> Alpine Linux dist-copy-out (makefile)"
@echo "--> Done:" >&3
@set -e;\
shopt -s nullglob;\
mkdir -p $(ORIG_SRC)/$(OUTPUT_DIR);\
echo -n > $(pkg_list_path);\
for arch_chroot_dir in $(CHROOT_DIR)/$(DIST_SRC)/; do\
arch_pkg_dir=$(ORIG_SRC)/$(OUTPUT_DIR);\
mkdir -p $$arch_pkg_dir;\
for pkg in $$arch_chroot_dir/*.pkg.tar.*; do\
echo " $$arch_pkg_dir/`basename $$pkg`" >&3 ;\
for alpine_chroot_dir in $(CHROOT_DIR)/$(DIST_SRC)/; do\
alpine_pkg_dir=$(ORIG_SRC)/$(OUTPUT_DIR);\
mkdir -p $$alpine_pkg_dir;\
for pkg in $$alpine_chroot_dir/*.pkg.tar.*; do\
echo " $$alpine_pkg_dir/`basename $$pkg`" >&3 ;\
echo "$(OUTPUT_DIR)/`basename $$pkg`" >> $(pkg_list_path);\
done;\
mkdir -p $(BUILDER_REPO_DIR)/pkgs;\
ln -f -t $(BUILDER_REPO_DIR)/pkgs $$arch_chroot_dir/*.pkg.tar.*;\
ln -f -t $(BUILDER_REPO_DIR)/pkgs $$alpine_chroot_dir/*.pkg.tar.*;\
done;\
mv -t $$arch_pkg_dir $$arch_chroot_dir/*.pkg.tar.*
mv -t $$alpine_pkg_dir $$alpine_chroot_dir/*.pkg.tar.*
### Additional targets

View file

@ -1,7 +1,7 @@
#!/bin/sh
# vim: set ts=4 sw=4 sts=4 et :
### prepare-chroot-base : Create a (any) chroot instance of Archlinux
### May be called from ./scripts/01_install_core.sh or ./prepare-chroot-archlinux
### prepare-chroot-base : Create a (any) chroot instance of Alpine Linux
### May be called from ./scripts/01_install_core.sh or ./prepare-chroot-base
echo "--> Alpine linux prepare-chroot-base"
INSTALLDIR="$1"

View file

@ -1,7 +1,7 @@
#!/bin/sh
# vim: set ts=4 sw=4 sts=4 et :
### prepare-chroot-builder : Create the build chroot instance of Archlinux
### prepare-chroot-builder : Create the build chroot instance of Alpine Linux
### (in which to build Qubes packages)
echo "--> Alpine Linux prepare-chroot-builder"
@ -46,14 +46,10 @@ if ! [ -d "${INSTALLDIR}/home/user" ]; then
echo " --> Synchronize resolv.conf..."
cp /etc/resolv.conf "${INSTALLDIR}/etc/resolv.conf"
# Checking for free disk free space doesn't work in chroots
# echo " --> Comment out CheckSpace in pacman.conf..."
# sed 's/^ *CheckSpace/#CheckSpace/g' -i "${INSTALLDIR}/etc/pacman.conf"
echo " --> Installing required makepkg dependencies..."
pkgs="alpine-sdk"
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"http_proxy='${REPO_PROXY}' apk add $pkgs"
"apk add $pkgs"
# makepkg internally calls sudo without '-E', so we need to add an
# env_keep to honor proxy settings
@ -65,17 +61,4 @@ EOF
# Register custom repository (it will be created later)
echo "file:///tmp/qubes-packages-mirror-repo/pkgs" | tee -a "${INSTALLDIR}/etc/apk/repositories"
# if [ -n "$USE_QUBES_REPO_VERSION" ]; then
# cat "${ALPINELINUX_PLUGIN_DIR}/repos/archlinux-qubes-repo-${USE_QUBES_REPO_VERSION}-current.conf" >> "${INSTALLDIR}/etc/pacman.conf"
# if [ "0$USE_QUBES_REPO_TESTING" -gt 0 ]; then
# cat "${ALPINELINUX_PLUGIN_DIR}repos/archlinux-qubes-repo-${USE_QUBES_REPO_VERSION}-current-testing.conf" \
# >> "${INSTALLDIR}/etc/pacman.conf"
# fi
# "${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" pacman-key --add - < \
# "${ALPINELINUX_PLUGIN_DIR}keys/qubes-repo-archlinux-key.asc"
# key_fpr=$(gpg --with-colons --show-key "${ALPINELINUX_PLUGIN_DIR}keys/qubes-repo-archlinux-key.asc" |\
# grep ^fpr: | cut -d : -f 10)
#"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" pacman-key --lsign "$key_fpr"
# fi
fi

View file

@ -10,13 +10,13 @@ ALPINELINUX_PLUGIN_DIR="${ALPINELINUX_PLUGIN_DIR:-"${SCRIPTSDIR}/.."}"
ALPINELINUX_VERSION=${ALPINELINUX_VERSION:-latest-stable}
ALPINELINUX_MIRROR=${ALPINELINUX_MIRROR:-https://dl-cdn.alpinelinux.org/alpine}
ALPINELINUX_ARCH=${ALPINELINUX_ARCH:-x86_64}
APKTOOLS_VERSION=${APKTOOLS_VERSION:-2.12.7-r3}
APKTOOLS_VERSION=${APKTOOLS_VERSION:-2.14.0-r2}
APKTOOLS_FILE="${APKTOOLS_FILE:-apk-tools-static-"$APKTOOLS_VERSION".apk}"
APKTOOLS_URL="$ALPINELINUX_MIRROR/$ALPINELINUX_VERSION/main/$ALPINELINUX_ARCH/$APKTOOLS_FILE"
[ "$VERBOSE" -ge 2 -o "$DEBUG" -gt 0 ] && set -x
mkdir -p "${CACHEDIR}/pacman_cache"
mkdir -p "${CACHEDIR}/apk_cache"
echo " --> Downloading Alpine Linux bootstrap (v${APKTOOLS_VERSION-})..."

View file

@ -1,6 +1,6 @@
#!/bin/bash -e
# vim: set ts=4 sw=4 sts=4 et :
### 01_install_core.sh : Create build chroot install of Archlinux using pacstrap
### 01_install_core.sh : Create build chroot install of Alpine Linux using apk
echo "--> Alpine Linux 01_install_core.sh"
ALPINELINUX_PLUGIN_DIR="${ALPINELINUX_PLUGIN_DIR:-"${SCRIPTSDIR}/.."}"
@ -10,8 +10,4 @@ ALPINELINUX_SRC_PREFIX="${ALPINELINUX_SRC_PREFIX:-https://dl-cdn.alpinelinux.org
set -e
[ "$VERBOSE" -ge 2 -o "$DEBUG" -gt 0 ] && set -x
# make sure pacman master private key is _not_ stored in the TemplateVM - see
# scripts/alpine-chroot for details
unset SKIP_VOLATILE_SECRET_KEY_DIR
"${ALPINELINUX_PLUGIN_DIR}/prepare-chroot-base" "$INSTALLDIR" "$DIST"

43
scripts/02_install_groups.sh Executable file
View file

@ -0,0 +1,43 @@
#!/bin/bash -e
# vim: set ts=4 sw=4 sts=4 et :
### 02_install_groups.sh : Install specified additional packages into chroot
echo "--> Alpine Linux 02_install_groups.sh"
set -e
if [ "${VERBOSE:-0}" -ge 2 ] || [ "${DEBUG:-0}" -eq 1 ]; then
set -x
fi
if [ -n "$TEMPLATE_FLAVOR" ]; then
PKGLISTFILE="${TEMPLATE_CONTENT_DIR}/packages_${TEMPLATE_FLAVOR}.list"
if ! [ -r "$PKGLISTFILE" ]; then
echo "ERROR: PKGLISTFILE '${PKGLISTFILE}' does not exist!"
exit 1
fi
else
PKGLISTFILE="${TEMPLATE_CONTENT_DIR}/packages.list"
fi
# Strip comments, then convert newlines to single spaces
PKGGROUPS="$(sed '/^ *#/d; s/ *#.*//' "${PKGLISTFILE}" | sed ':a;N;$!ba; s/\n/ /g; s/ */ /g')"
APKTOOLS_CACHE_DIR="${CACHE_DIR}/apk_cache"
export APKTOOLS_CACHE_DIR
ln -sf ../../var/cache/apk $INSTALLDIR/etc/apk/cache
echo " --> Enabling main and community repos..."
su -c "echo 'https://dl-cdn.alpinelinux.org/alpine/v3.18/main' > $INSTALLDIR/etc/apk/repositories"
su -c "echo 'https://dl-cdn.alpinelinux.org/alpine/v3.18/community' >> $INSTALLDIR/etc/apk/repositories"
echo " --> Synchronize resolv.conf..."
cp /etc/resolv.conf "${INSTALL_DIR}/etc/resolv.conf"
echo " --> Updating installed packages..."
"${TEMPLATE_CONTENT_DIR}/alpine-chroot" "$INSTALL_DIR" /bin/sh -c \
"apk update; apk upgrade"
echo " --> Installing Alpine Linux package groups..."
echo " --> Selected packages: ${PKGGROUPS}"
"${TEMPLATE_CONTENT_DIR}/alpine-chroot" "$INSTALL_DIR" /bin/sh -c \
"apk add ${PKGGROUPS}"

View file

@ -1,77 +1,35 @@
#!/bin/bash -e
# vim: set ts=4 sw=4 sts=4 et :
### 04_install_qubes.sh : Prepare chroot instance as a Qubes template
echo "--> Archlinux 04_install_qubes.sh"
echo "--> Alpine linux 04_install_qubes.sh"
PACMAN_CACHE_DIR="${CACHEDIR}/pacman_cache"
PACMAN_CUSTOM_REPO_DIR="${PWD}/pkgs-for-template/${DIST}"
export PACMAN_CACHE_DIR PACMAN_CUSTOM_REPO_DIR "ALL_PROXY=$REPO_PROXY"
APKTOOLS_CACHE_DIR="${CACHEDIR}/apk_cache"
APK_CUSTOM_REPO_DIR="${PWD}/pkgs-for-template/${DIST}"
export APK_CACHE_DIR APK_CUSTOM_REPO_DIR "ALL_PROXY=$REPO_PROXY"
set -e
if [ "$VERBOSE" -ge 2 ] || [ "$DEBUG" -gt 0 ]; then
set -x
fi
echo " --> Enabling x86 repos..."
su -c "echo '[multilib]' >> $INSTALLDIR/etc/pacman.conf"
su -c "echo 'SigLevel = PackageRequired' >> $INSTALLDIR/etc/pacman.conf"
su -c "echo 'Include = /etc/pacman.d/mirrorlist' >> $INSTALLDIR/etc/pacman.conf"
sudo sed -Ei 's,^#(Server *= *https://mirrors\.kernel\.org/),\1,' "$INSTALLDIR/etc/pacman.d/mirrorlist"
echo " --> Updating Qubes custom repository..."
# Repo Add need packages to be added in the right version number order as it only keeps the last entered package version
# shellcheck disable=SC2016
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
'cd /tmp/qubes-packages-mirror-repo; for pkg in `ls -v pkgs/*.pkg.tar.zst`; do repo-add pkgs/qubes.db.tar.gz "$pkg"; done;'
chown -R --reference="$PACMAN_CUSTOM_REPO_DIR" "$PACMAN_CUSTOM_REPO_DIR"
echo " --> Registering Qubes custom repository..."
# shellcheck disable=SC2016
su -c 'echo "[qubes] " >> $INSTALLDIR/etc/pacman.conf'
# shellcheck disable=SC2016
su -c 'echo "SigLevel = Never " >> $INSTALLDIR/etc/pacman.conf'
# shellcheck disable=SC2016
su -c 'echo "Server = file:///tmp/qubes-packages-mirror-repo/pkgs " >> $INSTALLDIR/etc/pacman.conf'
echo " --> Adding Qubes custom repository..."
su -c "echo 'https://lab.ilot.io/ayakael/repo-apk/-/raw/v3.18/qubes/r4.1' >> $INSTALLDIR/etc/apk/repositories"
wget "https://lab.ilot.io/ayakael/repo-apk/-/raw/v3.18/antoine.martin@protonmail.com-5b3109ad.rsa.pub" -P "$INSTALLDIR"/etc/apk/keys
echo " --> Synchronize resolv.conf..."
cp /etc/resolv.conf "${INSTALLDIR}/etc/resolv.conf"
echo " --> Updating pacman sources..."
echo " --> Updating apk repos..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"until http_proxy='${REPO_PROXY}' pacman -Syu; do sleep 1; done"
echo " --> Checking available qubes packages (for debugging only)..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"until http_proxy='${REPO_PROXY}' pacman -Ss qubes; do sleep 1; done"
if [ -n "$USE_QUBES_REPO_VERSION" ]; then
# we don't check specific value here, assume correct branch of
# meta-packages component
echo " --> Installing repository qubes package..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"http_proxy='${REPO_PROXY}' pacman -S --noconfirm qubes-vm-repo"
if [ "0$USE_QUBES_REPO_TESTING" -gt 0 ]; then
echo " --> Enabling current-testing repository..."
ln -s "90-qubes-${USE_QUBES_REPO_VERSION}-current-testing.conf.disabled" \
"$INSTALLDIR/etc/pacman.d/90-qubes-${USE_QUBES_REPO_VERSION}-current-testing.conf"
# abort if the file doesn't exist
if ! [ -f "$INSTALLDIR/etc/pacman.d/90-qubes-${USE_QUBES_REPO_VERSION}-current-testing.conf" ]; then
ls -l "$INSTALLDIR/etc/pacman.d/"
exit 1
fi
fi
echo " --> Updating pacman sources..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"until http_proxy='${REPO_PROXY}' pacman -Syu; do sleep 1; done"
fi
"apk update; apk upgrade"
echo " --> Installing mandatory qubes packages..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"until http_proxy='${REPO_PROXY}' pacman -S --noconfirm qubes-vm-dependencies; do sleep 1; done"
"apk add qubes-vm-dependencies"
echo " --> Installing recommended qubes apps"
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"until http_proxy='${REPO_PROXY}' pacman -S --noconfirm qubes-vm-recommended; do sleep 1; done"
"apk add qubes-vm-recommended"
echo " --> Updating template fstab file..."
cat >> "${INSTALLDIR}/etc/fstab" <<EOF
@ -90,23 +48,15 @@ cat >> "${INSTALLDIR}/etc/fstab" <<EOF
# Template Customizations
tmpfs /dev/shm tmpfs defaults,size=1G 0 0
# This MUST be a ramfs, not a tmpfs! The data here is incredibly sensitive
# (allows root access) and must not be leaked to disk.
tmpfs /etc/pacman.d/gnupg/private-keys-v1.d ramfs defaults,noexec,nosuid,nodev,mode=600 0 0
EOF
echo " --> Configuring system to our preferences..."
# Name network devices using simple names (ethX)
ln -s /dev/null "${INSTALLDIR}/etc/udev/rules.d/80-net-name-slot.rules"
# Enable some locales (incl. UTF-8)
sed 's/#en_US/en_US/g' -i "${INSTALLDIR}/etc/locale.gen"
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" locale-gen
echo 'LANG=en_US.UTF-8' > "${INSTALLDIR}/etc/locale.conf"
# Creating a random file in /lib/modules to ensure that the directory in never deleted when packages are removed
mkdir -p "${INSTALLDIR}/lib/modules"
touch "${INSTALLDIR}/lib/modules/QUBES_NODELETE"
# Remove qubes local repository definition
sed '/\[qubes]/,+2 d' -i "${INSTALLDIR}/etc/pacman.conf"
# add hcv0 to inittab
echo "hvc0::respawn:/sbin/getty -L hvc0 115200 vt220" >> "$INSTALLDIR"/etc/inittap
# add user:user
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" adduser -D -S user
# enable services
for i in udev udev-trigger xendriverdomain qubes-qrexec-agent qubes-db qubes-meminfo-writer qubes-sysinit qubes-core-early qubes-core qubes-gui-agent; do
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" rc-update add $i
done

View file

@ -1,37 +1,11 @@
#!/bin/bash -e
# vim: set ts=4 sw=4 sts=4 et :
### 09_cleanup.sh : Clean up the new chroot prior to image finalisation
echo "--> Archlinux 09_cleanup.sh"
echo "--> Alpine Linux 09_cleanup.sh"
set -e
[ "$VERBOSE" -ge 2 -o "$DEBUG" -gt 0 ] && set -x
# Remove unused packages and their dependencies (make dependencies)
cleanuppkgs="$("${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c 'pacman -Qdt | grep -v kernel | cut -d " " -f 1')"
if [ -n "$cleanuppkgs" ] ; then
echo " --> Packages that will be cleaned up: $cleanuppkgs"
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c "pacman --noconfirm -Rsc $cleanuppkgs"
else
echo " --> NB: No packages to clean up"
fi
echo " --> Removing video plugins..."
videopkgs="$("${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c 'pacman -Qs -q xf86-video')"
echo $videopkgs | "${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c 'pacman --noconfirm -Rsc -'
echo " --> Removing other font packages..."
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"pacman --noconfirm -Rsc xorg-fonts-100dpi xorg-fonts-75dpi"
# TODO: Be more deliberate here; is the umount necessary?
# Moreover, given where this script is called, should we be bothering
# alpine-chroot?
echo " --> Cleaning up pacman state..."
umount "${INSTALLDIR}/var/cache/pacman" || true
unset PACMAN_CACHE_DIR
"${SCRIPTSDIR}/alpine-chroot" "$INSTALLDIR" /bin/sh -c \
"pacman --noconfirm -Scc"
echo " --> Cleaning /etc/resolv.conf"
rm -f "${INSTALLDIR}/etc/resolv.conf"
cat > "${INSTALLDIR}/etc/resolv.conf" << EOF

View file

@ -14,76 +14,19 @@ chroot_add_mount() {
mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
setup_volatile_secret_key_dir() {
if [ "$SKIP_VOLATILE_SECRET_KEY_DIR" = "true" ]; then
return
fi
# This directory stores secret GPG keys, so its contents must be kept secret
# at all costs. Anyone with access to the files in it can compromise the
# built TemplateVM and all VMs based on it.
secret_key_dir="$1/etc/pacman.d/gnupg/private-keys-v1.d" &&
# private-keys-v1.d does not exist before we create the tmpfs
mkdir -p -m 0755 -- "${secret_key_dir%/*}" &&
mkdir -p -m 0000 -- "$secret_key_dir" &&
# Create README
[[ -f "$secret_key_dir/README" ]] || cat > "$secret_key_dir/README" <<'EOF' &&
# Why is this directory immutable?
In QubesOS, a TemplateVMs root volume is readable by all AppVMs based on it.
Therefore, it cannot be used to store secret data.
Pacman relies on the secrecy of its master key, which is normally stored in
`/etc/pacman.d/gnupg/private-keys-v1.d`. Anyone who has this key can sign
packages that Pacman will accept. Therefore, this key must not be stored on the
root volume. Furthermore, a user might (quite reasonably) assume that there is
no sensitive information on a TemplateVMs private volume unless they have added
it explicitly. So the master key cannot be stored there either.
The only remaining option is to use an ephemeral key that is only kept in
memory. That is what QubesOS does: during the build process, a ramfs is mounted
over /etc/pacman.d/gnupg/private-keys-v1.d, so that the secret key is kept in
memory. When the ramfs is unmounted, the key is destroyed along with it.
There is one remaining problem: relying on a mount point is not fail-safe. If
the ramfs fails to mount, or if the user later runs operations like
`pacman-key --init`, a new master key will be generated. It will later be
leaked to AppVMs based on this template.
To prevent this potentially disasterous failure, QubesOS marks the directory as
immutable. This ensures that nobody (not even root) can create any files in it.
When GPG tries to write its secret key to disk, it will fail, preventing any
leakage.
P.S.: Why a ramfs and not a tmpfs? Data on a ramfs can never be paged out to
disk, which ensures that this key is never leaked to swap partitions. GPG
internally locks its memory into RAM to prevent similar problems.
EOF
# Mark private-keys-v1.d immutable, so that files (such as secret keys)
# cannot accidentally be created in it.
chattr -R +i -- "$secret_key_dir" &&
# See the README above for why this is a ramfs
chroot_add_mount pacman-privkeys "$secret_key_dir" -t ramfs -o mode=000,nosuid,noexec,nodev || exit
}
chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'chroot_teardown' EXIT
# alpine-chroot drops the conditional bind mount on the chroot path, as
# it seemed to shadow mounts set up before arch-chroot was invoked
# it seemed to shadow mounts set up before alpine-chroot was invoked
# Set the correct permissions for mount points
chmod -- 0755 "$1/dev" "$1/run" &&
chmod -- 0555 "$1/proc" "$1/sys" &&
chmod -- 1777 "$1/tmp" &&
setup_volatile_secret_key_dir &&
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro &&
# alpine-chroot will never have occasion to use efivars, so don't bother

View file

@ -1,13 +1,21 @@
# X
xorg
xinit
xorg-server
xterm
setxkbmap
xrandr
# Basic utils
chrony
cups
ethtool
net-tools
sudo
wget
diffutils
openssh
grep
htop
# User env
ldns
@ -16,31 +24,23 @@ vim
# Fonts
terminus-font
ttf-bitstream-vera
ttf-dejavu
ttf-inconsolata
ttf-linux-libertine
# Particularly good Unicode coverage:
noto-fonts
noto-fonts-emoji
# Gnome
gnome-settings-daemon
gtk-engines
gvfs
lxappearance
# XFCE
leafpad
thunar
thunar-volman
# Desktop
pcmanfm
xfce4-terminal
xfce4-settings
evince
faenza-icon-theme-libreoffice
pavucontrol
# Major "productivity" applications
evince
firefox
thunderbird
# Hardening-related
checksec