KVM // Bootstrap Debian / Ubuntu / Kali

this is almost a script

Bootstrap on a loop device

as root

    guest=buster
guest=jammy

    mkdir -p /data/guests/$guest/lala/
    cd /data/guests/$guest/
    dd if=/dev/zero of=$guest.img bs=1G count=0 seek=26

losetup -a | grep -v snapd
    loopdevice=`losetup --find --partscan --show $guest.img`
    echo loopdevice is $loopdevice

manual partitioning

fdisk $loopdevice

n
p
ENTER
ENTER
ENTER
a
w

    fdisk -l $loopdevice

you could otherwise automate this as such

total=`fdisk -l $loopdevice | head -1 | awk '{print $7}'`

# 2048 * 512 = 1048576
echo -n writing vda.sfdisk...
cat > vda.sfdisk <<-EOF && echo done
label: dos
label-id: 0x8ae$((RANDOM % 10))$((RANDOM % 10))3cc
device: vda
unit: sectors

/dev/sda1 : start=2048, size=$((total-2048)), type=83, bootable
EOF
sfdisk $loopdevice < vda.sfdisk
#partprobe $loopdevice

prepare the file-system

    mkfs.btrfs ${loopdevice}p1
    mount ${loopdevice}p1 lala/

apt install debian-keyring debian-archive-keyring
ls -lF /usr/share/keyrings/debian-archive-keyring.gpg

mirror=...

    time debootstrap --arch=amd64 $guest lala/ $mirror
# 1m52,078s buster
# 4m4,939s jammy

Guest setup

    cat > lala/etc/fstab <<-EOF # override
    /dev/vda1 / btrfs defaults 0 1
    proc /proc proc defaults 0 0
    tmpfs /tmp tmpfs rw,nodev,nosuid,noatime,relatime 0 0
    devpts /dev/pts devpts gid=5,mode=620 0 0
    EOF

Sysprep

system setup

ls -lF lala/etc/hostname # no exist
    echo $guest > lala/etc/hostname

To make Perl packages happy, you need to tweak bash.bashrc, not profile

    cp -pi lala/etc/bash.bashrc lala/etc/bash.bashrc.dist
    cat >> lala/etc/bash.bashrc <<-EOF

source /usr/share/bash-completion/bash_completion

    export LANGUAGE="en_US:en"
    export LC_ALL="C.UTF-8"
    export LC_COLLATE="C.UTF-8"
    export LANG="C.UTF-8"

    alias ll='ls --group-directories-first --color=auto -alh'
    alias ls='ls --group-directories-first --color=auto'
    alias cp='cp -i'
    alias mv='mv -i'
    alias rm='rm -i'

    EOF

    zone=Europe/Moscow

ls -lF lala/etc/localtime
    ln -sf ../usr/share/zoneinfo/$zone lala/etc/localtime

cat lala/etc/timezone
    echo $zone > lala/etc/timezone # override

point to the closest mirror

    cat lala/etc/apt/sources.list
echo $mirror
echo $release

# debian
    cat > lala/etc/apt/sources.list <<-EOF
    deb $mirror $release main contrib non-free
    deb $mirror $release-updates main contrib non-free
    # $release-backports
    EOF

# ubuntu
    cat > lala/etc/apt/sources.list <<-EOF
    deb $mirror $release main restricted universe multiverse
    deb $mirror $release-updates main restricted universe multiverse
    deb $mirror $release-security main restricted universe multiverse
    #deb $mirror $release-backports main restricted universe multiverse
    EOF

eventually setup a package proxy

    vi lala/etc/apt/apt.conf.d/02proxy

    Acquire::http { Proxy "http://x.x.x.x:3142"; };

network setup

    mv -i lala/etc/hosts lala/etc/hosts.dist
    cat > lala/etc/hosts <<-EOF
    127.0.0.1       localhost
    ::1             localhost ip6-localhost ip6-loopback
    ff02::1         ip6-allnodes
    ff02::2         ip6-allrouters

    10.1.0.7    $guest
    10.1.255.254    gw
    EOF

    rmdir lala/etc/network/interfaces.d/
    cat > lala/etc/network/interfaces <<-EOF # override
    auto lo
    iface lo inet loopback

    auto eth0
    iface eth0 inet static
            address 10.1.0.7/24
            gateway 10.1.255.254
EOF

moar options

            #dns-nameservers 208.67.222.222 208.67.220.220
            #dns-search DOMAIN.TLD

we use our own stub-resolver

ls -lF lala/etc/resolv.conf* # not a symlink
cat lala/etc/resolv.conf

# kvm
    echo nameserver 192.168.122.1 > lala/etc/resolv.conf

# dedibox
echo 62.210.16.6 > lala/etc/resolv.conf
echo 62.210.16.7 >> lala/etc/resolv.conf

# opendns
    echo nameserver 208.67.222.222 > lala/etc/resolv.conf
    echo nameserver 208.67.222.220 >> lala/etc/resolv.conf

