diff --git a/USB/.gitignore b/USB/.gitignore new file mode 100644 index 0000000..3593331 --- /dev/null +++ b/USB/.gitignore @@ -0,0 +1,7 @@ +# Build output +output/ +data/ + +# Nebula certificates and keys (user-provided secrets) +nebula/*.crt +nebula/*.key diff --git a/USB/Dockerfile b/USB/Dockerfile new file mode 100644 index 0000000..1098869 --- /dev/null +++ b/USB/Dockerfile @@ -0,0 +1,54 @@ +FROM alpine:3.22 + +# Base tools +RUN apk add --no-cache \ + bash \ + coreutils \ + util-linux \ + tar \ + gzip \ + xz \ + cpio \ + curl \ + wget \ + ca-certificates \ + rsync \ + file \ + grep \ + gawk \ + sed \ + vim + +# Filesystem + disk tools (needed by chroot-setup.sh and for Alpine install) +RUN apk add --no-cache \ + dosfstools \ + e2fsprogs \ + xfsprogs \ + btrfs-progs \ + parted \ + sfdisk \ + blkid \ + lsblk \ + wipefs \ + util-linux-misc \ + findmnt + +# ISO + boot tools +RUN apk add --no-cache \ + xorriso \ + syslinux \ + mtools \ + squashfs-tools \ + libarchive-tools \ + busybox-static + +# GRUB (BIOS + EFI) — available if needed for alternative builds +RUN apk add --no-cache \ + grub \ + grub-bios \ + grub-efi \ + efibootmgr + +WORKDIR /work + +CMD ["/bin/bash"] diff --git a/USB/README.md b/USB/README.md new file mode 100644 index 0000000..e91d7bd --- /dev/null +++ b/USB/README.md @@ -0,0 +1,119 @@ +# Alpine Linux USB Rescue ISO + +A bootable hybrid ISO that: + +- Gets an IP via **DHCP on `eth0`** +- Automatically opens a **Nebula overlay tunnel** +- Runs **OpenSSH** (login: `root` / `alpine`) +- Carries all tools needed to **install Alpine onto the host machine** (`setup-alpine`, `setup-disk`, `parted`, …) + +The ISO is a hybrid image — it can be written to a USB stick with `dd` *or* burned to a CD/DVD. + +--- + +## Prerequisites + +- Docker + Docker Compose +- A Nebula certificate set for this node (see below) + +--- + +## 1. Place Nebula certificates + +Put the following files in `nebula/`: + +``` +nebula/ + nebula ← binary (already included) + config.yml ← already included, edit as needed + ca.crt ← your Nebula CA certificate ← YOU PROVIDE + host.crt ← this node's certificate ← YOU PROVIDE + host.key ← this node's private key ← YOU PROVIDE +``` + +`ca.crt`, `host.crt`, and `host.key` are gitignored. + +--- + +## 2. Build the ISO + +```bash +docker compose run --rm alpine bash /scripts/create.sh +``` + +The ISO is written to `output/rescue-alpine.iso`. + +--- + +## 3. Write to USB + +```bash +dd if=output/rescue-alpine.iso of=/dev/sdX bs=4M status=progress && sync +``` + +Replace `/dev/sdX` with your USB device (check with `lsblk`). **All data on the device will be erased.** + +Or burn to CD/DVD: + +```bash +cdrecord dev=/dev/sr0 output/rescue-alpine.iso +``` + +--- + +## 4. Boot and connect + +1. Insert USB and boot the target machine from it. +2. The system comes up fully in RAM — no writes to the host disk. +3. On boot, `eth0` gets an IP via DHCP, then the Nebula tunnel comes up automatically. +4. SSH in via the Nebula overlay IP (see `nebula/config.yml`): + +```bash +ssh root@ +# password: alpine +``` + +--- + +## 5. Install Alpine onto the host machine + +Once SSH'd in (or at the local console): + +```bash +# Interactive guided installer — partitions disk, installs Alpine +setup-alpine + +# Or use setup-disk for more control +setup-disk -m sys /dev/sda +``` + +All required tools (`parted`, `e2fsprogs`, `dosfstools`, `btrfs-progs`, `alpine-conf`, …) are pre-installed. + +--- + +## Default credentials + +| Field | Value | +|----------|----------| +| Username | `root` | +| Password | `alpine` | + +Change this in `scripts/chroot-setup.sh` before building if needed. + +--- + +## Architecture + +``` +ISO (hybrid — bootable on USB or CD) +└── isolinux (BIOS boot) + ├── vmlinuz-lts + └── initramfs.gz ← entire Alpine system packed as cpio+gzip + ├── eth0 DHCP (openrc networking) + ├── nebula → /usr/local/bin/nebula + ├── /etc/nebula/ (config + certs) + ├── OpenSSH (sshd) + └── Alpine install tools +``` + +The system runs **entirely in RAM** — the host disk is never touched until you explicitly run the installer. diff --git a/USB/build b/USB/build new file mode 100755 index 0000000..7fc04a9 --- /dev/null +++ b/USB/build @@ -0,0 +1,2 @@ +docker compose run --rm alpine bash /scripts/create.sh + diff --git a/USB/docker-compose.yml b/USB/docker-compose.yml new file mode 100644 index 0000000..ecf2408 --- /dev/null +++ b/USB/docker-compose.yml @@ -0,0 +1,15 @@ +services: + alpine: + build: . + devices: + - /dev/loop-control:/dev/loop-control + privileged: true + volumes: + - ./data:/work + - ./scripts:/scripts:ro + - ./nebula:/nebula:ro + - ./output:/output + - /dev:/dev + working_dir: /work + tty: true + stdin_open: true diff --git a/USB/nebula/config.yml b/USB/nebula/config.yml new file mode 100644 index 0000000..cbb596e --- /dev/null +++ b/USB/nebula/config.yml @@ -0,0 +1,66 @@ +pki: + ca: /etc/nebula/ca.crt + cert: /etc/nebula/host.crt + key: /etc/nebula/host.key +static_host_map: + "192.168.9.1": ["167.71.79.60:4242"] +lighthouse: + am_lighthouse: false + interval: 60 + hosts: + - "192.168.9.1" +listen: + host: 0.0.0.0 + port: 4242 +punchy: + punch: true + +relay: + am_relay: false + use_relays: true + +tun: + disabled: false + dev: nebula2 + drop_local_broadcast: false + drop_multicast: false + tx_queue: 500 + mtu: 1300 + routes: + #- mtu: 8800 + # route: 10.0.0.0/16 + + unsafe_routes: +logging: + level: info + format: text +firewall: + outbound_action: drop + inbound_action: drop + + conntrack: + tcp_timeout: 12m + udp_timeout: 3m + default_timeout: 10m + + outbound: + - port: any + proto: any + host: any + + inbound: + - port: any #ping + proto: icmp + groups: + - admin + + + - port: 22 #GIT + proto: tcp + groups: + - admin + + + + + diff --git a/USB/nebula/nebula b/USB/nebula/nebula new file mode 100755 index 0000000..e70dcc4 Binary files /dev/null and b/USB/nebula/nebula differ diff --git a/USB/scripts/chroot-setup.sh b/USB/scripts/chroot-setup.sh new file mode 100755 index 0000000..64c3345 --- /dev/null +++ b/USB/scripts/chroot-setup.sh @@ -0,0 +1,135 @@ +#!/bin/sh +set -eu + +# --------------------------------------------------------------------------- +# chroot-setup.sh — Runs inside the Alpine chroot to configure the system +# --------------------------------------------------------------------------- + +# --------------------------------------------------------------------------- +# 1. APK repositories +# --------------------------------------------------------------------------- +echo "==> Configuring APK repositories" +cat > /etc/apk/repositories <<'EOF' +https://dl-cdn.alpinelinux.org/alpine/latest-stable/main +https://dl-cdn.alpinelinux.org/alpine/latest-stable/community +EOF + +apk update + +# --------------------------------------------------------------------------- +# 2. Install packages +# --------------------------------------------------------------------------- +echo "==> Installing packages" +apk add --no-cache \ + linux-lts \ + mkinitfs \ + openrc \ + busybox \ + musl \ + libc-utils \ + util-linux \ + e2fsprogs \ + dosfstools \ + btrfs-progs \ + parted \ + sfdisk \ + openssh \ + dhcpcd \ + iproute2 \ + iputils \ + net-tools \ + curl \ + wget \ + ca-certificates \ + vim \ + mc \ + bind-tools \ + nmap \ + rsync \ + alpine-conf + +# --------------------------------------------------------------------------- +# 3. Generate initramfs +# --------------------------------------------------------------------------- +echo "==> Generating initramfs with mkinitfs" +mkinitfs $(ls /lib/modules/ | tail -1) + +# --------------------------------------------------------------------------- +# 4. Network configuration +# --------------------------------------------------------------------------- +echo "==> Configuring network interfaces" +mkdir -p /etc/network +cat > /etc/network/interfaces <<'EOF' +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +EOF + +# --------------------------------------------------------------------------- +# 5. SSH configuration +# --------------------------------------------------------------------------- +echo "==> Configuring sshd" +sed -i \ + -e 's/^#*\s*PermitRootLogin.*/PermitRootLogin yes/' \ + -e 's/^#*\s*PasswordAuthentication.*/PasswordAuthentication yes/' \ + /etc/ssh/sshd_config + +# Ensure the directives exist if sed found nothing to replace +grep -q '^PermitRootLogin' /etc/ssh/sshd_config || echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config +grep -q '^PasswordAuthentication' /etc/ssh/sshd_config || echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config + +echo "==> Generating SSH host keys" +ssh-keygen -A + +# --------------------------------------------------------------------------- +# 6. Root password +# --------------------------------------------------------------------------- +echo "==> Setting root password" +echo "root:alpine" | chpasswd + +# --------------------------------------------------------------------------- +# 7. Nebula OpenRC service +# --------------------------------------------------------------------------- +echo "==> Creating /etc/init.d/nebula" +cat > /etc/init.d/nebula <<'EOF' +#!/sbin/openrc-run +description="Nebula overlay network" +command="/usr/local/bin/nebula" +command_args="-config /etc/nebula/config.yml" +command_background=true +pidfile="/run/nebula.pid" + +depend() { + need net + after networking +} + +start_pre() { + checkpath -f -m 0600 -o root:root /run/nebula.pid +} +EOF +chmod +x /etc/init.d/nebula + +# --------------------------------------------------------------------------- +# 8. OpenRC service enablement +# --------------------------------------------------------------------------- +echo "==> Enabling services" +rc-update add sshd default +rc-update add networking default +rc-update add nebula default + +# Also ensure basic boot services are present +rc-update add devfs sysinit || true +rc-update add dmesg sysinit || true +rc-update add mdev sysinit || true +rc-update add hwdrivers sysinit || true + +# --------------------------------------------------------------------------- +# 9. Hostname +# --------------------------------------------------------------------------- +echo "==> Setting hostname to 'rescue'" +echo "rescue" > /etc/hostname + +echo "==> chroot-setup.sh complete" diff --git a/USB/scripts/create.sh b/USB/scripts/create.sh new file mode 100755 index 0000000..b4c0c27 --- /dev/null +++ b/USB/scripts/create.sh @@ -0,0 +1,211 @@ +#!/bin/bash +set -euo pipefail + +# --------------------------------------------------------------------------- +# create.sh — Build a bootable Alpine Linux rescue ISO +# +# Run inside the Docker build container: +# docker compose run --rm alpine bash /scripts/create.sh +# +# The resulting ISO is a hybrid image: it can be burned to a CD/DVD or +# written directly to a USB stick with dd. +# --------------------------------------------------------------------------- + +ALPINE_MIRROR="https://dl-cdn.alpinelinux.org/alpine" +ALPINE_BRANCH="latest-stable" +ALPINE_ARCH="x86_64" +MINIROOTFS_BASE="${ALPINE_MIRROR}/${ALPINE_BRANCH}/releases/${ALPINE_ARCH}" + +ISO="/output/rescue-alpine.iso" +CHROOT="/mnt/alpine-chroot" +ISOROOT="/tmp/isoroot" + +mkdir -p /output "$CHROOT" "$ISOROOT" + +# --------------------------------------------------------------------------- +# 1. Fetch latest Alpine minirootfs +# --------------------------------------------------------------------------- +echo "==> Fetching latest Alpine minirootfs index" +TARBALL=$(curl -fsSL "${MINIROOTFS_BASE}/" \ + | grep -oP 'alpine-minirootfs-[0-9.]+-x86_64\.tar\.gz' \ + | sort -V | tail -1) + +[[ -z "$TARBALL" ]] && { echo "ERROR: could not determine minirootfs tarball" >&2; exit 1; } + +TARBALL_LOCAL="/tmp/${TARBALL}" +if [[ ! -f "$TARBALL_LOCAL" ]]; then + echo "==> Downloading ${MINIROOTFS_BASE}/${TARBALL}" + curl -fsSL -o "$TARBALL_LOCAL" "${MINIROOTFS_BASE}/${TARBALL}" +else + echo "==> Using cached ${TARBALL_LOCAL}" +fi + +# --------------------------------------------------------------------------- +# 2. Extract minirootfs into chroot +# --------------------------------------------------------------------------- +echo "==> Extracting minirootfs into ${CHROOT}" +tar -xzf "$TARBALL_LOCAL" -C "$CHROOT" + +# --------------------------------------------------------------------------- +# 3. Copy Nebula binary and config into chroot +# --------------------------------------------------------------------------- +echo "==> Installing Nebula binary" +mkdir -p "${CHROOT}/usr/local/bin" +cp /nebula/nebula "${CHROOT}/usr/local/bin/nebula" +chmod +x "${CHROOT}/usr/local/bin/nebula" + +echo "==> Installing Nebula config and certificates" +mkdir -p "${CHROOT}/etc/nebula" +cp /nebula/config.yml "${CHROOT}/etc/nebula/config.yml" +for f in /nebula/*.crt /nebula/*.key; do + [[ -f "$f" ]] && cp "$f" "${CHROOT}/etc/nebula/" +done + +# --------------------------------------------------------------------------- +# 4. Bind-mount virtual filesystems for chroot +# --------------------------------------------------------------------------- +echo "==> Bind-mounting virtual filesystems" +mount --bind /dev "${CHROOT}/dev" +mount --bind /proc "${CHROOT}/proc" +mount --bind /sys "${CHROOT}/sys" +mkdir -p "${CHROOT}/run" +mount --bind /run "${CHROOT}/run" +cp /etc/resolv.conf "${CHROOT}/etc/resolv.conf" + +# Make scripts available inside chroot +mkdir -p "${CHROOT}/scripts" +mount --bind /scripts "${CHROOT}/scripts" + +# --------------------------------------------------------------------------- +# 5. Run in-chroot configuration +# --------------------------------------------------------------------------- +echo "==> Running chroot-setup.sh inside chroot" +chroot "$CHROOT" /bin/sh /scripts/chroot-setup.sh + +# --------------------------------------------------------------------------- +# 6. Unmount virtual filesystems +# --------------------------------------------------------------------------- +echo "==> Unmounting virtual filesystems" +umount "${CHROOT}/scripts" || true +umount "${CHROOT}/run" || true +umount "${CHROOT}/sys" || true +umount "${CHROOT}/proc" || true +umount "${CHROOT}/dev" || true + +# --------------------------------------------------------------------------- +# 7. Pack the full system as a squashfs (xz compressed) +# --------------------------------------------------------------------------- +echo "==> Creating squashfs from chroot (xz — this may take a while)" +mksquashfs "$CHROOT" "${ISOROOT}/rootfs.squashfs" \ + -comp xz -Xdict-size 100% -noappend \ + -e boot/initramfs-lts 2>/dev/null || \ +mksquashfs "$CHROOT" "${ISOROOT}/rootfs.squashfs" \ + -comp xz -noappend +echo " squashfs size: $(du -sh "${ISOROOT}/rootfs.squashfs" | cut -f1)" + +# --------------------------------------------------------------------------- +# 8. Copy kernel into ISO root +# --------------------------------------------------------------------------- +echo "==> Copying kernel" +cp "${CHROOT}/boot/vmlinuz-lts" "${ISOROOT}/vmlinuz" + +# --------------------------------------------------------------------------- +# 9. Build tiny initramfs: busybox + init script that mounts the squashfs +# --------------------------------------------------------------------------- +echo "==> Building tiny initramfs" +INITRD="/tmp/initrd" +rm -rf "$INITRD" +mkdir -p "${INITRD}"/{bin,dev,proc,sys,mnt/boot,mnt/squash,mnt/upper,mnt/work,mnt/newroot} + +# Static busybox — no external library deps +BBOX=$(find /bin /usr/bin /usr/sbin -name 'busybox.static' -o -name 'busybox' 2>/dev/null \ + | xargs -r file 2>/dev/null | grep -i 'statically linked' | cut -d: -f1 | head -1) +[[ -z "$BBOX" ]] && { echo "ERROR: cannot find a statically linked busybox" >&2; exit 1; } +echo " using static busybox: $BBOX" +cp "$BBOX" "${INITRD}/bin/busybox" +chmod +x "${INITRD}/bin/busybox" +for cmd in sh mount umount mkdir mknod switch_root mdev sleep; do + ln -sf busybox "${INITRD}/bin/${cmd}" +done + +cat > "${INITRD}/init" <<'INIT_EOF' +#!/bin/sh +mount -t proc none /proc +mount -t sysfs none /sys +mount -t devtmpfs none /dev 2>/dev/null || mdev -s + +# Scan block devices for the ISO containing rootfs.squashfs +found=0 +for try in 1 2 3 4 5; do + for dev in /dev/sr0 /dev/sda /dev/sda1 /dev/sdb /dev/sdb1 /dev/sdc /dev/sdc1; do + [ -b "$dev" ] || continue + mount -t iso9660 -o ro "$dev" /mnt/boot 2>/dev/null || \ + mount -o ro "$dev" /mnt/boot 2>/dev/null || continue + if [ -f /mnt/boot/rootfs.squashfs ]; then + found=1 + break 2 + fi + umount /mnt/boot 2>/dev/null + done + sleep 1 +done + +if [ "$found" != "1" ]; then + echo "ERROR: rootfs.squashfs not found — dropping to shell" + exec sh +fi + +mount -t squashfs -o ro /mnt/boot/rootfs.squashfs /mnt/squash + +mount -t tmpfs tmpfs /mnt/upper +mkdir -p /mnt/upper/rw /mnt/upper/work +mount -t overlay overlay \ + -o lowerdir=/mnt/squash,upperdir=/mnt/upper/rw,workdir=/mnt/upper/work \ + /mnt/newroot + +exec switch_root /mnt/newroot /sbin/init +INIT_EOF +chmod +x "${INITRD}/init" + +( cd "$INITRD" && find . | cpio --quiet -oH newc | gzip -9 ) > "${ISOROOT}/initramfs.gz" +echo " initramfs size: $(du -sh "${ISOROOT}/initramfs.gz" | cut -f1)" +echo " initramfs contents:" +zcat "${ISOROOT}/initramfs.gz" | cpio -t 2>/dev/null + +# --------------------------------------------------------------------------- +# 10. Build ISO with grub-mkrescue (BIOS + UEFI hybrid) +# grub-mkrescue uses its own file loader — no BIOS INT 13h size limits. +# --------------------------------------------------------------------------- +echo "==> Writing GRUB config" +mkdir -p "${ISOROOT}/boot/grub" +cat > "${ISOROOT}/boot/grub/grub.cfg" <<'EOF' +set timeout=5 +set default=0 + +menuentry "Alpine Linux USB Rescue" { + linux /vmlinuz quiet init=/sbin/init + initrd /initramfs.gz +} +EOF + +echo "==> Building hybrid ISO with grub-mkrescue: ${ISO}" +grub-mkrescue -o "$ISO" "$ISOROOT" -- -V ALPINE_RESCUE + +# --------------------------------------------------------------------------- +# Done +# --------------------------------------------------------------------------- +ISO_SIZE=$(du -sh "$ISO" | cut -f1) +echo "" +echo "================================================================" +echo " Build complete!" +echo " ISO : ${ISO} (${ISO_SIZE})" +echo "" +echo " Burn to USB:" +echo " dd if=${ISO} of=/dev/sdX bs=4M status=progress && sync" +echo "" +echo " Burn to CD/DVD:" +echo " cdrecord dev=/dev/sr0 ${ISO}" +echo "" +echo " Default login : root / alpine" +echo " Nebula tunnel : auto-starts on boot (needs certs in nebula/)" +echo "================================================================"