#!/bin/bash # Ce script est une base qu’il faut sûrement améliorer. # Il sert à installer un debian d’ordi portable JC pour le cluster SHLAGO # Le but est d’installer juste ce qu’il faut pour le le serveur tourne, le reste est laissé à ansible. # Il génère une clé SSH qui permettra d’accéder à la machine. C’est peut-être con, il faudrait plutôt le remplir de nos ssh publiques. # https://github.com/adrianamaglio/driglibash declare -A usage declare -A varia export driglibash_run_retry=true version="alpha nightly 0.0.1 pre-release unstable" summary="$0 [options]" usage[m]="Path of the temporar mount point" varia[m]=mnt mnt="temporary_mount_point" usage[a]="The architecture of installed system as supported by debootstrap" varia[a]=arch arch="amd64" usage[r]="The release of installed system as supported by debootstrap" varia[r]=release release="bullseye" usage[s]="Source repository of installed system" varia[s]=repo #repo= repo="http://ftp.fr.debian.org/debian" #repo="http://localhost:3142/ftp.fr.debian.org/debian" usage[S]="Additional sources to add in source.list. Newline separated." varia[S]=repos repos="deb http://ftp.fr.debian.org/debian stable main contrib non-free" usage[n]="The hostname" varia[n]=hostname hostname="" usage[b]="The device where grub will be installed" varia[b]=boot_device boot_device= usage[B]="Boot partition" varia[B]=boot_part boot_part= usage[R]="The device where the system will be installed" varia[R]=root_device root_device= usage[l]="System locale" varia[l]=locale locale="en_US.UTF-8 UTF-8\nfr_FR.UTF-8 UTF-8" usage[w]="Wireguard IP last number (4 for 1.2.3.4)" varia[w]=wireguard_number wireguard_number= usage[J]="Just mount and chroot it. No installation" varia[J]=just_mount just_mount=false usage[i]="Packages to install. space separated" varia[i]=install install= usage[u]="Install grub as UEFI (not working)" varia[u]=uefi uefi=false usage[I]="Interractive mode. Ask questions if needed." varia[I]=interractive interractive=false usage[D]="Data Device. Will be encrypted." varia[D]=data_device data_device= . driglibash-args secret_dir=secrets secret_dir="$(realpath -m "$secret_dir/$hostname")" install="$install linux-image-amd64 console-data grub2 locales vim openssh-server git nginx smartmontools tcpdump netcat-openbsd wireguard" debootstrap_done_marker="$mnt/etc/debootstrap_done" uefi_mountpoint=/boot/efi dependancies="cryptsetup locales openssh-server wireguard-tools grub2" ############################################################################### # Actual script ############################################################################### chroot_run(){ run chroot "$mnt" $@ if [ "$?" -ne 0 ] && [ "$?" != '0' ] ; then die "Error, chroot command [$@] exited with code '$?'" fi } wait_for_user(){ section "Time for a pause" run echo "Press 'Enter' to continue" read } mount_misc(){ run mkdir -p "$mnt"/{proc,dev,sys} run mount -t proc /proc "$mnt/proc" #clean "umount '$(realpath "$mnt/proc")'" # To access physical devices run mount --rbind --make-rslave /dev "$mnt/dev" # even explicitly mounting /dev/pts makes apt cry for its absence… #clean "umount -R '$(realpath "$mnt/dev")'" run mount --rbind --make-rslave /sys "$mnt/sys" #clean "umount -R '$(realpath "$mnt/sys")'" if "$uefi" ; then run mkdir -p "$mnt$uefi_mountpoint" run mount "$boot_device" "$mnt$uefi_mountpoint" fi clean "umount -R '$mnt'" } if [ -z "$hostname" ] ; then die "Hostname arg needed" fi root_or_die section "Testing for existing secrets" if ! [ -d "$secret_dir" ] ; then run mkdir -p "$secret_dir" run chown -R root:root "$secret_dir" run chmod 700 "$secret_dir" fi section "Mounting additionnal items" if [ -n "$(df | grep "$root_device")" ] ; then run umount "$root_device" fi run mkdir -p "$mnt" run mount --make-private "$root_device" "$mnt" # bug in driglibash-base. If $mnt got spaces it breaks if [ -n "$boot_part" ] ; then run mkdir -p "$mnt/boot" run mount "$boot_part" "$mnt/boot" fi clean "umount -R $mnt" if [ "$just_mount" != false ] ; then echo 'Mounted. Exit shell to unmount.' chroot_run die 'You asked to just mount then exit.' fi section "debootstraping" if [ ! -f "$debootstrap_done_marker" ] ; then # Debootstrap may fail when the target is an existing system if [ -n "$(ls -A $mnt | grep -vi -e 'lost+found' -e boot)" ]; then yell "Root dir '$mnt' is not empty." if "$interractive" ; then read -p 'Press enter to continue anyway' else die "Won’t debootstrap it. Is this installation broken?" fi fi run debootstrap --verbose --arch "$arch" "$release" "$mnt" "$repo" touch "$debootstrap_done_marker" else yell "Already done" fi mount_misc section "Installing selected software" echo "$repos" >> "$mnt/etc/apt/sources.list" run chroot "$mnt" <<EOF export DEBIAN_FRONTEND=noninteractive apt-get update -q -y apt-get install -q -y $install EOF # TODO watershed ? section "Generating locales" echo -e "$locale" > "$mnt/etc/locale.gen" chroot_run locale-gen if [ -n "$data_device" ] ; then section "Mounting and encrypting data dir" run cryptsetup create --type plain dmcrypt-jeancloud "$data_device" run mkfs.ext4 dmcrypt-jeancloud uuid="$(blkid | grep dmcrypt-jeancloud | grep -o 'UUID="[^"]\+"')" if [ -z "$uuid" ] ; then die "Error, unexpected empty uuid" fi line_in_file "$uuid /data ext4 rw,nofail 0 1" "$mnt/etc/fstab" fi section "Configuring new system" uuid=$(blkid | grep "$root_device" | cut -d ' ' -f 2) line_in_file "$uuid / ext4 errors=remount-ro 0 1" "$mnt/etc/fstab" line_in_file "proc /proc proc defaults" "$mnt/etc/fstab" # TODO set noauto to /boot if needed # Set hostname run echo "$hostname" > "$mnt/etc/hostname" # Prenvent suspend on lid close line_in_file HandleLidSwitch=ignore "$mnt/etc/systemd/logind.conf" # Inform futur scripts that /data is not mounted touch "$mnt/data/mounted" # Fix path run cat > "$mnt/root/.bashrc" <<EOF PATH=$PATH:/usr/bin:/bin:/sbin:/usr/sbin:/sbin setterm -powerdown 0 EOF # Be sure this fucking beep is gone echo 'set bell-style none' >> "$mnt/etc/inputrc" # TODO find a second method to kill this doomed beep line_in_file '@reboot root shutdownscreen.sh' "$mnt/etc/crontab" # boot crypted #section "Installing cryptsetup in initramfs" #run echo 'CRYPTSETUP=y' >> /etc/cryptsetup-initramfs/conf-hook #run cp key "$mnt/root/" #run echo 'FILES="/root/key"' >> /etc/initramfs-tools/initramfs.conf #run update-initramfs -ut #echo "$mnt/etc/initramfs-tools/conf.d/cryptsetup" <<EOF ## This will setup non-us keyboards in early userspace, ## necessary for punching in passphrases. #KEYMAP=y # ## force busybox and cryptsetup on initramfs #BUSYBOX=y #CRYPTSETUP=y # ## and for systems using plymouth instead, use the new option #FRAMEBUFFER=y #EOF #echo 'export CRYPTSETUP=y' >> "$mnt/etc/environment" #echo 'export FILES="./key"' >> "$mnt/etc/initramfs-tools/initramfs.conf" #chroot_run 'update-initramfs -ut' section "Set up networking" # Disable the unpredictable naming (since we are not on the future host) if [ ! -L "$mnt/etc/udev/rules.d/80-net-setup-link.rules" ] ; then run ln -s /dev/null "$mnt/etc/udev/rules.d/80-net-setup-link.rules" fi run cat >> "$mnt/etc/network/interfaces" <<EOF allow-hotplug eth0 iface eth0 inet dhcp EOF #iface eth0 inet6 dhcp # TODO add dyndn service section "Creating root SSH key to connect" if [ -n "$(ls -A $secret_dir)" ]; then #die "Secret dir '$secret_dir' is not empty" yell "Secret dir is not empty. May erase key." fi run export HOSTNAME="$hostname" && ssh-keygen -b 4096 -f "$secret_dir/id_rsa" -P '' -C "access@$hostname" run mkdir -p "$mnt/root/.ssh/" cat "$secret_dir/id_rsa.pub" >> "$mnt/root/.ssh/authorized_keys" chroot_run systemctl enable ssh section "Creating wireguard conf" if [ -n "$wireguard_number" ] ; then run cat >> "$mnt/etc/wireguard/jeancloud.conf" <<EOF [Interface] PrivateKey = $(wg genkey) ListenPort = 51812 Address = 10.98.1.$wireguard_number/32 [Peer] # debug PublicKey = OpENQI1ElPuVdNssMySffO8iZEyJsOaSQ9bQLU6Uz2E= AllowedIPs = 10.98.1.254/32 Endpoint = 193.33.56.94:51812 PersistentKeepalive = 25 EOF wireguard_pubkey="$(cat "$mnt/etc/wireguard/jeancloud.conf" | grep -oP '^PrivateKey = \K.*' | wg pubkey)" run cat > "$secret_dir/wg_conf_part" <<EOF [Peer] # $hostname PublicKey = $wireguard_pubkey AllowedIPs = 10.98.1.$wireguard_number/32 EOF chroot_run systemctl enable wg-quick@jeancloud.service else yell "Passing" fi section "Installing grub" # Disable predictable interfaces name since we are not on the target host run sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"/g' "$mnt/etc/default/grub" chroot_run update-grub if $uefi ; then chroot_run grub-install --efi-directory="$uefi_mountpoint" --recheck "$boot_device" else chroot_run grub-install --recheck "$boot_device" fi if [ "$arg_test" != "false" ] ; then section "Testing installed system" run qemu-system-x86_64 -m 1024M "$boot_device" fi echo "To test the system with qemu type:" echo "qemu-system-x86_64 -m 1024M '$boot_device'" clean