308 lines
8.8 KiB
Bash
308 lines
8.8 KiB
Bash
#!/bin/bash
|
|
|
|
# Author: Wallun <wallun@disroot.org>
|
|
# This script has to be run from archlinux iso.
|
|
# It allows a fast encrypted VM deployment with almost nothing but the
|
|
# essential.
|
|
|
|
# Variables
|
|
SWAP=true
|
|
|
|
# Check arguments
|
|
if [[ "${#}" -lt "4" ]]; then
|
|
echo "Usage: ${0} -h MACHINE_HOSTNAME -d DEVICE"
|
|
exit 1;
|
|
else
|
|
while getopts ":h:d:s" OPTION; do
|
|
case "${OPTION}" in
|
|
h)
|
|
MACHINE_HOSTNAME="${OPTARG}";
|
|
;;
|
|
d)
|
|
DEVICE="${OPTARG}";
|
|
;;
|
|
s)
|
|
SWAP=false
|
|
;;
|
|
*)
|
|
;;
|
|
esac;
|
|
done
|
|
|
|
if [[ -z "${MACHINE_HOSTNAME}" ]]; then
|
|
echo "MACHINE_HOSTNAME is not defined";
|
|
exit 2;
|
|
fi;
|
|
|
|
if [[ -z "${DEVICE}" ]]; then
|
|
echo "DEVICE is not defined";
|
|
exit 3;
|
|
fi;
|
|
|
|
if [[ ! -b "${DEVICE}" ]]; then
|
|
echo "${DEVICE} is not a block device"
|
|
exit 4;
|
|
fi;
|
|
fi;
|
|
|
|
# Check configuration
|
|
CONFIG_FILE=$(dirname "${0}")/config
|
|
if [[ ! -f "${CONFIG_FILE}" ]]; then
|
|
echo "${CONFIG_FILE} does not exist"
|
|
exit 10;
|
|
else
|
|
# shellcheck source=config
|
|
source "${CONFIG_FILE}";
|
|
if [[ -z "${PASSPHRASE}" ]]; then
|
|
echo "PASSPHRASE is not defined";
|
|
exit 11
|
|
fi;
|
|
if [[ -z "${ADMIN_NAME}" ]]; then
|
|
echo "ADMIN_NAME is not defined in config file"
|
|
exit 12;
|
|
fi;
|
|
if [[ -z "${AUTHORIZED_KEY}" ]]; then
|
|
echo "AUTHORIZED_KEY is not defined in config file"
|
|
fi
|
|
fi;
|
|
|
|
# Check if BIOS or UEFI
|
|
if [[ -d /sys/firmware/efi/efivars ]]; then
|
|
readonly MODE="uefi";
|
|
else
|
|
readonly MODE="bios";
|
|
fi;
|
|
|
|
# Enable NTP
|
|
timedatectl set-ntp on;
|
|
|
|
# Create partitions
|
|
SWAP_SIZE=$(free -m | grep "Mem" | awk '{print $2}')
|
|
|
|
parted -s -a optimal "${DEVICE}" mklabel gpt;
|
|
|
|
if [[ "${MODE}" == bios ]]; then
|
|
parted -s -a optimal "${DEVICE}" unit mib mkpart primary 1 3
|
|
parted -s -a optimal "${DEVICE}" name 1 grub;
|
|
parted -s -a optimal "${DEVICE}" set 1 bios on;
|
|
|
|
parted -s -a optimal "${DEVICE}" unit mib mkpart primary 3 515;
|
|
parted -s -a optimal "${DEVICE}" name 2 boot;
|
|
|
|
parted -s -a optimal "${DEVICE}" unit mib mkpart primary 515 100%;
|
|
parted -s -a optimal "${DEVICE}" name 3 lvmcrypt;
|
|
|
|
readonly BOOT_PARTITION="${DEVICE}2"
|
|
readonly ENCRYPTED_PARTITION="${DEVICE}3"
|
|
else
|
|
parted -s -a optimal "${DEVICE}" unit mib mkpart primary 1 513
|
|
parted -s -a optimal "${DEVICE}" name 1 boot
|
|
parted -s -a optimal "${DEVICE}" set 1 esp on
|
|
|
|
parted -s -a optimal "${DEVICE}" unit mib mkpart primary 513 100%
|
|
parted -s -a optimal "${DEVICE}" name 2 lvmcrypt;
|
|
|
|
readonly BOOT_PARTITION="${DEVICE}1"
|
|
readonly ENCRYPTED_PARTITION="${DEVICE}2"
|
|
fi;
|
|
|
|
# Create LUKS partition
|
|
echo "${PASSPHRASE}" |\
|
|
cryptsetup -q luksFormat "${ENCRYPTED_PARTITION}";
|
|
echo "${PASSPHRASE}" | \
|
|
cryptsetup -q open "${ENCRYPTED_PARTITION}" cryptlvm
|
|
|
|
# Create PV
|
|
pvcreate /dev/mapper/cryptlvm
|
|
|
|
# Create VG
|
|
vgcreate vgos /dev/mapper/cryptlvm;
|
|
|
|
# Optional: create and enable swap partition
|
|
if ${SWAP}; then
|
|
lvcreate -L "${SWAP_SIZE}m" vgos -n swap
|
|
mkswap -f /dev/vgos/swap;
|
|
swapon /dev/vgos/swap
|
|
fi
|
|
|
|
# Create LV
|
|
lvcreate -l 100%FREE vgos -n root
|
|
|
|
# Create filesystems
|
|
mkfs.ext4 -F /dev/vgos/root;
|
|
if [[ "${MODE}" == "bios" ]]; then
|
|
mkfs.ext2 -F "${BOOT_PARTITION}";
|
|
else
|
|
mkfs.fat -F32 "${BOOT_PARTITION}"
|
|
fi;
|
|
|
|
# Mount filesystems
|
|
mount /dev/vgos/root /mnt;
|
|
mkdir /mnt/boot;
|
|
mount "${BOOT_PARTITION}" /mnt/boot;
|
|
|
|
# /etc/login.defs
|
|
sed -i "s/UID_MIN.*1000$/UID_MIN\t\t\t10000/g;\
|
|
s/UID_MAX.*60000$/UID_MAX\t\t\t11000/g;\
|
|
s/SYS_UID_MIN.*500$/SYS_UID_MIN\t\t 600/g;\
|
|
s/SYS_UID_MAX.*999$/SYS_UID_MAX\t\t 700/g;\
|
|
s/GID_MIN.*1000$/GID_MIN\t\t\t10000/g;\
|
|
s/GID_MAX.*60000$/GID_MAX\t\t\t11000/g;\
|
|
s/SYS_GID_MIN.*500$/SYS_GID_MIN\t\t 600/g;\
|
|
s/SYS_GID_MAX.*999$/SYS_GID_MAX\t\t 700/g;" /etc/login.defs
|
|
|
|
# Change pacman mirrorlist
|
|
curl -L "www.archlinux.org/mirrorlist/?country=FR&protocol=https\
|
|
&ip_version=4&use_mirror_status=on" \
|
|
| sed "s/#Server/Server/g" \
|
|
| tee /etc/pacman.d/mirrorlist > /dev/null
|
|
|
|
# Populate /mnt
|
|
pacstrap /mnt base base-devel linux linux-firmware \
|
|
nano git man-db man-pages texinfo lvm2
|
|
|
|
# Generate fstab
|
|
genfstab -U /mnt >> /mnt/etc/fstab
|
|
|
|
# Configure system-resolved
|
|
cd /mnt/etc || exit;
|
|
rm -f resolv.conf;
|
|
ln -sf ../run/systemd/resolve/resolv.conf resolv.conf
|
|
|
|
# Configure timezone
|
|
arch-chroot /mnt ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime;
|
|
|
|
# Localization
|
|
arch-chroot /mnt sed -i "s/#en_US.UTF-8/en_US.UTF-8/g; \
|
|
s/#fr_FR.UTF-8/fr_FR.UTF-8/g" /etc/locale.gen;
|
|
arch-chroot /mnt locale-gen;
|
|
|
|
echo "LANG=en_US.UTF-8
|
|
LC_CTYPE=fr_FR.UTF-8
|
|
LC_NUMERIC=fr_FR.UTF-8
|
|
LC_TIME=fr_FR.UTF-8
|
|
LC_COLLATE=fr_FR.UTF-8
|
|
LC_MONETARY=fr_FR.UTF-8
|
|
LC_MESSAGES=en_US.UTF-8
|
|
LC_PAPER=fr_FR.UTF-8
|
|
LC_NAME=fr_FR.UTF-8
|
|
LC_ADDRESS=fr_FR.UTF-8
|
|
LC_TELEPHONE=fr_FR.UTF-8
|
|
LC_MEASUREMENT=fr_FR.UTF-8
|
|
LC_IDENTIFICATION=fr_FR.UTF-8"\
|
|
| arch-chroot tee /etc/locale.conf > /dev/null
|
|
|
|
echo "KEYMAP=fr-latin1" \
|
|
| arch-chroot /mnt tee /etc/vconsole.conf > /dev/null;
|
|
|
|
# Network
|
|
## Hostname
|
|
echo "${MACHINE_HOSTNAME}" \
|
|
| arch-chroot /mnt tee /etc/hostname > /dev/null;
|
|
|
|
## Localhost
|
|
echo "127.0.0.1 localhost" \
|
|
| arch-chroot /mnt tee -a /etc/hosts > /dev/null;
|
|
|
|
## Disable interface renaming
|
|
arch-chroot /mnt ln -sf /dev/null /etc/udev/rules.d/80-net-setup-link.rules;
|
|
|
|
## Configure eth0 DHCP
|
|
echo "[Match]
|
|
Name=eth0
|
|
|
|
[Network]
|
|
DHCP=ipv4
|
|
|
|
[DHCP]
|
|
UseDNS=true
|
|
UseDomains=true" \
|
|
| arch-chroot /mnt tee /etc/systemd/network/eth0.network > /dev/null;
|
|
|
|
## Enable systemd-networkd and systemd-resolved
|
|
arch-chroot /mnt systemctl enable systemd-networkd systemd-resolved
|
|
|
|
# /etc/logins/def
|
|
arch-chroot /mnt sed -i "s/UID_MIN.*1000$/UID_MIN\t\t\t10000/g;\
|
|
s/UID_MAX.*60000$/UID_MAX\t\t\t11000/g;\
|
|
s/SYS_UID_MIN.*500$/SYS_UID_MIN\t\t 600/g;\
|
|
s/SYS_UID_MAX.*999$/SYS_UID_MAX\t\t 700/g;\
|
|
s/GID_MIN.*1000$/GID_MIN\t\t\t10000/g;\
|
|
s/GID_MAX.*60000$/GID_MAX\t\t\t11000/g;\
|
|
s/SYS_GID_MIN.*500$/SYS_GID_MIN\t\t 600/g;\
|
|
s/SYS_GID_MAX.*999$/SYS_GID_MAX\t\t 700/g;"\
|
|
/etc/login.defs
|
|
|
|
# Create local admin account
|
|
arch-chroot /mnt useradd "${ADMIN_NAME}"
|
|
arch-chroot /mnt usermod -aG wheel "${ADMIN_NAME}";
|
|
arch-chroot /mnt mkdir -p "/home/${ADMIN_NAME}/.ssh"
|
|
arch-chroot /mnt chmod -R 700 "/home/${ADMIN_NAME}"
|
|
|
|
echo "# User rules for ${ADMIN_NAME}
|
|
${ADMIN_NAME} ALL=(ALL) NOPASSWD:ALL" \
|
|
| arch-chroot /mnt tee "/etc/sudoers.d/${ADMIN_NAME}" > /dev/null;
|
|
|
|
|
|
# Bootloader
|
|
arch-chroot /mnt pacman -S --noconfirm grub;
|
|
|
|
if [[ "${MODE}" == "bios" ]]; then
|
|
arch-chroot /mnt grub-install "${DEVICE}";
|
|
else
|
|
arch-chroot /mnt pacman -S --noconfirm efibootmgr
|
|
arch-chroot /mnt grub-install \
|
|
--target=x86_64-efi \
|
|
--efi-directory=/boot \
|
|
--bootloader-id=GRUB
|
|
fi;
|
|
arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg;
|
|
|
|
# /etc/default/grub
|
|
CRYPTDEVICE=""
|
|
DISK_UUID_LIST=$(find /dev/disk/by-uuid -type l)
|
|
for DISK_UUID in ${DISK_UUID_LIST}; do
|
|
if [[ "$(realpath "$DISK_UUID")" == "${ENCRYPTED_PARTITION}" ]]; then
|
|
CRYPTDEVICE="cryptdevice=UUID=$(basename "${DISK_UUID}"):cryplvm"
|
|
fi;
|
|
done
|
|
IP="ip=::::${HOSTNAME}:eth0:dhcp netconf_timeout=10"
|
|
ROOT="root=/dev/vgos/root"
|
|
PRELOAD_MODULES="part_gpt part_msdos lvm"
|
|
arch-chroot /mnt sed -i "s|CMDLINE_LINUX=.*|CMDLINE_LINUX=\"${IP} ${CRYPTDEVICE} ${ROOT}\"|g;\
|
|
s|PRELOAD_MODULES=.*|PRELOAD_MODULES=\"${PRELOAD_MODULES}\"|g;\
|
|
s|^#GRUB_ENABLE_CRYPTODISK|GRUB_ENABLE_CRYPTODISK|g;" /etc/default/grub;
|
|
|
|
# Openssh
|
|
arch-chroot /mnt pacman -S --noconfirm openssh;
|
|
|
|
arch-chroot /mnt sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin no/g" /etc/ssh/sshd_config;
|
|
arch-chroot /mnt sed -i "s/#PasswordAuthentication yes/PasswordAuthentication no/g" /etc/ssh/sshd_config;
|
|
|
|
echo "${AUTHORIZED_KEY}" \
|
|
| arch-chroot /mnt tee "/home/${ADMIN_NAME}/.ssh/authorized_keys" > /dev/null
|
|
arch-chroot /mnt chown -R "${ADMIN_NAME}": "/home/${ADMIN_NAME}"
|
|
|
|
arch-chroot /mnt systemctl enable sshd
|
|
|
|
# /etc/mkinitcpio.conf
|
|
HOOKS="base udev autodetect keyboard keymap consolefont modconf block \
|
|
lvm2 netconf dropbear encryptssh filesystems fsck"
|
|
|
|
arch-chroot /mnt sed -i "s/^HOOKS=.*/HOOKS=(${HOOKS})/" /etc/mkinitcpio.conf
|
|
|
|
arch-chroot /mnt pacman -S --noconfirm \
|
|
mkinitcpio-dropbear mkinitcpio-netconf mkinitcpio-utils;
|
|
|
|
arch-chroot /mnt cp "/home/${ADMIN_NAME}/.ssh/authorized_keys" /etc/dropbear/root_key;
|
|
arch-chroot /mnt dropbearkey -t rsa -f /etc/dropbear/dropbear_rsa_host_key
|
|
arch-chroot /mnt dropbearkey -t ecdsa -f /etc/dropbear/dropbear_ecdsa_host_key
|
|
arch-chroot /mnt dropbearkey -t ed25519 -f /etc/dropbear/dropbear_ed25519_host_key
|
|
|
|
arch-chroot /mnt sed -i "s/-E -s -j -k/-E -s -j -k -p 222/g" /usr/lib/initcpio/hooks/dropbear
|
|
NET_MODULE=$(realpath /sys/class/net/eth0/device/driver | awk -F"/" '{print $NF}')
|
|
arch-chroot /mnt sed -i "s/^MODULES=()/MODULES=(${NET_MODULE})/g" /etc/mkinitcpio.conf
|
|
|
|
arch-chroot /mnt mkinitcpio -P;
|
|
arch-chroot /mnt grub-mkconfig -o /boot/grub/grub.cfg;
|