Initial commit
This commit is contained in:
commit
cd96dcb95a
13 changed files with 726 additions and 0 deletions
196
Makefile.alpinelinux
Normal file
196
Makefile.alpinelinux
Normal file
|
@ -0,0 +1,196 @@
|
|||
# Makefile for Archlinux packages build
|
||||
#
|
||||
# For "API" documentation check Makefile.generic
|
||||
#
|
||||
# Variables supposed to be in component's Makefile.builder:
|
||||
# ALPINE_BUILD_DIRS - list of alpinelinux directories containing build sripts (PKGFILES...)
|
||||
|
||||
### Variables required as per Makefile.generic:
|
||||
#
|
||||
# PACKAGE_LIST - list of packages to build. Targets 'build-dep', 'package' and 'copy-out'
|
||||
# will be run for each word on the list, with PACKAGE set to current word
|
||||
# DIST_BUILD_DIR - basedir for sources inside of chroot - relative to
|
||||
# CHROOT_DIR (qubes-src will be created in this directory)
|
||||
#
|
||||
PACKAGE_LIST = $(ALPINE_BUILD_DIRS)
|
||||
DIST_BUILD_DIR = /home/user
|
||||
|
||||
### Local variables
|
||||
RUN_AS_USER = user
|
||||
|
||||
ALPINELINUX_MIRROR ?= https://dl-cdn.alpinelinux.org/alpine
|
||||
|
||||
DEBUG ?= 0
|
||||
ifneq ($(DEBUG),0)
|
||||
$(info ╔══ DEBUG ══════════════════════════════════════════════════════════════════════)
|
||||
$(info ║ Repo Variables)
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ SRC_DIR: $(SRC_DIR)) # qubes-src
|
||||
$(info ║ CHROOT_DIR: $(CHROOT_DIR)) # /home/user/qubes-builder/chroot-alpinelinux
|
||||
$(info ║ BUILDER_REPO_DIR: $(BUILDER_REPO_DIR)) # /home/user/qubes-builder/qubes-packages-mirror-repo/alpinelinux
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ Chroot Variables)
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ CHROOT_DIR: $(CHROOT_DIR)) #
|
||||
$(info ║ DIST_BUILD_DIR: $(DIST_BUILD_DIR)) # /home/user
|
||||
$(info ║ DIST_SRC: $(DIST_SRC)) # /home/user/qubes-src/repo
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ Build Variables)
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ ALPINELINUX_PLUGIN_DIR: $(ALPINELINUX_PLUGIN_DIR)) # /home/user/qubes-builder/qubes-src/builder-alpinelinux
|
||||
$(info ║ CACHEDIR: $(CACHEDIR)) # cache/alpinelinux
|
||||
$(info ║ PACKAGE_LIST: $(PACKAGE_LIST)) # alpinelinux
|
||||
$(info ║ DISTRIBUTION: $(DISTRIBUTION)) # alpinelinux
|
||||
$(info ║ DIST: $(DIST)) #
|
||||
$(info ║ COMPONENT: $(COMPONENT)) #
|
||||
$(info ║ PACKAGE_SET: $(PACKAGE_SET)) # vm
|
||||
$(info ║ CHROOT_ENV: $(CHROOT_ENV)) # BACKEND_VMM=xen
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ Repository Variables)
|
||||
$(info ╠───────────────────────────────────────────────────────────────────────────────)
|
||||
$(info ║ UPDATE_REPO: $(UPDATE_REPO)) #
|
||||
$(info ║ TARGET_REPO: $(TARGET_REPO)) #
|
||||
$(info ║ SNAPSHOT_REPO: $(SNAPSHOT_REPO)) #
|
||||
$(info ║ SNAPSHOT_FILE: $(SNAPSHOT_FILE)) #
|
||||
$(info ║ REPO_PROXY: $(REPO_PROXY)) #
|
||||
$(info ║ ALPINELINUX_SRC_PREFIX: $(ALPINELINUX_SRC_PREFIX)) # http://mirrors.kernel.org/alpinelinux
|
||||
$(info ║ ALPINELINUX_REL_VERSION: $(ALPINELINUX_REL_VERSION)) #
|
||||
$(info ║ ALPINELINUX_MIRROR: $(ALPINELINUX_MIRROR)) # mirror.rackspace.com
|
||||
$(info ╚═══════════════════════════════════════════════════════════════════════════════)
|
||||
endif
|
||||
|
||||
define bin_packages
|
||||
$(shell cd $(ORIG_SRC) && \
|
||||
if [ 0`stat -c %Y $(OUTPUT_DIR)/$(notdir $(1)).list 2>/dev/null` -ge \
|
||||
0`git log -1 --pretty=format:%ct` ]; then \
|
||||
cat $(OUTPUT_DIR)/$(notdir $(1)).list; \
|
||||
else \
|
||||
echo unknown.package; \
|
||||
fi)
|
||||
endef
|
||||
|
||||
### Targets required by Makefile.generic to build packages:
|
||||
|
||||
# dist-prepare-chroot - initial preparation of chroot environment
|
||||
# Specifically, load mounts for the build chroot
|
||||
dist-prepare-chroot: $(CHROOT_DIR)/home/user/.prepared_base
|
||||
@echo "--> Alpine linux dist-prepare-chroot (makefile):"
|
||||
@mkdir -p "$(BUILDER_REPO_DIR)/pkgs"
|
||||
@mkdir -p "$(CHROOT_DIR)/var/cache/apk"
|
||||
@mkdir -p "$(CHROOT_DIR)/tmp/qubes-packages-mirror-repo"
|
||||
|
||||
# Create the build chroot, if it does not already exist
|
||||
$(CHROOT_DIR)/home/user/.prepared_base: $(ALPINELINUX_PLUGIN_DIR)/prepare-chroot-builder
|
||||
@echo "--> Alpine linux preparing build chroot environment"
|
||||
@sudo -E "$(ALPINELINUX_PLUGIN_DIR)/prepare-chroot-builder" "$(CHROOT_DIR)" $(DIST) || exit 1
|
||||
@touch "$(CHROOT_DIR)/home/user/.prepared_base"
|
||||
|
||||
# dist-prep - some preparation of sources (if needed)
|
||||
dist-prep:
|
||||
@true
|
||||
|
||||
# dist-build-dep - install build dependencies (should operate on chroot directory)
|
||||
dist-build-dep:
|
||||
@echo "--> Alpine linux dist-build-dep (makefile)"
|
||||
@echo " --> Generate locales..."
|
||||
@echo "en_US.UTF-8 UTF-8" | sudo tee -a $(CHROOT_DIR)/etc/locale.gen
|
||||
@sudo $(CHROOT_ENV) chroot "$(CHROOT_DIR)" locale-gen
|
||||
@echo "LANG=en_US.UTF-8" | sudo tee -a $(CHROOT_DIR)/etc/locale.conf
|
||||
@sudo -E "$(ALPINELINUX_PLUGIN_DIR)/update-local-repo.sh" $(DIST)
|
||||
|
||||
# dist-package - compile package (should operate on chroot directory)
|
||||
# TODO: makepkg doesn't seem to honor $http_proxy
|
||||
dist-package:
|
||||
@echo "--> Alpine linux dist-package (makefile)"
|
||||
ifndef PACKAGE
|
||||
$(error "PACKAGE need to be set!")
|
||||
endif
|
||||
@echo " --> Building package in $(DIST_SRC)"
|
||||
sudo $(CHROOT_ENV) /usr/sbin/chroot "$(CHROOT_DIR)" sh -c -l "abuild -r $(ABUILD_ARGS)"
|
||||
|
||||
# dist-copy-out - copy compiled package out of chroot env; this target should
|
||||
# move packages to ORIG_SRC (distro-specific subdir) and hardlink them to
|
||||
# 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 "--> 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 ;\
|
||||
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.*;\
|
||||
done;\
|
||||
mv -t $$arch_pkg_dir $$arch_chroot_dir/*.pkg.tar.*
|
||||
|
||||
### Additional targets
|
||||
|
||||
# Sign packages
|
||||
sign: sign_client = $(if $(GNUPG),$(GNUPG),gpg)
|
||||
sign:
|
||||
@if [ -d $(ORIG_SRC)/$(OUTPUT_DIR) ]; then \
|
||||
cd $(ORIG_SRC)/$(OUTPUT_DIR); \
|
||||
for filename in *.pkg.tar.zst; do\
|
||||
echo $$filename; \
|
||||
$(sign_client) --yes --local-user "$(ALPINELINUX_SIGN_KEY)" --detach-sign -o "$$filename.sig" "$$filename";\
|
||||
ln -f -t $(BUILDER_REPO_DIR)/pkgs "$$filename.sig";\
|
||||
done; \
|
||||
fi
|
||||
|
||||
|
||||
# Copies requested packages (based on PACKAGE_SET, COMPONENT, DIST) to
|
||||
# requested repository (UPDATE_REPO)
|
||||
update-repo:
|
||||
ifndef UPDATE_REPO
|
||||
$(error "You need to specify destination repo in UPDATE_REPO variable")
|
||||
endif
|
||||
ifeq (,$(PACKAGE_LIST))
|
||||
@true
|
||||
else
|
||||
ifdef SNAPSHOT_FILE
|
||||
@echo -n > $(SNAPSHOT_FILE)
|
||||
endif
|
||||
mkdir -p $(UPDATE_REPO)/pkgs; \
|
||||
for package in $(PACKAGE_LIST); do\
|
||||
pkgnames=`cat $(ORIG_SRC)/$(OUTPUT_DIR)/$$package.list`;\
|
||||
for pkgname in $$pkgnames; do\
|
||||
ln -f $(ORIG_SRC)/$$pkgname $(UPDATE_REPO)/pkgs/ || exit 1;\
|
||||
ln -f $(ORIG_SRC)/$$pkgname.sig $(UPDATE_REPO)/pkgs/ 2>/dev/null;\
|
||||
if [ -n "$(SNAPSHOT_FILE)" ]; then \
|
||||
echo $$pkgname >> "$(SNAPSHOT_FILE)"; \
|
||||
fi; \
|
||||
done; \
|
||||
done
|
||||
endif
|
||||
|
||||
|
||||
update-repo-from-snapshot: packages = $(shell cat $(SNAPSHOT_FILE) 2>/dev/null)
|
||||
update-repo-from-snapshot:
|
||||
ifndef UPDATE_REPO
|
||||
$(error "You need to specify destination repo in UPDATE_REPO variable")
|
||||
endif
|
||||
mkdir -p $(UPDATE_REPO)/pkgs; \
|
||||
for f in $(packages); do \
|
||||
ln -f $(subst /$(TARGET_REPO)/,/$(SNAPSHOT_REPO)/,$(UPDATE_REPO)/)pkgs/`basename $$f` $(UPDATE_REPO)/pkgs/ || exit 1; \
|
||||
ln -f $(subst /$(TARGET_REPO)/,/$(SNAPSHOT_REPO)/,$(UPDATE_REPO)/)pkgs/`basename $$f`.sig $(UPDATE_REPO)/pkgs/ 2>/dev/null; \
|
||||
done
|
||||
|
||||
check-repo: packages = $(foreach pkg,$(PACKAGE_LIST),$(call bin_packages,$(pkg)))
|
||||
check-repo:
|
||||
ifndef UPDATE_REPO
|
||||
$(error "You need to specify destination repo in UPDATE_REPO variable")
|
||||
endif
|
||||
@if [ -n "$(strip $(packages))" ]; then \
|
||||
cd $(ORIG_SRC) && ls $(addprefix $(UPDATE_REPO)/pkgs/, $(notdir $(packages))) >/dev/null 2>&1 || exit 1; \
|
||||
else \
|
||||
echo "`tput bold`No packages defined by $(PACKAGE_LIST), syntax error?`tput sgr0`"; \
|
||||
exit 1; \
|
||||
fi
|
8
Makefile.builder
Normal file
8
Makefile.builder
Normal file
|
@ -0,0 +1,8 @@
|
|||
ifeq ($(DIST),alpinelinux)
|
||||
ALPINELINUX_PLUGIN_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
DISTRIBUTION := alpinelinux
|
||||
BUILDER_MAKEFILE = $(ALPINELINUX_PLUGIN_DIR)Makefile.alpinelinux
|
||||
TEMPLATE_SCRIPTS = $(ALPINELINUX_PLUGIN_DIR)scripts
|
||||
endif
|
||||
|
||||
# vim: ft=make
|
36
prepare-chroot-base
Executable file
36
prepare-chroot-base
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/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
|
||||
echo "--> Alpine linux prepare-chroot-base"
|
||||
|
||||
INSTALLDIR="$1"
|
||||
DISTRO="$2" # aka elsewhere as $DIST
|
||||
|
||||
BOOTSTRAP_DIR="${CACHEDIR}/bootstrap"
|
||||
ALPINELINUX_PLUGIN_DIR="${ALPINELINUX_PLUGIN_DIR:-"${SCRIPTSDIR}/.."}"
|
||||
ALPINELINUX_VERSION=${ALPINELINUX_VERSION:-latest-stable}
|
||||
ALPINELINUX_MIRROR=${ALPINELINUX_MIRROR:-http://dl-cdn.alpinelinux.org/alpine}
|
||||
|
||||
set -e
|
||||
if [ "$VERBOSE" -ge 2 ] || [ "$DEBUG" -gt 0 ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
exit_prepare() {
|
||||
local exit_code=$?
|
||||
echo " --> Unbinding INSTALLDIR..."
|
||||
umount ${BOOTSTRAP_DIR}/mnt || true
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
trap 'exit_prepare' 0 1 2 3 6 15
|
||||
|
||||
echo " --> Binding INSTALLDIR '${INSTALLDIR}' to bootstrap environment..."
|
||||
mkdir -p "${BOOTSTRAP_DIR}/mnt"
|
||||
mount --bind "$INSTALLDIR" "${BOOTSTRAP_DIR}/mnt"
|
||||
|
||||
echo " --> Installing core apk packages..."
|
||||
"$BOOTSTRAP_DIR"/sbin/apk.static -X $ALPINELINUX_MIRROR/$ALPINELINUX_VERSION/main -U --allow-untrusted -p "$INSTALLDIR" --initdb add alpine-base
|
||||
|
||||
touch "${INSTALLDIR}/.prepared_base"
|
81
prepare-chroot-builder
Executable file
81
prepare-chroot-builder
Executable file
|
@ -0,0 +1,81 @@
|
|||
#!/bin/sh
|
||||
# vim: set ts=4 sw=4 sts=4 et :
|
||||
|
||||
### prepare-chroot-builder : Create the build chroot instance of Archlinux
|
||||
### (in which to build Qubes packages)
|
||||
echo "--> Alpine Linux prepare-chroot-builder"
|
||||
|
||||
PLUGIN_DIR="$(dirname $0)"
|
||||
INSTALLDIR="$1"
|
||||
DISTRO="$2"
|
||||
|
||||
SCRIPTSDIR=${ALPINELINUX_PLUGIN_DIR}scripts
|
||||
export INSTALLDIR SCRIPTSDIR
|
||||
|
||||
# do not make volatile private key dir for the package builds themselves
|
||||
# this is interpreted by scripts/alpine-chroot
|
||||
SKIP_VOLATILE_SECRET_KEY_DIR=true
|
||||
export SKIP_VOLATILE_SECRET_KEY_DIR
|
||||
|
||||
set -e
|
||||
[ "$VERBOSE" -ge 1 -o "$DEBUG" -gt 0 ] && echo " --> INSTALLDIR: '$INSTALLDIR'"
|
||||
[ "$VERBOSE" -ge 2 -o "$DEBUG" -gt 0 ] && set -x
|
||||
|
||||
# /home/user will exist if we've completed the build previously
|
||||
if ! [ -d "${INSTALLDIR}/home/user" ]; then
|
||||
# It's non-existance means this is likely the initial run, so build it
|
||||
|
||||
mkdir -p "$INSTALLDIR"
|
||||
|
||||
echo " --> Installing alpine linux build root:"
|
||||
"${PLUGIN_DIR}/prepare-chroot-base" "$INSTALLDIR" "$DISTRO"
|
||||
|
||||
echo " --> Configure system accounts..."
|
||||
[ -n "$SUDO_UID" ] && USER_OPTS="-u ${SUDO_UID}"
|
||||
[ -n "$USER_UID" ] && USER_OPTS="-u ${USER_UID}"
|
||||
if [ -n "$USER_GID" ]; then
|
||||
chroot "$INSTALLDIR" /bin/addgroup -g "$USER_GID" user
|
||||
elif [ -n "$SUDO_GID" ]; then
|
||||
chroot "$INSTALLDIR" /bin/addgroup -g "$SUDO_GID" user
|
||||
else
|
||||
chroot "$INSTALLDIR" /bin/addgroup user
|
||||
fi
|
||||
chroot "$INSTALLDIR" /bin/sh -c \
|
||||
"useradd -g user -G wheel $USER_OPTS -m user; su -c 'mkdir qubes-src' - user"
|
||||
|
||||
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"
|
||||
|
||||
# makepkg internally calls sudo without '-E', so we need to add an
|
||||
# env_keep to honor proxy settings
|
||||
echo " --> Configure sudo..."
|
||||
cat > "${INSTALLDIR}/etc/sudoers.d/qubes-build-user" <<EOF
|
||||
Defaults env_keep += "http_proxy https_proxy ftp_proxy"
|
||||
%wheel ALL=(ALL) NOPASSWD: ALL
|
||||
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
|
34
scripts/00_prepare.sh
Executable file
34
scripts/00_prepare.sh
Executable file
|
@ -0,0 +1,34 @@
|
|||
#! /bin/bash --
|
||||
|
||||
set -euo pipefail
|
||||
echo "--> Alpine Linux 00_prepare.sh"
|
||||
|
||||
if [[ -n "${REPO_PROXY+x}" ]]; then
|
||||
export "https_proxy=$REPO_PROXY" "http_proxy=$REPO_PROXY"
|
||||
fi
|
||||
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_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"
|
||||
|
||||
echo " --> Downloading Alpine Linux bootstrap (v${APKTOOLS_VERSION-})..."
|
||||
|
||||
wget -N -P "$CACHEDIR" "$APKTOOLS_URL"
|
||||
|
||||
if [ "${CACHEDIR}/${APKTOOLS_FILE}" -nt "${CACHEDIR}/bootstrap/.extracted" ]; then
|
||||
echo " --> Extracting bootstrap tarball (nuking previous directory)..."
|
||||
rm -rf "${CACHEDIR}/bootstrap/"
|
||||
mkdir -p "${CACHEDIR}/bootstrap"
|
||||
# By default will extract to a "root.x86_64" directory; strip that off
|
||||
tar -xzC "${CACHEDIR}/bootstrap" -f "${CACHEDIR}/${APKTOOLS_FILE}"
|
||||
touch "${CACHEDIR}/bootstrap/.extracted"
|
||||
else
|
||||
echo " --> NB: Bootstrap tarball not newer than bootstrap directory, will use existing!"
|
||||
fi
|
17
scripts/01_install_core.sh
Executable file
17
scripts/01_install_core.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash -e
|
||||
# vim: set ts=4 sw=4 sts=4 et :
|
||||
### 01_install_core.sh : Create build chroot install of Archlinux using pacstrap
|
||||
echo "--> Alpine Linux 01_install_core.sh"
|
||||
|
||||
ALPINELINUX_PLUGIN_DIR="${ALPINELINUX_PLUGIN_DIR:-"${SCRIPTSDIR}/.."}"
|
||||
ALPINELINUX_VERSION=${ALPINELINUX_VERSION:-latest-stable}
|
||||
ALPINELINUX_SRC_PREFIX="${ALPINELINUX_SRC_PREFIX:-https://dl-cdn.alpinelinux.org/alpine/"$ALPINELINUX_VERSION"/main}"
|
||||
|
||||
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"
|
112
scripts/04_install_qubes.sh
Executable file
112
scripts/04_install_qubes.sh
Executable file
|
@ -0,0 +1,112 @@
|
|||
#!/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"
|
||||
|
||||
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"
|
||||
|
||||
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 " --> Synchronize resolv.conf..."
|
||||
cp /etc/resolv.conf "${INSTALLDIR}/etc/resolv.conf"
|
||||
|
||||
echo " --> Updating pacman sources..."
|
||||
"${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
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
echo " --> Updating template fstab file..."
|
||||
cat >> "${INSTALLDIR}/etc/fstab" <<EOF
|
||||
#
|
||||
# /etc/fstab: static file system information
|
||||
#
|
||||
|
||||
# Templates Directories
|
||||
/dev/mapper/dmroot / ext4 defaults,discard,noatime 1 1
|
||||
/dev/xvdb /rw auto noauto,defaults,discard 1 2
|
||||
/dev/xvdc1 swap swap defaults 0 0
|
||||
|
||||
# Template Binds
|
||||
/rw/home /home none noauto,bind,defaults 0 0
|
||||
/rw/usrlocal /usr/local none noauto,bind,defaults 0 0
|
||||
|
||||
# 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"
|
40
scripts/09_cleanup.sh
Executable file
40
scripts/09_cleanup.sh
Executable file
|
@ -0,0 +1,40 @@
|
|||
#!/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"
|
||||
|
||||
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
|
||||
# This file intentionally left blank
|
||||
|
||||
EOF
|
144
scripts/alpine-chroot
Executable file
144
scripts/alpine-chroot
Executable file
|
@ -0,0 +1,144 @@
|
|||
#!/bin/bash
|
||||
###
|
||||
### A stripped-down version of the 'arch-chroot' script bundled with Archlinux
|
||||
###
|
||||
### This version drops unused code and makes a fey key modifications,
|
||||
### annotated where they occur below.
|
||||
###
|
||||
|
||||
shopt -s extglob
|
||||
|
||||
die() { error "$@"; exit 1; }
|
||||
|
||||
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 TemplateVM’s 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 TemplateVM’s 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
|
||||
|
||||
# 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
|
||||
# mounting efivarfs here
|
||||
chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid &&
|
||||
chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec &&
|
||||
chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev &&
|
||||
chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
|
||||
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid ||
|
||||
|
||||
exit
|
||||
if [[ -d "$APKTOOLS_CACHE_DIR" ]]; then
|
||||
APKTOOLS_CACHE_MOUNT_DIR="${APKTOOLS_CACHE_MOUNT_DIR:-$1/var/cache/apk}"
|
||||
mkdir -p "$APKTOOLS_CACHE_MOUNT_DIR"
|
||||
# Cached qubes packages may be from old runs and throw checksum errors
|
||||
chroot_add_mount "$APKTOOLS_CACHE_DIR" "$APKTOOLS_CACHE_MOUNT_DIR" --bind
|
||||
fi
|
||||
if [[ -d "$APKTOOLS_CUSTOM_REPO_DIR" ]]; then
|
||||
mkdir -p "$1/tmp/qubes-packages-mirror-repo"
|
||||
chroot_add_mount "$APKTOOLS_CUSTOM_REPO_DIR" "$1/tmp/qubes-packages-mirror-repo" --bind
|
||||
fi
|
||||
}
|
||||
|
||||
chroot_teardown() {
|
||||
# alpine-chroot kills gpg-agent, started by pacman-key, which otherwise
|
||||
# keeps the mounts busy and prevents unmounting
|
||||
pkill gpg-agent
|
||||
umount "${CHROOT_ACTIVE_MOUNTS[@]}"
|
||||
unset CHROOT_ACTIVE_MOUNTS
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
usage: ${0##*/} chroot-dir [command]
|
||||
|
||||
-h Print this help message
|
||||
|
||||
If 'command' is unspecified, ${0##*/} will launch /bin/sh.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ -z $1 || $1 = @(-h|--help) ]]; then
|
||||
usage
|
||||
exit $(( $# ? 0 : 1 ))
|
||||
fi
|
||||
|
||||
(( EUID == 0 )) || die 'This script must be run with root privileges'
|
||||
chrootdir=$1
|
||||
shift
|
||||
|
||||
[[ -d $chrootdir ]] || die "Can't create chroot on non-directory %s" "$chrootdir"
|
||||
|
||||
chroot_setup "$chrootdir" || die "failed to setup chroot %s" "$chrootdir"
|
||||
# alpine-chroot already has /etc/resolv.conf managed by the builder
|
||||
# scripts, so no need to bind to the host system's resolv.conf here
|
||||
|
||||
SHELL=/bin/sh unshare --fork --pid chroot "$chrootdir" "$@"
|
1
scripts/network
Normal file
1
scripts/network
Normal file
|
@ -0,0 +1 @@
|
|||
NETWORKING=yes
|
46
scripts/packages.list
Normal file
46
scripts/packages.list
Normal file
|
@ -0,0 +1,46 @@
|
|||
# X
|
||||
xorg
|
||||
xterm
|
||||
|
||||
# Basic utils
|
||||
ethtool
|
||||
net-tools
|
||||
sudo
|
||||
wget
|
||||
diffutils
|
||||
|
||||
# User env
|
||||
ldns
|
||||
tmux
|
||||
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
|
||||
xfce4-terminal
|
||||
xfce4-settings
|
||||
|
||||
# Major "productivity" applications
|
||||
evince
|
||||
firefox
|
||||
thunderbird
|
||||
|
||||
# Hardening-related
|
||||
checksec
|
10
scripts/packages_minimal.list
Normal file
10
scripts/packages_minimal.list
Normal file
|
@ -0,0 +1,10 @@
|
|||
# X
|
||||
xorg
|
||||
xterm
|
||||
|
||||
# Basic utils
|
||||
ethtool
|
||||
net-tools
|
||||
sudo
|
||||
wget
|
||||
diffutils
|
1
scripts/resolv.conf
Normal file
1
scripts/resolv.conf
Normal file
|
@ -0,0 +1 @@
|
|||
# This file intentionally left blank
|
Loading…
Reference in a new issue