feat: add Debian 13 golden image Packer pipeline and cloud-init bootstrap
This commit is contained in:
12 files changed
+645
-6
No files matched your search
@@ -0,0 +1,51 @@
|
||||
#cloud-config
|
||||
# ==============================================================================
|
||||
# Cloud-Init User-Data Template for apex.ermnvldmr.com Node
|
||||
# Compatible with generic cloud-init and virtualized environments (QEMU/KVM)
|
||||
#
|
||||
# Usage:
|
||||
# 1. Copy template: cp ci/cloud-init/user-data.template.yaml user-data.yaml
|
||||
# 2. Replace the public SSH key for adam.
|
||||
# 3. Replace the private SSH deploy key for GitHub access.
|
||||
# 4. Adjust APEX_REPO_NAME, APEX_REPO_URL, and tier devices in /etc/apex/bootstrap.env.
|
||||
# 5. Pass user-data.yaml as user-data during VM creation.
|
||||
# ==============================================================================
|
||||
|
||||
preserve_hostname: false
|
||||
hostname: daedalus.a1.apex.ermnvldmr.com
|
||||
|
||||
users:
|
||||
- name: adam
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
groups: [sudo, docker]
|
||||
shell: /bin/bash
|
||||
ssh_authorized_keys:
|
||||
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI_REPLACE_WITH_YOUR_PUBLIC_SSH_KEY adam@workstation"
|
||||
|
||||
write_files:
|
||||
# ----------------------------------------------------------------------------
|
||||
# 1. SSH Deploy Key for GitHub Submodule & Repo Access
|
||||
# ----------------------------------------------------------------------------
|
||||
- path: /home/adam/.ssh/id_ed25519
|
||||
owner: adam:adam
|
||||
permissions: '0600'
|
||||
content: |
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
# REPLACE WITH YOUR ED25519 DEPLOY PRIVATE KEY
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 2. Node Bootstrap Parameters
|
||||
# ----------------------------------------------------------------------------
|
||||
- path: /etc/apex/bootstrap.env
|
||||
owner: root:root
|
||||
permissions: '0600'
|
||||
content: |
|
||||
APEX_REPO_NAME="daedalus.apex.ermnvldmr.com"
|
||||
APEX_REPO_URL="git@github.com:deytenit/daedalus.apex.ermnvldmr.com.git"
|
||||
APEX_TIER1_DEVICE="/dev/vdb"
|
||||
APEX_TIER2_DEVICE="/dev/vdc"
|
||||
APEX_TIER3_DEVICE=""
|
||||
|
||||
runcmd:
|
||||
- /usr/local/bin/apex-bootstrap
|
||||
@@ -0,0 +1,75 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
qemu = {
|
||||
version = ">= 1.1.0"
|
||||
source = "github.com/hashicorp/qemu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "debian_cloud_image_url" {
|
||||
type = string
|
||||
default = "https://cloud.debian.org/images/cloud/trixie/daily/latest/debian-13-genericcloud-amd64-daily.qcow2"
|
||||
}
|
||||
|
||||
variable "debian_cloud_image_checksum" {
|
||||
type = string
|
||||
default = "none"
|
||||
}
|
||||
|
||||
variable "vm_name" {
|
||||
type = string
|
||||
default = "com-ermnvldmr-apex-debian-13-amd64.qcow2"
|
||||
}
|
||||
|
||||
variable "accelerator" {
|
||||
type = string
|
||||
default = "kvm"
|
||||
}
|
||||
|
||||
source "qemu" "apex_debian" {
|
||||
iso_url = var.debian_cloud_image_url
|
||||
iso_checksum = var.debian_cloud_image_checksum
|
||||
disk_image = true
|
||||
disk_size = "10G"
|
||||
format = "qcow2"
|
||||
output_directory = "output-qemu"
|
||||
shutdown_command = "echo 'packer' | sudo -S shutdown -P now"
|
||||
accelerator = var.accelerator
|
||||
cd_files = ["ci/packer/cidata/user-data", "ci/packer/cidata/meta-data"]
|
||||
cd_label = "cidata"
|
||||
ssh_username = "debian"
|
||||
ssh_password = "packer"
|
||||
ssh_timeout = "10m"
|
||||
vm_name = var.vm_name
|
||||
net_device = "virtio-net"
|
||||
disk_interface = "virtio"
|
||||
headless = true
|
||||
|
||||
qemuargs = [
|
||||
["-m", "2048M"],
|
||||
["-smp", "2"]
|
||||
]
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.qemu.apex_debian"]
|
||||
|
||||
provisioner "shell" {
|
||||
execute_command = "echo 'packer' | sudo -S sh -c '{{ .Vars }} {{ .Path }}'"
|
||||
scripts = [
|
||||
"ci/packer/scripts/01-base-system.sh",
|
||||
"ci/packer/scripts/02-storage-docker.sh",
|
||||
"ci/packer/scripts/03-bootstrap-helper.sh",
|
||||
"ci/packer/scripts/04-cleanup.sh"
|
||||
]
|
||||
}
|
||||
|
||||
post-processor "shell-local" {
|
||||
inline = [
|
||||
"echo 'Compressing and optimizing qcow2 image with 2M cluster size...'",
|
||||
"qemu-img convert -f qcow2 -O qcow2 -o cluster_size=2M -c output-qemu/${var.vm_name} output-qemu/com-ermnvldmr-apex-debian-13-optimized.qcow2",
|
||||
"mv output-qemu/com-ermnvldmr-apex-debian-13-optimized.qcow2 output-qemu/${var.vm_name}"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
instance-id: apex-golden-image-build
|
||||
local-hostname: apex-builder
|
||||
@@ -0,0 +1,14 @@
|
||||
#cloud-config
|
||||
ssh_pwauth: true
|
||||
disable_root: false
|
||||
chpasswd:
|
||||
list: |
|
||||
debian:packer
|
||||
root:packer
|
||||
expire: false
|
||||
users:
|
||||
- default
|
||||
- name: debian
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
shell: /bin/bash
|
||||
lock_passwd: false
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
echo "=== [1/6] Configuring Base Packages ==="
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl wget tcpdump socat rsync bind9-dnsutils iproute2 net-tools traceroute ca-certificates \
|
||||
jq sed gawk tar gzip bzip2 xz-utils unzip htop iotop strace lsof sysstat \
|
||||
parted fdisk pciutils usbutils smartmontools tmux vim less tree bash-completion \
|
||||
git python3 python3-minimal sudo rsyslog cron qemu-guest-agent
|
||||
|
||||
echo "=== [2/6] Configuring Sudo & Passwordless Escalation ==="
|
||||
cat << 'EOF_SUDO' > /etc/sudoers.d/99-apex
|
||||
%sudo ALL=(ALL:ALL) NOPASSWD: ALL
|
||||
EOF_SUDO
|
||||
chmod 0440 /etc/sudoers.d/99-apex
|
||||
visudo -cf /etc/sudoers.d/99-apex
|
||||
|
||||
echo "=== [3/6] Configuring VirtIO Kernel Modules ==="
|
||||
cat << 'EOF_VIRTIO' > /etc/modules-load.d/virtio.conf
|
||||
virtio
|
||||
virtio_net
|
||||
virtio_blk
|
||||
virtio_pci
|
||||
virtio_scsi
|
||||
virtiofs
|
||||
EOF_VIRTIO
|
||||
|
||||
echo "=== [4/6] Configuring GRUB Serial Console & Predictable Interfaces ==="
|
||||
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8 net.ifnames=0 biosdevname=0"/' /etc/default/grub
|
||||
sed -i 's/^#GRUB_TERMINAL=.*/GRUB_TERMINAL="console serial"/' /etc/default/grub
|
||||
if ! grep -q "GRUB_SERIAL_COMMAND" /etc/default/grub; then
|
||||
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >> /etc/default/grub
|
||||
fi
|
||||
update-grub
|
||||
|
||||
mkdir -p /etc/systemd/system/serial-getty@ttyS0.service.d
|
||||
cat << 'EOF_GETTY' > /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud 115200,38400,9600 %I $TERM
|
||||
EOF_GETTY
|
||||
systemctl enable serial-getty@ttyS0.service || true
|
||||
systemctl enable qemu-guest-agent 2>/dev/null || true
|
||||
|
||||
echo "=== [5/6] Configuring Cloud-Init Datasources & Service Enablement ==="
|
||||
mkdir -p /etc/cloud /etc/cloud/cloud.cfg.d
|
||||
cat << 'EOF_DS' > /etc/cloud/ds-identify.cfg
|
||||
policy: enabled
|
||||
EOF_DS
|
||||
|
||||
cat << 'EOF_CLOUD_CFG' > /etc/cloud/cloud.cfg.d/99-cloud-init.cfg
|
||||
datasource_list: [ NoCloud, ConfigDrive, OpenStack, Ec2, None ]
|
||||
disable_vm_template: false
|
||||
EOF_CLOUD_CFG
|
||||
|
||||
# Cloud-init services are static and enabled by generator via ds-identify
|
||||
systemctl enable cloud-init-local.service cloud-init.service cloud-config.service cloud-final.service 2>/dev/null || true
|
||||
|
||||
echo "=== [6/6] Configuring Predictable Network DHCP ==="
|
||||
mkdir -p /etc/systemd/network
|
||||
cat << 'EOF_NET' > /etc/systemd/network/10-eth.network
|
||||
[Match]
|
||||
Name=eth* en*
|
||||
|
||||
[Network]
|
||||
DHCP=yes
|
||||
EOF_NET
|
||||
systemctl enable systemd-networkd systemd-resolved || true
|
||||
|
||||
mkdir -p /etc/network/interfaces.d
|
||||
cat << 'EOF_IF' > /etc/network/interfaces.d/eth0
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
EOF_IF
|
||||
|
||||
echo "=== Base System Configuration Complete ==="
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
echo "=== [1/5] Configuring Debian Repositories for OpenZFS DKMS ==="
|
||||
# Enable contrib and non-free-firmware for zfs-dkms
|
||||
sed -i 's/Components: main/Components: main contrib non-free-firmware/g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || \
|
||||
sed -i 's/main$/main contrib non-free-firmware/g' /etc/apt/sources.list 2>/dev/null || true
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends linux-headers-amd64 zfsutils-linux zfs-dkms
|
||||
|
||||
# Pre-compile DKMS modules during bake time so first boot has zero compilation delay
|
||||
systemctl enable zfs-import-cache zfs-import.target zfs.target || true
|
||||
|
||||
echo "=== [2/5] Installing Docker CE from Official Debian Repository ==="
|
||||
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do
|
||||
apt-get remove -y "$pkg" 2>/dev/null || true
|
||||
done
|
||||
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
|
||||
chmod a+r /etc/apt/keyrings/docker.asc
|
||||
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
|
||||
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
||||
tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends \
|
||||
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
|
||||
mkdir -p /srv/docker
|
||||
cat << 'EOF_DOCKER' > /etc/docker/daemon.json
|
||||
{
|
||||
"data-root": "/srv/docker",
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "20m",
|
||||
"max-file": "3"
|
||||
}
|
||||
}
|
||||
EOF_DOCKER
|
||||
systemctl enable docker.service containerd.service
|
||||
|
||||
echo "=== [3/5] Installing and Configuring UFW + ufw-docker ==="
|
||||
apt-get install -y --no-install-recommends ufw iptables
|
||||
|
||||
curl -fsSL https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker -o /usr/local/bin/ufw-docker
|
||||
chmod +x /usr/local/bin/ufw-docker
|
||||
|
||||
# Pre-configure firewall baseline (keep port 22 open during build for Packer SSH session)
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
ufw default allow routed
|
||||
ufw allow 22/tcp comment 'SSH default for builder'
|
||||
ufw allow 2222/tcp comment 'SSH for Apex'
|
||||
ufw --force enable
|
||||
|
||||
# Set up ufw-docker routing in after.rules (now that UFW is active)
|
||||
/usr/local/bin/ufw-docker install || true
|
||||
|
||||
# Symlink into adam ~/.local/bin for engine compatibility
|
||||
mkdir -p /etc/skel/.local/bin
|
||||
ln -sf /usr/local/bin/ufw-docker /etc/skel/.local/bin/ufw-docker
|
||||
|
||||
echo "=== [4/5] Hardening SSH Configuration ==="
|
||||
mkdir -p /etc/ssh/sshd_config.d
|
||||
cat << 'EOF_SSH' > /etc/ssh/sshd_config.d/99-apex.conf
|
||||
Port 2222
|
||||
PasswordAuthentication no
|
||||
PermitEmptyPasswords no
|
||||
KbdInteractiveAuthentication no
|
||||
X11Forwarding no
|
||||
AllowUsers adam
|
||||
EOF_SSH
|
||||
|
||||
echo "=== [5/5] Installing CrowdSec ==="
|
||||
# PackageCloud does not publish a dedicated 'trixie' suite yet; bookworm suite works seamlessly on Debian 13
|
||||
export os=debian
|
||||
export dist=bookworm
|
||||
if curl -fsSL https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | bash; then
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends crowdsec crowdsec-firewall-bouncer-iptables
|
||||
else
|
||||
echo "PackageCloud script failed, falling back to Debian native repository..."
|
||||
rm -f /etc/apt/sources.list.d/crowdsec*.list
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends crowdsec crowdsec-firewall-bouncer-iptables || \
|
||||
apt-get install -y --no-install-recommends crowdsec
|
||||
fi
|
||||
|
||||
echo "=== Docker, ZFS & Security Stack Complete ==="
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "=== Baking /usr/local/bin/apex-bootstrap Runner ==="
|
||||
|
||||
cat << 'BOOTSTRAP_EOF' > /usr/local/bin/apex-bootstrap
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
MARKER="/var/lib/apex-bootstrapped"
|
||||
if [ -f "$MARKER" ]; then
|
||||
echo "[apex-bootstrap] Node has already been bootstrapped ($MARKER exists). Exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "============================================================"
|
||||
echo " Starting apex.ermnvldmr.com Node Bootstrap "
|
||||
echo "============================================================"
|
||||
|
||||
CONFIG_ENV="/etc/apex/bootstrap.env"
|
||||
if [ ! -f "$CONFIG_ENV" ]; then
|
||||
echo "[apex-bootstrap] ERROR: $CONFIG_ENV not found!" >&2
|
||||
echo "[apex-bootstrap] Provide APEX_REPO_NAME, APEX_REPO_URL via cloud-init write_files." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_ENV"
|
||||
|
||||
if [ -z "${APEX_REPO_NAME:-}" ] || [ -z "${APEX_REPO_URL:-}" ]; then
|
||||
echo "[apex-bootstrap] ERROR: APEX_REPO_NAME or APEX_REPO_URL is empty in $CONFIG_ENV" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[apex-bootstrap] Target repository: $APEX_REPO_NAME ($APEX_REPO_URL)"
|
||||
|
||||
# 1. Dynamic Swap Allocation
|
||||
if ! swapon --show | grep -q "/swapfile"; then
|
||||
echo "[apex-bootstrap] Configuring dynamic swapfile..."
|
||||
TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||
ROOT_AVAIL_KB=$(df -k / | awk 'NR==2 {print $4}')
|
||||
SWAP_SIZE_MB=2048
|
||||
if [ "$TOTAL_MEM_KB" -gt 4194304 ]; then
|
||||
SWAP_SIZE_MB=4096
|
||||
fi
|
||||
if [ "$ROOT_AVAIL_KB" -gt $((SWAP_SIZE_MB * 1024 * 2)) ]; then
|
||||
echo "[apex-bootstrap] Allocating ${SWAP_SIZE_MB}MB swap..."
|
||||
fallocate -l "${SWAP_SIZE_MB}M" /swapfile || dd if=/dev/zero of=/swapfile bs=1M count="$SWAP_SIZE_MB"
|
||||
chmod 0600 /swapfile
|
||||
mkswap /swapfile
|
||||
swapon /swapfile
|
||||
if ! grep -q "/swapfile" /etc/fstab; then
|
||||
echo "/swapfile none swap sw 0 0" >> /etc/fstab
|
||||
fi
|
||||
else
|
||||
echo "[apex-bootstrap] WARNING: Insufficient free space on rootfs for swapfile. Skipping swap."
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2. Storage Tiers & ZFS Configuration
|
||||
mkdir -p /srv
|
||||
for TIER_NUM in 1 2 3; do
|
||||
TIER_PATH="/srv/tier-${TIER_NUM}.${APEX_REPO_NAME}"
|
||||
DEV_VAR="APEX_TIER${TIER_NUM}_DEVICE"
|
||||
DEV="${!DEV_VAR:-}"
|
||||
|
||||
if [ -n "$DEV" ] && [ -b "$DEV" ]; then
|
||||
echo "[apex-bootstrap] Checking mapped tier $TIER_NUM on device: $DEV"
|
||||
POOL_NAME="tier-${TIER_NUM}"
|
||||
|
||||
# Check if pool already exists on the device or in zfs
|
||||
if zpool list -H -o name 2>/dev/null | grep -qw "$POOL_NAME"; then
|
||||
echo "[apex-bootstrap] ZFS pool $POOL_NAME is already imported."
|
||||
elif zpool import 2>/dev/null | grep -qw "$POOL_NAME"; then
|
||||
echo "[apex-bootstrap] Importing existing ZFS pool $POOL_NAME..."
|
||||
zpool import -f "$POOL_NAME"
|
||||
else
|
||||
echo "[apex-bootstrap] Creating new ZFS pool $POOL_NAME on $DEV..."
|
||||
zpool create -f -o ashift=12 \
|
||||
-O compression=lz4 \
|
||||
-O atime=off \
|
||||
-O mountpoint="$TIER_PATH" \
|
||||
"$POOL_NAME" "$DEV"
|
||||
fi
|
||||
zfs set mountpoint="$TIER_PATH" "$POOL_NAME" || true
|
||||
else
|
||||
echo "[apex-bootstrap] Tier $TIER_NUM device unmapped. Using rootfs directory: $TIER_PATH"
|
||||
mkdir -p "$TIER_PATH"
|
||||
fi
|
||||
done
|
||||
|
||||
# 3. User Directories & Permissions
|
||||
mkdir -p /srv/docker
|
||||
mkdir -p /home/adam/.local/bin /home/adam/.ssh
|
||||
ln -sf /usr/local/bin/ufw-docker /home/adam/.local/bin/ufw-docker
|
||||
|
||||
echo "[apex-bootstrap] Setting permissions on /srv and home directory..."
|
||||
chown -R adam:adam /srv /home/adam/.local /home/adam/.ssh
|
||||
chmod 0700 /home/adam/.ssh
|
||||
if [ -f /home/adam/.ssh/id_ed25519 ]; then
|
||||
chmod 0600 /home/adam/.ssh/id_ed25519
|
||||
fi
|
||||
|
||||
# 4. SSH Host Key Verification for GitHub
|
||||
echo "[apex-bootstrap] Registering GitHub SSH host keys..."
|
||||
ssh-keyscan -t ed25519,ecdsa,rsa github.com >> /home/adam/.ssh/known_hosts 2>/dev/null || true
|
||||
chown adam:adam /home/adam/.ssh/known_hosts
|
||||
chmod 0644 /home/adam/.ssh/known_hosts
|
||||
|
||||
# 5. Clone Repository
|
||||
REPO_DIR="/srv/${APEX_REPO_NAME}"
|
||||
if [ ! -d "$REPO_DIR/.git" ]; then
|
||||
echo "[apex-bootstrap] Cloning repository $APEX_REPO_URL as user adam..."
|
||||
sudo -u adam git clone "$APEX_REPO_URL" "$REPO_DIR"
|
||||
else
|
||||
echo "[apex-bootstrap] Repository already cloned at $REPO_DIR."
|
||||
fi
|
||||
|
||||
# 6. Execute ./init.sh
|
||||
INIT_SCRIPT="$REPO_DIR/init.sh"
|
||||
if [ -f "$INIT_SCRIPT" ]; then
|
||||
echo "[apex-bootstrap] Running ./init.sh from $REPO_DIR as user adam..."
|
||||
sudo -u adam bash -c "cd '$REPO_DIR' && bash ./init.sh"
|
||||
echo "[apex-bootstrap] ./init.sh completed successfully."
|
||||
else
|
||||
echo "[apex-bootstrap] No ./init.sh found in $REPO_DIR. Skipping."
|
||||
fi
|
||||
|
||||
# 7. Complete & Mark Bootstrapped
|
||||
touch "$MARKER"
|
||||
echo "============================================================"
|
||||
echo " [apex-bootstrap] Node bootstrap finished successfully! "
|
||||
echo " Next steps: SSH as adam on port 2222, fill secrets & run: "
|
||||
echo " apex tiers/link <tier1> <tier2> <tier3> "
|
||||
echo " apex tiers/useradd && apex tiers/chown "
|
||||
echo " apex configure && apex compose up "
|
||||
echo "============================================================"
|
||||
BOOTSTRAP_EOF
|
||||
|
||||
chmod 0755 /usr/local/bin/apex-bootstrap
|
||||
echo "=== /usr/local/bin/apex-bootstrap baked successfully ==="
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
echo "=== [1/4] Purging APT Caches and Temp Files ==="
|
||||
apt-get autoremove -y --purge
|
||||
apt-get clean
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
echo "=== [2/4] Resetting Machine Identity for Clones ==="
|
||||
truncate -s 0 /etc/machine-id
|
||||
rm -f /var/lib/dbus/machine-id
|
||||
ln -sf /etc/machine-id /var/lib/dbus/machine-id
|
||||
|
||||
mkdir -p /etc/systemd/system/ssh.service.d
|
||||
cat << 'EOF_SSH_HOST' > /etc/systemd/system/ssh.service.d/10-generate-host-keys.conf
|
||||
[Service]
|
||||
ExecStartPre=-/usr/bin/ssh-keygen -A
|
||||
EOF_SSH_HOST
|
||||
ssh-keygen -A
|
||||
|
||||
echo "=== [3/4] Resetting Cloud-Init State & Bash History ==="
|
||||
ufw delete allow 22/tcp 2>/dev/null || true
|
||||
cloud-init clean --logs --seed || true
|
||||
rm -rf /var/lib/cloud/*
|
||||
rm -f /root/.bash_history /home/*/.bash_history
|
||||
|
||||
echo "=== [4/4] Syncing Filesystems ==="
|
||||
sync
|
||||
|
||||
echo "=== Image Sanitization Complete ==="
|
||||
Reference in new issue
Block a user