# pmr nobudget
    echo nameserver 10.1.255.254 > lala/etc/resolv.conf
    echo nameserver 10.1.255.253 >> lala/etc/resolv.conf
    echo nameserver 10.1.255.252 >> lala/etc/resolv.conf
    echo nameserver 10.1.255.251 >> lala/etc/resolv.conf

chroot

now let’s proceed with the insider stuff

    mount -o bind /dev/pts lala/dev/pts
    mount -o bind /proc lala/proc # rsyslog:systemd-tmpfiles
    chroot lala/ bash

    perl -e exit

console requires a password unless you tweak getty like hell – disabling it instead

    passwd -d root
    #usermod -p '*' root

tune the guest userland serial console

    systemctl get-default
    systemctl set-default multi-user

# kvm-only
    #systemctl enable serial-getty@ttyS0.service

No NTP is required, this is a guest system

dpkg -l | grep ntp # not installed
dpkg -l | grep chrony # not installed
    systemctl list-unit-files | grep ntp # not present
    systemctl list-unit-files | grep chrony # not present

    # ubuntu
    systemctl disable systemd-timesyncd

also disable the stub-on-steroids

dpkg -l | grep resolv # absent
    systemctl list-unit-files | grep resolv # systemd-resolved.service disabled already
#systemctl disable systemd-resolved

perform a system upgrade before making a template out of it

    export DEBIAN_FRONTEND=noninteractive
    apt update
    apt dist-upgrade
apt autoremove --purge

you might also want those additional packages

    apt install \
            ifupdown \
    locales \
            net-tools \
            man-db \
            manpages \
            openssh-server \
            openssh-client \
            mlocate \
    netcat-openbsd \
    nmap \
            wget \
            elvis-tiny \
            bash-completion

dpkg-reconfigure locale # en_US.UTF-8

ls -lF /usr/share/bash-completion/bash_completion

note bsd-mailx would install postfix or exim - we don’t want that

ls -lF /etc/postfix/main.cf # absent
ls -lF /etc/exim4/ # absent

get rid of the generated keys

rm -f /etc/ssh/ssh_host_*
systemctl list-unit-files | grep ssh

finally exit the chroot

    updatedb
ls -lF ~/.bash_history # nope
history -c
    ^D

we’re done!

ls -lF lala/root/.bash_history # nope
    umount -R lala/
    rmdir lala/

Boot-blocks & kernel

we need a kernel in there as this is KVM not XEN

chroot lala/ bash

apt install linux-image-kvm btrfs-progs

^D
ln -s boot/vmlinuz lala/vmlinuz

now setup the kvm guest boot-loader and kernel-time serial console

ls -lh /usr/lib/syslinux/mbr/mbr.bin

    dd if=/usr/lib/syslinux/mbr/mbr.bin of=$loopdevice
    mkdir lala/boot/syslinux/
    extlinux --install lala/boot/syslinux --device ${loopdevice}p1
    cp -f /usr/lib/syslinux/modules/bios/mboot.c32 lala/boot/syslinux/
    cp -f /usr/lib/syslinux/modules/bios/libcom32.c32 lala/boot/syslinux/
vi lala/boot/syslinux/syslinux.cfg

and see syslinux

umount -R lala/
rmdir lala/
btrfsck ${loopdevice}p1
losetup --detach $loopdevice

ls -lh $guest.img
    du -sh $guest.img
# 493M    jammy.img

Ready to go

cat > $guest.xml <<EOF
<domain type='kvm'>
  <name>$guest</name>
  <memory unit='GiB'>1</memory>
  <currentMemory unit='GiB'>1</currentMemory>
  <vcpu placement='static'>$((`grep ^processor /proc/cpuinfo | tail -1 | awk '{print $3}'` + 1))</vcpu>
  <os>
    <type arch='x86_64' machine='q35'>hvm</type>
    <boot dev='hd'/>
  </os>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw'/>
      <source file='/data/guests/$guest/$guest.img'/>
      <target dev='vda' bus='virtio'/>
    </disk>
    <interface type='bridge'>
      <source bridge='virbr0'/>
      <model type='virtio'/>
    </interface>
    <serial type='pty'>
      <target type='isa-serial' port='0'>
    <model name='isa-serial'/>
      </target>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
  </devices>
</domain>
EOF

chown ADMIN.adm $guest.xml

as user

guest=buster
guest=jammy

cd /data/guests/$guest/

virsh create $guest.xml --console

^]

virsh console $guest

^]

maybe add your SSH pubkey in there and we’re good

Acceptance and template

ping opendns.com
poweroff

as root

virsh list --all | grep $guest # empty
cd /data/guests/
time nice tar cSf /data/templates/$guest.tar $guest/
ls -lh /data/templates/$guest.tar
# 1,1G

GNS3-ready

eventually make it available for GNS3

Troubleshooting

grub-install: error: unknown filesystem.

==> you need to see the partition, use losetup for that


HOME | GUIDES | LECTURES | LAB | SMTP HEALTH | HTML5
Copyright © 2023 Pierre-Philipp Braun