bootstrap-bookworm.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #!/bin/bash -e
  2. #----------
  3. # Interactive installation steps for Debian Bullseye from GRML using debootstrap
  4. # Design decisions
  5. # - Fokus on a simple setup, primarly for VMs
  6. # - One disk, one partion, swap-file in the same partion as safety net
  7. # - Use systemd whereever possible (network, ntp, cron, journald logging)
  8. # - Minimal number of packages & cloud kernel
  9. # - support for grub-pc and grub-efi
  10. # - random root and admin user password generation
  11. # - ssh on port 50101 limited to the admin user
  12. # Usage
  13. # # Boot grml
  14. # passwd root
  15. # grml-network
  16. # Start ssh
  17. # git clone https://git.in-ulm.de/ulpeters/bootstrap.git
  18. # cp config.sh.template config.sh # copy template
  19. # config-get-netconf-eth0.sh # get running grml network config
  20. # vi config.sh # update installation variables
  21. # bootstrap-bullseye.sh install # start installation
  22. # !! Note down the admin passwords and reboot
  23. # sudo /installer/bootstrap-bullseye.sh postinstall # run postinstall in the new system
  24. # Variables
  25. mnt="/mnt/root" # mountpoint for the new root filesystem
  26. hostname="somehost.example.com"
  27. kernel="linux-image-cloud-amd64" # alternative: linux-image-amd64
  28. partition="mbr-single" # mbr-single or efi-crypt
  29. disk="/dev/vda" # find with: lsblk --list
  30. disk0=$disk"p1" # efi partion, only relevant if partion="efi"
  31. disk1=$disk"1" # "p1" for nbd or nvme mounts
  32. netDev="eth0" # find with: ip link
  33. netAddress="203.0.113.66/24" # "" blank for dhcp on e*
  34. netGateway="203.0.113.1"
  35. netBroadcast="203.0.113.255"
  36. netDNS1="192.0.2.10"
  37. netDNS2="198.51.100.10"
  38. netNTP="pool.ntp.org"
  39. pwdAdmin="" # "" blank for auto-generation
  40. pwdRoot="" # "" blank for auto-generation
  41. extraPackages="qemu-guest-agent"
  42. [ -f ./config.sh ] && source config.sh
  43. # Setup network in grml
  44. grmlnetwork(){
  45. ip link show # list interfaces
  46. ip addr add $netAddress dev $netDev
  47. ip link set $netDev up
  48. ip route add default via $netGateway
  49. echo nameserver $netDNS1 >> /etc/resolv.conf
  50. echo nameserver $netDNS2 >> /etc/resolv.conf
  51. }
  52. install(){
  53. # Wipe existing partition table
  54. dd if=/dev/zero of=$disk bs=512 count=34
  55. # Parition disks -- pkg: parted
  56. # Prepare partition tables and partitions
  57. # -parted --script does not accept blanks in partition names
  58. if [ "$partition" = "mbr-single" ]
  59. then
  60. #----------
  61. # Prepare disks with a single partition
  62. parted $disk --script \
  63. mklabel msdos \
  64. mkpart primary ext4 512M 100% toggle 1 boot
  65. fdisk -l $disk
  66. # Format disks -- pkg: e2fsprogs dosfstools and to file system check
  67. mkfs.ext4 $disk1 && e2fsck $disk1
  68. # Prepare mount points and mount
  69. mkdir -p $mnt
  70. mount $disk1 $mnt
  71. fi
  72. if [ "$partition" = "efi-crypt" ]
  73. then
  74. #----------
  75. # Prepare disks with following layout
  76. # - 301 MB partition for EFI --> p1
  77. # - 50 GB root partition for the OS (includes /boot) --> p2
  78. # - Remaining disk left to create a luks container --> p3
  79. parted $disk --script \
  80. mklabel gpt \
  81. mkpart EFI_system_partition fat32 1MiB 301MiB \
  82. set 1 esp on \
  83. set 1 boot on \
  84. align-check optimal 1 \
  85. mkpart Linux_system_parition ext4 301MiB 50GiB \
  86. align-check optimal 2 \
  87. mkpart Data_partion 50GiB 100% \
  88. align-check optimal 3 \
  89. unit MiB \
  90. print
  91. # Format disks -- pkg: e2fsprogs dosfstools and to file system check
  92. mkfs.fat -F 32 -n EFIBOOT $disk0 && fsck $disk0
  93. mkfs.ext4 $disk1 && fsck $disk1
  94. # Prepare mount points and mount
  95. mkdir -p $mnt $mnt"/boot/efi"
  96. mount $disk1 $mnt
  97. mount $disk0 $mnt"/boot/efi"
  98. fi
  99. # Create swapfile
  100. swapfile=$mnt/swapfile
  101. dd if=/dev/zero of=$swapfile bs=1M count=1024 status=progress # create 1GB file
  102. chmod 600 $swapfile #restric permissions
  103. mkswap $swapfile #format file
  104. #----------
  105. # Bootstrap -- pkg: debootstrap
  106. # Remark: Debootstrap does not install recommands!!
  107. debootstrap --variant=minbase --arch=amd64 bookworm $mnt http://ftp2.de.debian.org/debian/
  108. #----------
  109. # Configuration
  110. # Configure disk mounts
  111. # Or get UUID from blkid...
  112. cat >$mnt/etc/fstab <<EOL
  113. $disk1 / ext4 rw 0 0
  114. /swapfile none swap defaults 0 0
  115. EOL
  116. # Configure sources.list
  117. cat >$mnt/etc/apt/sources.list <<EOL
  118. deb http://deb.debian.org/debian bookworm main non-free-firmware
  119. # deb-src http://deb.debian.org/debian bookworm main non-free-firmware
  120. deb http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware
  121. # deb-src http://deb.debian.org/debian-security/ bookworm-security main non-free-firmware
  122. deb http://deb.debian.org/debian bookworm-updates main non-free-firmware
  123. # deb-src http://deb.debian.org/debian bookworm-updates main non-free-firmware
  124. EOL
  125. # Configure hostname
  126. echo "127.0.0.1 $hostname" >> $mnt/etc/hosts
  127. echo "$hostname" > $mnt/etc/hostname
  128. #----------
  129. # Prepare chroot
  130. mount -o bind /dev $mnt/dev
  131. mount -o bind /dev/pts $mnt/dev/pts
  132. mount -t sysfs /sys $mnt/sys
  133. mount -t proc /proc $mnt/proc
  134. cp /proc/mounts $mnt/etc/mtab
  135. cp /etc/resolv.conf $mnt/etc/resolv.conf
  136. mkdir -p $mnt/installer
  137. cp $(dirname `realpath $0`)/*.sh $mnt/installer
  138. # Run script in chroot
  139. chroot $mnt /bin/bash /installer/bootstrap-bullseye.sh install2
  140. # Install bootloader
  141. $0 bootloader
  142. }
  143. #----------
  144. # Function executed within chroot
  145. install2(){
  146. source /installer/config.sh
  147. # Install basic system
  148. apt-get update
  149. apt-get install --yes \
  150. apt-utils dialog msmtp-mta \
  151. systemd-sysv locales tzdata haveged \
  152. linux-image-cloud-amd64 grub-pc \
  153. iproute2 netbase \
  154. ssh sudo molly-guard \
  155. less vim-tiny bash-completion pwgen lsof \
  156. dnsutils iputils-ping curl \
  157. $extraPackages
  158. # Upgrade and clean up
  159. apt-get upgrade --yes
  160. apt-get autoremove --yes
  161. apt-get clean --yes
  162. # Setup users and passwords
  163. [ -z $pwdAdmin ] && pwdAdmin=`pwgen --capitalize --numerals --ambiguous 12 1`
  164. useradd admin --create-home --shell /bin/bash
  165. echo "admin:$pwdAdmin" | chpasswd
  166. usermod -a -G sudo admin
  167. echo -e "\e[1;33;4;44mPassword for the user admin: $pwdAdmin\e[0m"
  168. pass=`pwgen --capitalize --numerals --ambiguous 12 1`
  169. [ -z $pwdRoot ] && pwdRoot=`pwgen --capitalize --numerals --ambiguous 12 1`
  170. echo "root:$pwdRoot" | chpasswd
  171. echo -e "\e[1;33;4;44mPassword for the user root: $pwdRoot\e[0m"
  172. # Harden SSHD
  173. sed -i -e 's/#Port 22/Port 50101/g' /etc/ssh/sshd_config
  174. sed -i -e 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/g' /etc/ssh/sshd_config
  175. # https://infosec.mozilla.org/guidelines/openssh.html
  176. # Allow admin to sudo without password
  177. echo AllowUsers admin >> /etc/ssh/sshd_config
  178. echo "admin ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/admin
  179. ## Configure network using systemd
  180. if [ -z $netAddress ]
  181. then
  182. ## Network OPTION 1 - DHCP
  183. cat >/etc/systemd/network/20-wired.network <<EOL
  184. [Match]
  185. Name=e*
  186. [Network]
  187. DHCP=ipv4
  188. IPv6PrivacyExtensions=false
  189. IPv6AcceptRA=false
  190. NTP=$netNTP
  191. EOL
  192. else
  193. ## Network OPTION 2 - static
  194. cat >/etc/systemd/network/20-wired.network <<EOL
  195. [Match]
  196. Name=$netDev
  197. [Network]
  198. Address=$netAddress
  199. Gateway=$netGateway
  200. Broadcast=$netBroadcast
  201. DNS=$netDNS1
  202. DNS=$netDNS2
  203. NTP=$netNTP
  204. EOL
  205. fi
  206. ## Setup systemd resolver
  207. apt-get install --yes systemd-resolved
  208. echo -e "\n# Disable local name resolution" >> /etc/systemd/resolved.conf
  209. echo "LLMNR=no" >> /etc/systemd/resolved.conf
  210. echo "MulticastDNS=no" >> /etc/systemd/resolved.conf
  211. systemctl enable systemd-networkd
  212. systemctl enable systemd-resolved
  213. # Limit journald logging to 1 month, 1 GB in total and split files per week
  214. mkdir -p /etc/systemd/journald.conf.d/
  215. cat >/etc/systemd/journald.conf.d/retention.conf <<EOL
  216. MaxRetentionSec=1month
  217. SystemMaxUse=1G
  218. MaxFileSec=1week
  219. EOL
  220. # Show errors in motd
  221. rm /etc/motd
  222. cat >/etc/update-motd.d/15-boot-errors<<EOL
  223. #!/bin/sh
  224. echo
  225. journalctl --boot --priority=3 --no-pager
  226. EOL
  227. chmod 755 /etc/update-motd.d/15-boot-errors
  228. # Setup keyboard layout
  229. cat >/etc/default/keyboard <<EOL
  230. XKBMODEL="pc105"
  231. XKBLAYOUT="de"
  232. XKBVARIANT="nodeadkeys"
  233. XKBOPTIONS=""
  234. BACKSPACE="guess"
  235. EOL
  236. # Leave chroot
  237. exit
  238. }
  239. bootloader(){
  240. # Install grub in the mbr
  241. if [ $partition="mbr-single" ]
  242. then
  243. chroot $mnt /bin/bash -c "grub-install $disk && update-grub"
  244. fi
  245. # Install grub in the efi partition
  246. if [ $partition="efi-crypt" ]
  247. then
  248. chroot $mnt /bin/bash -c \
  249. "grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=grub && update-grub"
  250. fi
  251. }
  252. unmount(){
  253. # Unmount if mounted
  254. ! mountpoint -q $mnt/proc || umount $mnt/proc
  255. ! mountpoint -q $mnt/sys || umount $mnt/sys
  256. ! mountpoint -q $mnt/dev/pts || umount $mnt/dev/pts
  257. ! mountpoint -q $mnt/dev || umount $mnt/dev
  258. ! mountpoint -q $mnt/root || umount $mnt/root
  259. ! mountpoint -q $mnt || umount $mnt
  260. # Delete mount-point if empty and not mounted
  261. [ -z "$(ls -A /mnt/)" ] && ! mountpoint -q $mnt && rm -R $mnt
  262. }
  263. postinstall(){
  264. ####----REBOOT into the new system, so we'll have dbus running
  265. localectl set-locale LANG=de_DE.UTF-8 # Default for LC_* variables not set.
  266. localectl set-locale LC_MESSAGES=en_US.UTF-8 # System messages.
  267. #localectl set-locale LC_RESPONSE=en_US.UTF-8 # How responses (such as Yes and No) appear
  268. update-locale
  269. timedatectl set-timezone Europe/Berlin
  270. }
  271. # Switch to functions...
  272. case $1 in
  273. grmlnetwork)
  274. echo Setup network in grml
  275. grmlnetwork
  276. ;;
  277. install)
  278. echo "Stage 1: Start installation"
  279. install
  280. ;;
  281. install2)
  282. echo "Stage 2: Start installation in chroot"
  283. install2
  284. ;;
  285. bootloader)
  286. echo "Stage 3: Install bootloader and unmount chroot"
  287. bootloader
  288. unmount
  289. echo "We're done and can reboot now"
  290. ;;
  291. postinstall)
  292. echo "Stage 4: Start post-installation in live system"
  293. postinstall
  294. ;;
  295. unmount)
  296. echo "Unmount chroot, e.g. in case installation fails"
  297. unmount
  298. ;;
  299. *)
  300. echo "Valid functions are: grmlnetwork, install, postinstall and unmount" >&2
  301. ;;
  302. esac