#!/usr/bin/env bash # safety first set -euf -o pipefail # check we have what we need type virt-customize type wget # get the cloud image - btw this is how they are built https://salsa.debian.org/cloud-team/debian-cloud-images/-/blob/master/doc/details.md rm -fv debian-13-genericcloud-amd64.qcow2 wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2 # install wget (for cloud-init), set the root password to "password" and set timezone to UTC virt-customize -a debian-13-genericcloud-amd64.qcow2 --install wget --root-password password:password --timezone UTC # also save the root password hash, we'll need it later virt-customize -a debian-13-genericcloud-amd64.qcow2 --run-command 'getent shadow root | cut -d: -f2 > /etc/cloud/default-root-hash && chmod 600 /etc/cloud/default-root-hash' # install any additional software virt-customize -a debian-13-genericcloud-amd64.qcow2 --install mc --install screen --install tmux --install jnettop --install iptraf-ng --install tcpdump \ --install net-tools --install iperf3 --install netcat-openbsd --install netcat-traditional --install telnet --install busybox # disable console blanking, revert to eth0-like interface names, set tty0 as main tty instead of ttyS0 virt-customize -a debian-13-genericcloud-amd64.qcow2 --edit '/etc/default/grub:s/consoleblank=0(?! biosdevname)/consoleblank=0 biosdevname=0 net.ifnames=0/' \ --edit '/etc/default/grub:s/console=tty0 console=ttyS0,115200/console=ttyS0,115200 console=tty0/' \ --run-command 'update-grub' ## optional - enable autologin on tty1 and ttyS0 #virt-customize -a debian-13-genericcloud-amd64.qcow2 \ # --mkdir /etc/systemd/system/getty@tty1.service.d \ # --append-line '/etc/systemd/system/getty@tty1.service.d/override.conf:[Service]' \ # --append-line '/etc/systemd/system/getty@tty1.service.d/override.conf:ExecStart=' \ # --append-line '/etc/systemd/system/getty@tty1.service.d/override.conf:ExecStart=-/sbin/agetty --autologin root --noclear %I $TERM' \ # --mkdir /etc/systemd/system/serial-getty@ttyS0.service.d \ # --append-line '/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf:[Service]' \ # --append-line '/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf:ExecStart=' \ # --append-line '/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf:ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud 115200,57600,38400,9600 %I $TERM' # apply the CloudStack cloud-init config # step 1 - generate the files echo "policy: enabled" > ds-identify.cfg cat << 'EOF' > 99_cloudstack.cfg disable_root: 0 system_info: default_user: name: root ssh_pwauth: true ssh_deletekeys: false datasource_list: ['ConfigDrive','CloudStack'] cloud_config_modules: - [set-passwords, always] - [ssh, always] datasource: CloudStack: max_wait: 20 timeout: 5 retries: 2 system_info: default_user: name: root lock_passwd: false sudo: false groups: [] EOF # step 2 - put them in the guest virt-customize -a debian-13-genericcloud-amd64.qcow2 \ --upload ds-identify.cfg:/etc/ds-identify.cfg \ --upload 99_cloudstack.cfg:/etc/cloud/cloud.cfg.d/99_cloudstack.cfg # customise the /etc/issue banner similar to the SystemVMs cat << 'EOF' > etc-issue.txt __?.o/ Apache CloudStack Default Template ( )# https://cloudstack.apache.org (___(_) \S \n \l \4 \6 EOF # and put it in the guest - perhaps all these copy operations could be bundled together for speed virt-customize -a debian-13-genericcloud-amd64.qcow2 --upload etc-issue.txt:/etc/issue # the question of the default password "password" - there'll be cases where this template/VM gets exposed to the Internet, I reckon that we should deal with it this way: # - if the password has not been changed - we do this via comparison against the hash we saved at the beginning of the script - then no password based SSH allowed for root # - if the password has been changed - assuming by cloud-init - then we let root SSH in with the password, whatever that may be, assuming a secure one in comparison # - we achieve this via per-once cloud-init script which runs _after_ the password module cat << 'EOF' > root-ssh-pwlogin.sh #!/bin/sh default=$(cat /etc/cloud/default-root-hash) current=$(getent shadow root | cut -d: -f2) if [ -n "$current" ] && [ "$current" != "$default" ]; then printf 'PermitRootLogin yes\n' > /etc/ssh/sshd_config.d/10-root-sshpwlogin.conf systemctl restart ssh logger -t cloud-init "Default insecure password no longer in place, allowing root user in via SSH password." fi EOF chmod +x root-ssh-pwlogin.sh virt-customize -a debian-13-genericcloud-amd64.qcow2 --run-command 'mkdir -p /var/lib/cloud/scripts/per-once' \ --upload root-ssh-pwlogin.sh:/var/lib/cloud/scripts/per-once/root-ssh-pwlogin.sh # take care of guest tools - we build images for various hypervisor by means of --virt parameter, values = kvm, xen or vmware xe_url=https://github.com/xenserver/xe-guest-utilities/releases/download/v10.0.0/xe-guest-utilities_10.0.0-1_amd64.deb # we assume KVM if no virt parameter is passed to the script virt=kvm while [ $# -gt 0 ]; do case $1 in --virt) virt=$2; shift ;; --virt=*) virt=${1#*=} ;; *) echo "unknown option: $1" >&2; exit 1 ;; esac shift done case $virt in kvm) set -- --install qemu-guest-agent ;; vmware) set -- --install open-vm-tools ;; xen) set -- --run-command "wget -qO /tmp/xe.deb $xe_url && apt-get install -y /tmp/xe.deb && rm /tmp/xe.deb" ;; *) echo "usage: $0 --virt kvm|vmware|xen" >&2; exit 1 ;; esac virt-customize -a debian-13-genericcloud-amd64.qcow2 "$@" # to-do: create vhd and ova files