| @@ -0,0 +1,133 @@ | |||
| 1 | + | #!/usr/bin/env bash | |
| 2 | + | ||
| 3 | + | set -euo pipefail | |
| 4 | + | shopt -s nullglob | |
| 5 | + | ||
| 6 | + | if [[ "${EUID}" -ne 0 ]]; then | |
| 7 | + | echo "ERROR: This script must be run as root." | |
| 8 | + | exit 1 | |
| 9 | + | fi | |
| 10 | + | ||
| 11 | + | echo "========================================" | |
| 12 | + | echo " PVE VM Template Cleanup" | |
| 13 | + | echo "========================================" | |
| 14 | + | ||
| 15 | + | echo "[1/9] Cleaning Cloud-Init state..." | |
| 16 | + | ||
| 17 | + | if command -v cloud-init >/dev/null 2>&1; then | |
| 18 | + | clean_args=(--logs) | |
| 19 | + | clean_help=$(cloud-init clean --help 2>&1 || true) | |
| 20 | + | ||
| 21 | + | if grep -q -- "--machine-id" <<<"${clean_help}"; then | |
| 22 | + | clean_args+=(--machine-id) | |
| 23 | + | fi | |
| 24 | + | if grep -q -- "--seed" <<<"${clean_help}"; then | |
| 25 | + | clean_args+=(--seed) | |
| 26 | + | fi | |
| 27 | + | if grep -q -- "--configs" <<<"${clean_help}"; then | |
| 28 | + | clean_args+=(--configs ssh_config network) | |
| 29 | + | fi | |
| 30 | + | ||
| 31 | + | cloud-init clean "${clean_args[@]}" | |
| 32 | + | else | |
| 33 | + | echo "cloud-init is not installed; cleaning machine-id directly." | |
| 34 | + | fi | |
| 35 | + | ||
| 36 | + | # Ensure both systemd and legacy dbus machine IDs are empty. On this host the | |
| 37 | + | # dbus path is a symlink to /etc/machine-id, so it is not modified separately. | |
| 38 | + | truncate -s 0 /etc/machine-id | |
| 39 | + | if [[ -f /var/lib/dbus/machine-id && ! -L /var/lib/dbus/machine-id ]]; then | |
| 40 | + | truncate -s 0 /var/lib/dbus/machine-id | |
| 41 | + | fi | |
| 42 | + | ||
| 43 | + | echo "[2/9] Removing SSH host keys and generated network configuration..." | |
| 44 | + | ||
| 45 | + | rm -f /etc/ssh/ssh_host_* | |
| 46 | + | rm -f /etc/network/interfaces.d/50-cloud-init | |
| 47 | + | ||
| 48 | + | # This file pins the current VM's MAC address and must not be cloned. | |
| 49 | + | rm -f /etc/udev/rules.d/70-persistent-net.rules | |
| 50 | + | ||
| 51 | + | echo "[3/9] Removing clone-specific SSH keys and history..." | |
| 52 | + | ||
| 53 | + | find /root /home -maxdepth 3 -type f \ | |
| 54 | + | \( -name authorized_keys -o -name known_hosts -o \ | |
| 55 | + | -name .bash_history -o -name .zsh_history -o \ | |
| 56 | + | -name .fish_history -o -name .python_history -o \ | |
| 57 | + | -name .mysql_history \) \ | |
| 58 | + | -delete 2>/dev/null || true | |
| 59 | + | ||
| 60 | + | echo "[4/9] Resetting hostname metadata..." | |
| 61 | + | ||
| 62 | + | printf '%s\n' localhost > /etc/hostname | |
| 63 | + | sed -i '/^127\.0\.1\.1[[:space:]]/d' /etc/hosts | |
| 64 | + | ||
| 65 | + | echo "[5/9] Cleaning DHCP leases..." | |
| 66 | + | ||
| 67 | + | rm -f /var/lib/dhcp/*.leases 2>/dev/null || true | |
| 68 | + | rm -f /var/lib/dhcp/*.lease 2>/dev/null || true | |
| 69 | + | rm -f /var/lib/dhclient/*.leases 2>/dev/null || true | |
| 70 | + | rm -f /var/lib/dhclient/*.lease 2>/dev/null || true | |
| 71 | + | rm -f /run/systemd/netif/leases/* 2>/dev/null || true | |
| 72 | + | rm -f /var/lib/NetworkManager/*.lease 2>/dev/null || true | |
| 73 | + | rm -f /var/lib/NetworkManager/*lease* 2>/dev/null || true | |
| 74 | + | ||
| 75 | + | echo "[6/9] Removing systemd random seed and runtime state..." | |
| 76 | + | ||
| 77 | + | rm -f /var/lib/systemd/random-seed | |
| 78 | + | rm -rf /run/cloud-init 2>/dev/null || true | |
| 79 | + | ||
| 80 | + | echo "[7/9] Cleaning temporary files and logs..." | |
| 81 | + | ||
| 82 | + | find /tmp /var/tmp -mindepth 1 -maxdepth 1 -exec rm -rf -- {} + 2>/dev/null || true | |
| 83 | + | ||
| 84 | + | if command -v journalctl >/dev/null 2>&1; then | |
| 85 | + | journalctl --rotate 2>/dev/null || true | |
| 86 | + | journalctl --vacuum-time=1s 2>/dev/null || true | |
| 87 | + | fi | |
| 88 | + | ||
| 89 | + | find /var/log -type f -name '*.log' -exec truncate -s 0 -- {} + 2>/dev/null || true | |
| 90 | + | find /var/log -type f -name '*.gz' -delete 2>/dev/null || true | |
| 91 | + | ||
| 92 | + | echo "[8/9] Trimming filesystem..." | |
| 93 | + | ||
| 94 | + | sync | |
| 95 | + | if command -v fstrim >/dev/null 2>&1; then | |
| 96 | + | fstrim -av || true | |
| 97 | + | fi | |
| 98 | + | sync | |
| 99 | + | ||
| 100 | + | echo "[9/9] Final checks..." | |
| 101 | + | ||
| 102 | + | [[ ! -e /etc/ssh/ssh_host_ed25519_key ]] || { | |
| 103 | + | echo "ERROR: SSH host keys still exist." | |
| 104 | + | exit 1 | |
| 105 | + | } | |
| 106 | + | [[ ! -e /etc/udev/rules.d/70-persistent-net.rules ]] || { | |
| 107 | + | echo "ERROR: persistent network rule still exists." | |
| 108 | + | exit 1 | |
| 109 | + | } | |
| 110 | + | ||
| 111 | + | echo | |
| 112 | + | echo "========================================" | |
| 113 | + | echo " Cleanup completed" | |
| 114 | + | echo "========================================" | |
| 115 | + | echo | |
| 116 | + | echo "Cleaned:" | |
| 117 | + | echo " - Cloud-Init instance state, seed, and generated network config" | |
| 118 | + | echo " - machine-id" | |
| 119 | + | echo " - SSH host keys and user SSH known/authorized keys" | |
| 120 | + | echo " - shell history" | |
| 121 | + | echo " - persistent MAC mapping" | |
| 122 | + | echo " - hostname metadata" | |
| 123 | + | echo " - DHCP leases" | |
| 124 | + | echo " - systemd random seed" | |
| 125 | + | echo " - temporary files and logs" | |
| 126 | + | echo | |
| 127 | + | echo "Preserved:" | |
| 128 | + | echo " - package installation and package cache" | |
| 129 | + | echo " - base network configuration in /etc/network/interfaces" | |
| 130 | + | echo | |
| 131 | + | echo "DO NOT reboot this VM." | |
| 132 | + | echo "Power it off and convert it to a PVE template." | |
| 133 | + | echo | |
simbafs / Debian VM Template Clean Scriopt
Last active 1 week ago