diff --git a/README.md b/README.md
index 3c7a2f4..13b8302 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
| Template ID | OS | Version | Path | LUKS encrypted? | Mac Address | IP Address |
| :---------- | :--------------------------------------------------------------------------------------------- | :-------- | :---------------------- | :-------------- | :---------------- | :---------------------- |
-| 65000 |
Debian | 13-trixie | `debian/13-trixie-luks` | ✅ | BC:24:11:00:13:37 | 192.168.9.29 (via DHCP) |
+| 65000 |
Debian | 13-trixie | `debian/13-trixie` | optional | BC:24:11:00:13:37 | 192.168.9.29 (via DHCP) |
## Repository structure
@@ -28,14 +28,14 @@ Name
├── _scripts/ Support scripts for building templates.
│ └── unlock-luks-after-install.py* Unlocks the LUKS encrypted Disk on the 1st Boot after installation.
├── debian/ Debian template definitions and assets (Packer templates, cloud-init/KS files, provisioning files).
-│ └── 13-trixie-luks/ Template definition and assets for the Trixie template.
+│ └── 13-trixie/ Template definition and assets for the Trixie template.
│ ├── files/ Files used for the file provisioner.
│ │ ├── 99-pve.cfg Configures the data sources for cloud-init.
│ │ └── debian.sources Debian package sources.
│ ├── http/ Files that Packer provides during build via http.
-│ │ ├── ks.cfg Kickstart configuration.
-│ │ ├── meta-data cloud-init configuration.
-│ │ └── user-data cloud-init configuration.
+│ │ └── preseed.cfg.pkrtpl Debian preseed template.
+│ ├── variants/ Packer var-files for optional image variants.
+│ │ └── luks.pkrvars.hcl Enables LUKS encryption.
│ ├── credentials.auto.pkrvars.hcl -> ../../credentials.auto.pkrvars.hcl Local secrets for Packer (API token, endpoints) used at build time.
│ ├── debian-trixie.pkr.hcl The build template.
│ ├── variables-common.pkr.hcl -> ../../variables-common.pkr.hcl Shared Packer variables used by templates.
@@ -88,12 +88,27 @@ To build a template run:
mise run build
```
-## Build LUKS encrypted Templates
-
-To build a template run:
+For Debian 13 Trixie without LUKS:
```shell
-mise run build-luks
+mise run build debian/13-trixie
+```
+
+## Build LUKS encrypted Templates
+
+Debian LUKS builds use the same template directory and enable encryption through
+`debian/13-trixie/variants/luks.pkrvars.hcl`.
+
+To build a LUKS encrypted Debian 13 Trixie template run:
+
+```shell
+mise run build-luks debian/13-trixie
+```
+
+The equivalent direct Packer command is:
+
+```shell
+packer build -var-file=debian/13-trixie/variants/luks.pkrvars.hcl debian/13-trixie
```
## Setup new templates
@@ -104,4 +119,4 @@ Run:
mise run setup
```
-E.g. `mise run setup debian 13-trixie` or `mise run setup debian 13-trixie-luks`.
+E.g. `mise run setup debian 13-trixie`.
diff --git a/_scripts/unlock-luks-after-install.py b/_scripts/unlock-luks-after-install.py
index d544da0..04b0c13 100755
--- a/_scripts/unlock-luks-after-install.py
+++ b/_scripts/unlock-luks-after-install.py
@@ -32,11 +32,24 @@ def load_hcl(path: Path) -> dict:
return hcl2.load(handle)
-def get_variable_default(hcl_data: dict, name: str) -> str | None:
- for variable_block in hcl_data.get("variable", []):
- if name in variable_block:
- return variable_block[name].get("default")
- return None
+def resolve_input_path(path: str, script_root: Path) -> Path:
+ resolved = Path(path)
+ if not resolved.is_absolute():
+ resolved = script_root / resolved
+ return resolved
+
+
+def merge_values(*hcl_data_items: dict) -> dict:
+ values = {}
+ for hcl_data in hcl_data_items:
+ for variable_block in hcl_data.get("variable", []):
+ for name, body in variable_block.items():
+ if isinstance(body, dict) and "default" in body:
+ values[name] = body["default"]
+ for name, value in hcl_data.items():
+ if name != "variable":
+ values[name] = value
+ return values
def main() -> int:
@@ -55,29 +68,32 @@ def main() -> int:
default=45,
help="Seconds to wait before sending the LUKS password (default: 45).",
)
+ parser.add_argument(
+ "--var-file",
+ action="append",
+ default=[],
+ help="Path to an HCL var-file passed through to the Packer build.",
+ )
args = parser.parse_args()
script_root = Path(__file__).resolve().parents[1]
variables_common_path = script_root / "variables-common.pkr.hcl"
credentials_path = script_root / "credentials.auto.pkrvars.hcl"
- vars_dir = Path(args.template)
- if not vars_dir.is_absolute():
- vars_dir = script_root / vars_dir
+ vars_dir = resolve_input_path(args.template, script_root)
variables_path = vars_dir / "variables.pkr.hcl"
+ var_file_paths = [resolve_input_path(var_file, script_root) for var_file in args.var_file]
variables_common = load_hcl(variables_common_path)
credentials = load_hcl(credentials_path)
variables = load_hcl(variables_path)
+ var_files = [load_hcl(var_file_path) for var_file_path in var_file_paths]
+ values = merge_values(variables_common, variables, credentials, *var_files)
- proxmox_api_url = get_variable_default(variables_common, "proxmox_api_url")
- proxmox_skip_tls_verify = (
- get_variable_default(variables_common, "proxmox_skip_tls_verify") or False
- )
- default_luks_passphrase = get_variable_default(
- variables_common, "default_luks_passphrase"
- )
- proxmox_node = get_variable_default(variables, "proxmox_node")
- template_vm_id = get_variable_default(variables, "template_vm_id")
+ proxmox_api_url = values.get("proxmox_api_url")
+ proxmox_skip_tls_verify = values.get("proxmox_skip_tls_verify", False)
+ default_luks_passphrase = values.get("default_luks_passphrase")
+ proxmox_node = values.get("proxmox_node")
+ template_vm_id = values.get("template_vm_id")
_ = (
proxmox_api_url,
@@ -149,7 +165,10 @@ def main() -> int:
log(f"Listening for POST on /install_finished at port {port}")
- build_cmd = ["mise", "build", args.template, "-i", str(port)]
+ build_cmd = ["mise", "run", "build", args.template]
+ for var_file_path in var_file_paths:
+ build_cmd.extend(["--var-file", str(var_file_path)])
+ build_cmd.extend(["-i", str(port)])
build_proc = subprocess.Popen(
build_cmd,
stdout=subprocess.PIPE,
diff --git a/debian/13-trixie-luks/credentials.auto.pkrvars.hcl b/debian/13-trixie-luks/credentials.auto.pkrvars.hcl
deleted file mode 120000
index 2704ed7..0000000
--- a/debian/13-trixie-luks/credentials.auto.pkrvars.hcl
+++ /dev/null
@@ -1 +0,0 @@
-../../credentials.auto.pkrvars.hcl
\ No newline at end of file
diff --git a/debian/13-trixie-luks/debian-trixie.pkr.hcl b/debian/13-trixie-luks/debian-trixie.pkr.hcl
deleted file mode 100644
index a4fa2ae..0000000
--- a/debian/13-trixie-luks/debian-trixie.pkr.hcl
+++ /dev/null
@@ -1,223 +0,0 @@
-packer {
- required_plugins {
- proxmox = {
- version = "~> 1"
- source = "github.com/hashicorp/proxmox"
- }
- }
-}
-
-source "proxmox-iso" "debian-13-trixie-luks" {
- # Proxmox Connection Settings
- proxmox_url = "${var.proxmox_api_url}"
- username = "${var.proxmox_api_token_id}"
- token = "${var.proxmox_api_token_secret}"
-
- # Skip TLS Verification
- insecure_skip_tls_verify = "${var.proxmox_skip_tls_verify}"
-
- # VM General Settings
- node = "${var.proxmox_node}"
- vm_id = "${var.template_vm_id}"
- vm_name = "debian-13-trixie-luks-${local.timestamp}"
- template_description = "Debian 13 Trixie, LUKS encrypted, built with Packer on ${local.timestamp}\n\nLUKS default passphrase: `${var.default_luks_passphrase}`"
- os = "l26"
- qemu_agent = true
-
- # VM Hardware Settings
- machine = "q35"
- cpu_type = "${var.template_cpu_type}"
- cores = 2
- memory = 2048
- ballooning_minimum = 2048
- bios = "ovmf"
- scsi_controller = "virtio-scsi-single"
- disks {
- disk_size = "30G"
- format = "qcow2"
- storage_pool = "${var.disk_storage_pool}"
- type = "scsi" # VirtIO-SCSI better maintained as virtio-blk has been deprecated in Proxmox VE 7.4+ and may cause issues with newer Linux kernels
- io_thread = true
- ssd = true
- }
-
- efi_config {
- efi_storage_pool = "${var.disk_storage_pool}"
- pre_enrolled_keys = true
- efi_format = "raw"
- efi_type = "4m"
- }
-
- serials = [
- "socket"
- ]
-
- # Download ISO
- boot_iso {
- type = "scsi"
- iso_url = "${var.iso_url}"
- unmount = true
- iso_storage_pool = "${var.iso_storage_pool}"
- iso_checksum = "${var.iso_checksum}"
- }
-
- # VM Network Settings
- network_adapters {
- model = "virtio"
- mac_address = "${var.mac_address}"
- bridge = "${var.network_bridge}"
- firewall = "true"
- }
-
- # VM Cloud-Init Settings
- cloud_init = true
- cloud_init_storage_pool = "${var.disk_storage_pool}"
- cloud_init_disk_type = "scsi"
-
- # PACKER Boot Commands
- boot = "order=scsi0;scsi1"
- boot_wait = "10s"
- communicator = "ssh"
- boot_command = [
- "c",
- "linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
- "DEBIAN_FRONTEND=text ",
- "console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
- "passwd/root-password='${var.default_root_passphrase}' ",
- "passwd/root-password-again='${var.default_root_passphrase}' ",
- "partman-crypto/passphrase='${var.default_luks_passphrase}' ",
- "partman-crypto/passphrase-again='${var.default_luks_passphrase}' ",
- "INSTALL_FINISHED_INFORM_URL='http://{{ .HTTPIP }}:${var.install_finished_inform_port}/install_finished' ",
- "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg noprompt",
- "initrd /install.amd/initrd.gz",
- "DEBCONF_DEBUG=5",
- "boot"
- ]
-
- # PACKER Autoinstall Settings
- http_directory = "debian/13-trixie-luks/http"
- http_interface = "${var.source_proxmox_http_interface}"
-
- # SSH Settings
- ssh_username = "root"
- ssh_password = "${var.default_root_passphrase}"
- ssh_timeout = "20m"
- ssh_pty = true
-}
-
-build {
- name = "debian-13-trixie-luks-image"
- sources = ["source.proxmox-iso.debian-13-trixie-luks"]
-
- # Install dependencies and default packages
- provisioner "shell" {
- inline = [
- "export DEBIAN_FRONTEND=noninteractive",
- "apt-get update",
- "apt-get install -y age apt-transport-https aria2 bat bc bmon btop ca-certificates curl duf eza fastfetch fzf gdisk git gnupg htop iftop iotop iperf jq lsof magic-wormhole mosh mtr ncdu parted progress pv ripgrep rsync smartmontools socat sudo tmux usbutils vim wget yq zsh zstd"
- ]
- }
-
- # Install Tailscale
- provisioner "shell" {
- script = "debian/13-trixie-luks/scripts/tailscale.sh"
- }
-
- # Setup CrowdSec Repo
- provisioner "shell" {
- script = "debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh"
- }
-
- # Install CrowdSec
- provisioner "shell" {
- inline = [
- "apt-get install -y crowdsec",
- "apt-get install -y crowdsec-firewall-bouncer-iptables"
- ]
- }
-
- # Configure CrowdSec
- provisioner "shell" {
- script = "debian/13-trixie-luks/scripts/crowdsec-configuration.sh"
- }
-
- # Provisioning the VM Template for Cloud-Init Integration in Proxmox #2
- provisioner "file" {
- source = "debian/13-trixie-luks/files/99-pve.cfg"
- destination = "/tmp/99-pve.cfg"
- }
-
- # Provisioning the VM Template for Cloud-Init Integration in Proxmox #3
- provisioner "shell" {
- inline = ["sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg"]
- }
-
- # Remove CD-ROM entries from APT sources list
- provisioner "shell" {
- inline = ["sed -i '/cdrom/d' /etc/apt/sources.list"]
- }
-
- # Add custom APT sources list
- provisioner "file" {
- source = "debian/13-trixie-luks/files/debian.sources"
- destination = "/etc/apt/sources.list.d/debian.sources"
- }
-
- provisioner "file" {
- source = "debian/13-trixie-luks/files/90-initial-login-setup.sh"
- destination = "/etc/profile.d/90-initial-login-setup.sh"
- }
-
- provisioner "file" {
- source = "debian/13-trixie-luks/files/initial-setup.sh"
- destination = "/usr/local/bin/initial-setup.sh"
- }
-
- provisioner "shell" {
- inline = [
- "chmod +x /usr/local/bin/initial-setup.sh"
- ]
- }
-
- # Install Clevis
- provisioner "shell" {
- inline = [
- "apt-get update",
- "apt-get install -y clevis clevis-luks clevis-initramfs"
- ]
- }
-
- # Setup Serial Console for xterm.js in Proxmox VE
- provisioner "shell" {
- inline = [
- "sed -i 's/#\\?GRUB_CMDLINE_LINUX=.*\"/GRUB_CMDLINE_LINUX=\"console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0\"/' /etc/default/grub",
- "sed -i 's/#\\?GRUB_TERMINAL=.*/GRUB_TERMINAL=\"serial console\"/' /etc/default/grub",
- "sed -i 's/#\\?GRUB_SERIAL_COMMAND=.*/GRUB_SERIAL_COMMAND=\"serial --speed=115200\"/' /etc/default/grub",
- "update-grub"
- ]
- }
-
- # Provisioning the VM Template for Cloud-Init Integration in Proxmox #1
- provisioner "shell" {
- inline = [
- "rm /etc/ssh/ssh_host_*",
- "truncate -s 0 /etc/machine-id",
- "apt -y autoremove --purge 2> /dev/null",
- "apt -y clean 2> /dev/null",
- "apt -y autoclean 2> /dev/null",
- "rm -rf /var/cache/apt/archives /var/lib/apt/lists/*",
- "cloud-init clean",
- "rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
- "sync"
- ]
- }
-
- # Remove temporary settings and configuration for packer build
- provisioner "shell" {
- inline = [
- "sed -i 's/^#\\?PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config",
- "sed -i 's/^#\\?PasswordAuthentication .*/PasswordAuthentication no/' /etc/ssh/sshd_config",
- "passwd -dl root"
- ]
- }
-}
diff --git a/debian/13-trixie-luks/files/90-initial-login-setup.sh b/debian/13-trixie-luks/files/90-initial-login-setup.sh
deleted file mode 100644
index 0ec65be..0000000
--- a/debian/13-trixie-luks/files/90-initial-login-setup.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#! /bin/sed 2,5!d;s/^#.//
-# This script must be sourced from within a shell
-# and not executed. For instance with:
-#
-# . /usr/local/bin/initial-setup.sh
-
-# Only run in interactive shells
-case $- in
- *i*) ;;
- *) return ;;
-esac
-
-if [ "$EUID" -ne 0 ]; then
- if ! command -v sudo >/dev/null 2>&1 || ! sudo -n true >/dev/null 2>&1; then
- echo "Error: must be root or have sudo privileges to run initial login setup." >&2
- return
- fi
-fi
-
-SENTINEL="/var/lib/initial-login-setup.done"
-
-if [ ! -f "$SENTINEL" ] && [ -x /usr/local/bin/initial-setup.sh ]; then
- sudo touch "$SENTINEL"
- sudo /usr/local/bin/initial-setup.sh
-fi
diff --git a/debian/13-trixie-luks/files/99-pve.cfg b/debian/13-trixie-luks/files/99-pve.cfg
deleted file mode 100644
index a78672c..0000000
--- a/debian/13-trixie-luks/files/99-pve.cfg
+++ /dev/null
@@ -1 +0,0 @@
-datasource_list: [ConfigDrive, NoCloud]
\ No newline at end of file
diff --git a/debian/13-trixie-luks/files/debian.sources b/debian/13-trixie-luks/files/debian.sources
deleted file mode 100644
index 95cb2db..0000000
--- a/debian/13-trixie-luks/files/debian.sources
+++ /dev/null
@@ -1,17 +0,0 @@
-Types: deb
-URIs: http://ftp.de.debian.org/debian/
-Suites: trixie
-Components: main contrib non-free non-free-firmware
-Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
-
-Types: deb
-URIs: http://ftp.de.debian.org/debian/
-Suites: trixie-updates
-Components: main contrib non-free non-free-firmware
-Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
-
-Types: deb
-URIs: http://security.debian.org/
-Suites: trixie-security
-Components: main contrib non-free non-free-firmware
-Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
diff --git a/debian/13-trixie-luks/files/initial-setup.sh b/debian/13-trixie-luks/files/initial-setup.sh
deleted file mode 100644
index 1a2c426..0000000
--- a/debian/13-trixie-luks/files/initial-setup.sh
+++ /dev/null
@@ -1,766 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-IFS=$'\n\t'
-
-SCRIPT_NAME="$(basename "$0")"
-TASK_INDEX=0
-TASK_TOTAL=0
-TEMP_FILES=()
-STORAGE_DETECTED=0
-
-ROOT_SOURCE=""
-VG_NAME=""
-LV_NAME=""
-PV_NAME=""
-LUKS_DEV=""
-LUKS_NAME=""
-LUKS_PART=""
-DISK_DEV=""
-PART_NUM=""
-
-if [ -t 1 ]; then
- BOLD="$(tput bold 2>/dev/null || true)"
- DIM="$(tput dim 2>/dev/null || true)"
- RED="$(tput setaf 1 2>/dev/null || true)"
- GREEN="$(tput setaf 2 2>/dev/null || true)"
- YELLOW="$(tput setaf 3 2>/dev/null || true)"
- BLUE="$(tput setaf 4 2>/dev/null || true)"
- RESET="$(tput sgr0 2>/dev/null || true)"
-else
- BOLD=""
- DIM=""
- RED=""
- GREEN=""
- YELLOW=""
- BLUE=""
- RESET=""
-fi
-
-die() {
- echo "${RED}Error:${RESET} $*" >&2
- exit 1
-}
-
-log_info() {
- echo "${BLUE}INFO:${RESET} $*"
-}
-
-log_ok() {
- echo "${GREEN}OK:${RESET} $*"
-}
-
-log_warn() {
- echo "${YELLOW}WARN:${RESET} $*"
-}
-
-section() {
- local title="$1"
- echo
- echo "${BOLD}${title}${RESET}"
- echo "${DIM}------------------------------------------------------------${RESET}"
-}
-
-add_temp_file() {
- TEMP_FILES+=("$1")
-}
-
-cleanup() {
- local file
- for file in "${TEMP_FILES[@]:-}"; do
- [ -f "$file" ] && rm -f "$file"
- done
-}
-trap cleanup EXIT
-
-ensure_tty() {
- if [ ! -t 0 ] || [ ! -t 1 ]; then
- die "This setup must run interactively in a TTY."
- fi
-}
-
-ensure_root() {
- if [ "${EUID:-$(id -u)}" -ne 0 ]; then
- if command -v sudo >/dev/null 2>&1; then
- log_info "Re-running with sudo..."
- exec sudo -E "$0" "$@"
- fi
- die "Must be root or have sudo privileges to run this setup."
- fi
-}
-
-require_cmd() {
- local cmd="$1"
- if ! command -v "$cmd" >/dev/null 2>&1; then
- log_warn "Missing command: $cmd"
- return 1
- fi
- return 0
-}
-
-prompt_input() {
- local label="$1"
- local default="${2:-}"
- local value=""
- if [ -n "$default" ]; then
- read -r -p "${label} [${default}]: " value /dev/tty
- if [ -n "$value" ]; then
- printf '%s' "$value"
- return 0
- fi
- log_warn "Value cannot be empty."
- done
-}
-
-prompt_secret_confirm() {
- local label="$1"
- local confirm_label="$2"
- local a=""
- local b=""
- while true; do
- read -r -s -p "${label}: " a /dev/tty
- read -r -s -p "${confirm_label}: " b /dev/tty
- if [ -z "$a" ]; then
- log_warn "Value cannot be empty."
- continue
- fi
- if [ "$a" != "$b" ]; then
- log_warn "Values do not match. Please try again."
- continue
- fi
- printf '%s' "$a"
- return 0
- done
-}
-
-confirm() {
- local label="$1"
- local default="${2:-yes}"
- local prompt=""
- local answer=""
-
- if [ "$default" = "yes" ]; then
- prompt="[Y/n]"
- else
- prompt="[y/N]"
- fi
-
- while true; do
- read -r -p "${label} ${prompt} " answer /dev/null 2>&1; then
- numfmt --to=iec --suffix=B "$bytes"
- else
- awk -v b="$bytes" 'BEGIN {
- split("B KiB MiB GiB TiB", u, " ");
- i=1;
- while (b>=1024 && i<5) { b/=1024; i++; }
- printf "%.1f %s", b, u[i];
- }'
- fi
-}
-
-mib_to_human() {
- local mib="$1"
- awk -v m="$mib" 'BEGIN { printf "%.1f GiB", m/1024 }'
-}
-
-add_task() {
- TASK_TITLES+=("$1")
- TASK_FUNCS+=("$2")
- TASK_TOTAL=$((TASK_TOTAL + 1))
-}
-
-run_tasks() {
- local i
- local title
- local func
- for i in "${!TASK_FUNCS[@]}"; do
- TASK_INDEX=$((TASK_INDEX + 1))
- title="${TASK_TITLES[$i]}"
- func="${TASK_FUNCS[$i]}"
- section "Task ${TASK_INDEX}/${TASK_TOTAL}: ${title}"
- "$func"
- done
-}
-
-lsblk_attr() {
- local path="$1"
- local attr="$2"
- lsblk -dn -o "$attr" "$path" 2>/dev/null | head -n1 | xargs || true
-}
-
-infer_disk_part_from_partition() {
- local part_path="$1"
- local resolved
- local base
-
- resolved="$(readlink -f "$part_path" 2>/dev/null || printf '%s' "$part_path")"
- base="$(basename "$resolved")"
-
- if [[ "$base" =~ ^(nvme[0-9]+n[0-9]+)p([0-9]+)$ ]]; then
- printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
- return 0
- fi
- if [[ "$base" =~ ^(mmcblk[0-9]+)p([0-9]+)$ ]]; then
- printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
- return 0
- fi
- if [[ "$base" =~ ^(md[0-9]+)p([0-9]+)$ ]]; then
- printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
- return 0
- fi
- if [[ "$base" =~ ^((sd|vd|xvd|hd)[a-z]+)([0-9]+)$ ]]; then
- printf '/dev/%s\n%s\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[3]}"
- return 0
- fi
- return 1
-}
-
-resolve_luks_backing_partition() {
- local mapper_path="$1"
- local mapper_name="$2"
- local mapper_name_alt="$3"
- local part=""
-
- if command -v cryptsetup >/dev/null 2>&1; then
- part="$(cryptsetup status "$mapper_name" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
- if [ -z "$part" ] && [ -n "$mapper_name_alt" ] && [ "$mapper_name_alt" != "$mapper_name" ]; then
- part="$(cryptsetup status "$mapper_name_alt" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
- fi
- if [ -z "$part" ]; then
- part="$(cryptsetup status "$mapper_path" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
- fi
- fi
-
- if [ -z "$part" ]; then
- part="$(lsblk -nro PATH,TYPE -s "$mapper_path" 2>/dev/null | awk '$2=="part" {print $1; exit}' | xargs || true)"
- fi
-
- printf '%s' "$part"
-}
-
-refresh_partition_table() {
- local disk="$1"
- if command -v partprobe >/dev/null 2>&1; then
- partprobe "$disk" || true
- fi
- if command -v partx >/dev/null 2>&1; then
- partx -u "$disk" || true
- fi
- if command -v udevadm >/dev/null 2>&1; then
- udevadm settle || true
- fi
-}
-
-repair_gpt_backup_header() {
- local disk="$1"
-
- if command -v sgdisk >/dev/null 2>&1; then
- if sgdisk -e "$disk" >/dev/null 2>&1; then
- refresh_partition_table "$disk"
- return 0
- fi
- fi
-
- if parted -s "$disk" print >/dev/null 2>&1; then
- return 0
- fi
-
- if printf 'Fix\n' | parted ---pretend-input-tty "$disk" print >/dev/null 2>&1; then
- refresh_partition_table "$disk"
- return 0
- fi
-
- return 1
-}
-
-wait_for_partition_growth() {
- local part="$1"
- local old_bytes="$2"
- local new_bytes=0
- local i=0
-
- for ((i = 0; i < 12; i++)); do
- new_bytes="$(blockdev --getsize64 "$part" 2>/dev/null || echo 0)"
- if [ "$new_bytes" -gt "$old_bytes" ]; then
- return 0
- fi
- sleep 1
- done
- return 1
-}
-
-is_last_partition_on_disk() {
- local disk="$1"
- local part_num="$2"
- local last_part
-
- last_part="$(parted -ms "$disk" unit s print 2>/dev/null | awk -F: '$1 ~ /^[0-9]+$/ {last=$1} END {print last}')"
- [ -n "$last_part" ] && [ "$part_num" = "$last_part" ]
-}
-
-get_trailing_free_bytes() {
- local disk="$1"
- local part_num="$2"
- local disk_bytes
- local part_end_bytes
- local free_bytes
-
- disk_bytes="$(blockdev --getsize64 "$disk" 2>/dev/null || true)"
- part_end_bytes="$(parted -ms "$disk" unit B print 2>/dev/null | awk -F: -v p="$part_num" '$1==p {gsub("B","",$3); print $3; exit}')"
- if [ -z "$disk_bytes" ] || [ -z "$part_end_bytes" ]; then
- return 1
- fi
-
- free_bytes=$((disk_bytes - part_end_bytes - 1))
- if [ "$free_bytes" -lt 0 ]; then
- free_bytes=0
- fi
- echo "$free_bytes"
-}
-
-resize_open_luks_mapping() {
- if [ -n "$LUKS_NAME" ] && cryptsetup resize "$LUKS_NAME" >/dev/null 2>&1; then
- return 0
- fi
- cryptsetup resize "$LUKS_DEV" >/dev/null 2>&1
-}
-
-detect_storage_stack() {
- STORAGE_DETECTED=0
- LUKS_NAME=""
- LUKS_PART=""
- DISK_DEV=""
- PART_NUM=""
-
- require_cmd findmnt || return 1
- require_cmd lvs || return 1
- require_cmd pvs || return 1
- require_cmd lsblk || return 1
- require_cmd cryptsetup || return 1
-
- ROOT_SOURCE="$(findmnt -n -o SOURCE / || true)"
- if [ -z "$ROOT_SOURCE" ] || [ ! -e "$ROOT_SOURCE" ]; then
- log_warn "Unable to detect root device."
- return 1
- fi
-
- VG_NAME="$(lvs --noheadings -o vg_name "$ROOT_SOURCE" 2>/dev/null | xargs || true)"
- LV_NAME="$(lvs --noheadings -o lv_name "$ROOT_SOURCE" 2>/dev/null | xargs || true)"
- if [ -z "$VG_NAME" ]; then
- log_warn "Root does not appear to be on LVM."
- return 1
- fi
-
- PV_NAME="$(pvs --noheadings -o pv_name --select "vg_name=${VG_NAME}" 2>/dev/null | head -n1 | xargs || true)"
- if [ -z "$PV_NAME" ]; then
- log_warn "Unable to detect LVM physical volume."
- return 1
- fi
-
- LUKS_DEV="$PV_NAME"
- LUKS_NAME="$(basename "$LUKS_DEV")"
- local mapper_name_alt
- mapper_name_alt="$(lsblk_attr "$LUKS_DEV" NAME)"
-
- local luks_type
- luks_type="$(lsblk_attr "$LUKS_DEV" TYPE)"
- if [ "$luks_type" != "crypt" ]; then
- log_warn "LVM PV is not on a LUKS device (type: ${luks_type:-unknown}). LUKS resize will be skipped."
- return 1
- fi
-
- LUKS_PART="$(resolve_luks_backing_partition "$LUKS_DEV" "$LUKS_NAME" "$mapper_name_alt")"
- if [ -z "$LUKS_PART" ] || [ ! -b "$LUKS_PART" ]; then
- log_warn "Unable to detect LUKS backing partition."
- return 1
- fi
-
- local inferred
- local inferred_disk=""
- local inferred_part=""
- inferred="$(infer_disk_part_from_partition "$LUKS_PART" || true)"
- if [ -n "$inferred" ]; then
- inferred_disk="$(printf '%s\n' "$inferred" | sed -n '1p')"
- inferred_part="$(printf '%s\n' "$inferred" | sed -n '2p')"
- fi
-
- DISK_DEV="$inferred_disk"
- PART_NUM="$inferred_part"
-
- if [ -z "$DISK_DEV" ]; then
- local disk_parent
- disk_parent="$(lsblk_attr "$LUKS_PART" PKNAME)"
- if [ -n "$disk_parent" ]; then
- DISK_DEV="/dev/${disk_parent}"
- else
- DISK_DEV="$(lsblk -nro PATH,TYPE -s "$LUKS_PART" 2>/dev/null | awk '$2=="disk" {print $1; exit}' | xargs || true)"
- fi
- fi
-
- if [ -z "$PART_NUM" ]; then
- PART_NUM="$(lsblk_attr "$LUKS_PART" PARTNUM)"
- fi
-
- if [ -z "$DISK_DEV" ] || [ ! -b "$DISK_DEV" ] || [ -z "$PART_NUM" ] || ! [[ "$PART_NUM" =~ ^[0-9]+$ ]]; then
- log_warn "Unable to detect disk device or partition number."
- log_warn "Detected values: LUKS_PART=${LUKS_PART:-} DISK_DEV=${DISK_DEV:-} PART_NUM=${PART_NUM:-}"
- return 1
- fi
-
- STORAGE_DETECTED=1
- return 0
-}
-
-resize_lvm_on_luks() {
- if [ "$STORAGE_DETECTED" -ne 1 ]; then
- log_warn "Storage layout not detected; skipping resize."
- return 0
- fi
-
- require_cmd parted || return 0
- require_cmd blockdev || return 0
- require_cmd cryptsetup || return 0
- require_cmd pvresize || return 0
- require_cmd lvextend || return 0
-
- log_info "Root LV: ${ROOT_SOURCE}"
- log_info "VG: ${VG_NAME} | LV: ${LV_NAME}"
- log_info "LUKS device: ${LUKS_DEV}"
- log_info "LUKS partition: ${LUKS_PART}"
- log_info "Disk: ${DISK_DEV} | Partition number: ${PART_NUM}"
- [ -n "$LUKS_NAME" ] && log_info "LUKS mapper name: ${LUKS_NAME}"
-
- if ! repair_gpt_backup_header "$DISK_DEV"; then
- log_warn "Unable to repair or verify GPT backup header on ${DISK_DEV}; resize may fail."
- fi
-
- if ! is_last_partition_on_disk "$DISK_DEV" "$PART_NUM"; then
- log_warn "Partition ${PART_NUM} is not the last partition on ${DISK_DEV}. Automatic growth is skipped."
- return 0
- fi
-
- local part_size_before
- local free_bytes
-
- part_size_before="$(blockdev --getsize64 "$LUKS_PART" 2>/dev/null || echo 0)"
- free_bytes="$(get_trailing_free_bytes "$DISK_DEV" "$PART_NUM" || true)"
- if [ -z "$free_bytes" ]; then
- log_warn "Unable to determine free disk space."
- return 0
- fi
-
- if [ "$free_bytes" -lt $((1024 * 1024)) ]; then
- log_ok "No significant free space detected after the root partition."
- return 0
- fi
-
- log_info "Unallocated space available: $(human_bytes "$free_bytes")"
- if ! confirm "Extend partition, LUKS device, VG, and root LV now?" "yes"; then
- log_warn "Skipped resize."
- return 0
- fi
-
- log_info "Extending partition ${LUKS_PART} to 100% of disk..."
- if ! parted -s "$DISK_DEV" resizepart "$PART_NUM" 100%; then
- log_warn "Partition resize failed."
- return 0
- fi
-
- refresh_partition_table "$DISK_DEV"
- if [ "$part_size_before" -gt 0 ] && ! wait_for_partition_growth "$LUKS_PART" "$part_size_before"; then
- log_warn "Kernel has not reported the new partition size yet; continuing anyway."
- fi
-
- log_info "Resizing LUKS device..."
- if ! resize_open_luks_mapping; then
- log_warn "LUKS resize failed."
- return 0
- fi
-
- log_info "Resizing LVM physical volume..."
- if ! pvresize "$LUKS_DEV"; then
- log_warn "pvresize failed."
- return 0
- fi
-
- log_info "Extending root LV to use all free space..."
- if ! lvextend -l +100%FREE -r "$ROOT_SOURCE"; then
- log_warn "lvextend failed."
- return 0
- fi
-
- log_ok "Resize complete."
-}
-
-parse_size_to_mib() {
- local input="$1"
- local normalized
- normalized="$(echo "$input" | tr '[:upper:]' '[:lower:]' | xargs)"
- if [[ "$normalized" =~ ^[0-9]+$ ]]; then
- echo "$normalized"
- return 0
- fi
- if [[ "$normalized" =~ ^([0-9]+)(g|gb)$ ]]; then
- echo $((BASH_REMATCH[1] * 1024))
- return 0
- fi
- if [[ "$normalized" =~ ^([0-9]+)(m|mb)$ ]]; then
- echo "${BASH_REMATCH[1]}"
- return 0
- fi
- return 1
-}
-
-setup_swap() {
- require_cmd awk || return 0
- require_cmd fallocate || return 0
- require_cmd mkswap || return 0
- require_cmd swapon || return 0
-
- local mem_kib
- local mem_mib
- local swap_mib
-
- mem_kib="$(awk '/MemTotal/ {print $2}' /proc/meminfo)"
- mem_mib=$((mem_kib / 1024))
-
- if [ "$mem_mib" -lt 2048 ]; then
- swap_mib=$((mem_mib * 2))
- elif [ "$mem_mib" -lt 4096 ]; then
- swap_mib=$mem_mib
- else
- swap_mib=$((mem_mib / 5))
- fi
-
- log_info "Detected RAM: $(mib_to_human "$mem_mib")"
- log_info "Recommended swap size: $(mib_to_human "$swap_mib")"
-
- if ! confirm "Use recommended swap size?" "yes"; then
- local custom
- while true; do
- custom="$(prompt_input "Enter custom swap size (MiB or GiB, e.g. 2048 or 4G)")"
- if swap_mib="$(parse_size_to_mib "$custom")"; then
- if [ "$swap_mib" -gt 0 ]; then
- break
- fi
- fi
- log_warn "Invalid size. Try again."
- done
- fi
-
- local swapfile="/swapfile"
- if [ -e "$swapfile" ]; then
- log_warn "Swap file already exists at ${swapfile}."
- if ! confirm "Replace existing swap file?" "no"; then
- log_warn "Skipped swap setup."
- return 0
- fi
- if swapon --show=NAME --noheadings | grep -qx "$swapfile"; then
- swapoff "$swapfile" || true
- fi
- rm -f "$swapfile"
- fi
-
- log_info "Creating swap file (${swap_mib} MiB) at ${swapfile}..."
- fallocate -l "${swap_mib}M" "$swapfile"
- chmod 600 "$swapfile"
- mkswap "$swapfile" >/dev/null
- swapon "$swapfile"
-
- if ! grep -qE "^[[:space:]]*${swapfile}[[:space:]]" /etc/fstab; then
- echo "${swapfile} none swap sw 0 0" >> /etc/fstab
- fi
-
- log_ok "Swap enabled."
-}
-
-change_luks_passphrase() {
- if [ "$STORAGE_DETECTED" -ne 1 ]; then
- log_warn "Storage layout not detected; skipping LUKS passphrase change."
- return 0
- fi
- if [ -z "$LUKS_PART" ] || [ ! -e "$LUKS_PART" ]; then
- log_warn "LUKS partition not found; skipping."
- return 0
- fi
- require_cmd cryptsetup || return 0
-
- if ! confirm "Change LUKS passphrase in slot 0 now?" "yes"; then
- log_warn "Skipped LUKS passphrase change."
- return 0
- fi
-
- local old_pass
- local new_pass
- local tmp_old
- local tmp_new
-
- old_pass="$(prompt_secret "Enter current LUKS passphrase")"
- new_pass="$(prompt_secret_confirm "Enter new LUKS passphrase" "Confirm new LUKS passphrase")"
-
- tmp_old="$(mktemp)"
- tmp_new="$(mktemp)"
- add_temp_file "$tmp_old"
- add_temp_file "$tmp_new"
-
- printf '%s' "$old_pass" >"$tmp_old"
- printf '%s' "$new_pass" >"$tmp_new"
-
- log_info "Updating LUKS passphrase in slot 0..."
- if cryptsetup luksChangeKey --batch-mode --key-slot 0 --key-file "$tmp_old" "$LUKS_PART" "$tmp_new"; then
- log_ok "LUKS passphrase updated."
- else
- log_warn "Failed to update LUKS passphrase."
- fi
-}
-
-setup_clevis() {
- log_info "Clevis/Tang setup is not implemented in this template yet."
- if confirm "Would you like to configure Clevis with a Tang server now? (will be skipped)" "no"; then
- local tang
- tang="$(prompt_input "Tang server URL" "http://tang.int.r3w.de")"
- log_warn "Clevis setup for ${tang} is not implemented yet. Skipping."
- else
- log_info "Skipping Clevis setup."
- fi
-}
-
-setup_tailscale() {
- if ! require_cmd tailscale; then
- log_warn "Tailscale is not installed; skipping."
- return 0
- fi
-
- if ! confirm "Set up Tailscale now?" "yes"; then
- log_warn "Skipped Tailscale setup."
- return 0
- fi
-
- local server
- local tags
- local key
- local tag_list=""
- local t
-
- server="$(prompt_input "Tailscale/Headscale server URL" "https://vpn.s1q.dev")"
- tags="$(prompt_input "Client tags (comma-separated)" "server")"
- key="$(prompt_secret "Pre-authentication key")"
-
- if [ -n "$tags" ]; then
- IFS=',' read -r -a tag_array <<<"$tags"
- for t in "${tag_array[@]:-}"; do
- t="$(echo "$t" | xargs)"
- if [ -n "$t" ]; then
- if [ -n "$tag_list" ]; then
- tag_list+=","
- fi
- tag_list+="tag:${t}"
- fi
- done
- fi
-
- log_info "Bringing up Tailscale..."
- if [ -n "$tag_list" ]; then
- tailscale up --login-server "$server" --authkey "$key" --ssh --advertise-tags "$tag_list"
- else
- tailscale up --login-server "$server" --authkey "$key" --ssh
- fi
-
- log_ok "Tailscale setup complete."
-}
-
-setup_crowdsec() {
- if ! require_cmd cscli; then
- log_warn "CrowdSec (cscli) not installed; skipping."
- return 0
- fi
-
- if ! confirm "Set up CrowdSec now?" "yes"; then
- log_warn "Skipped CrowdSec setup."
- return 0
- fi
-
- local key
- key="$(prompt_secret "Enrollment key")"
-
- log_info "Enrolling CrowdSec..."
- if cscli console enroll -e "$key"; then
- log_info "Restarting CrowdSec service..."
- systemctl restart crowdsec || log_warn "Failed to restart crowdsec service."
- log_ok "CrowdSec enrollment complete."
- else
- log_warn "CrowdSec enrollment failed."
- fi
-}
-
-prompt_reboot() {
- log_warn "A reboot is strongly recommended after partition or swap changes."
- if confirm "Reboot now?" "yes"; then
- log_info "Rebooting..."
- reboot
- else
- log_info "Please reboot later to ensure changes take effect."
- fi
-}
-
-welcome() {
- section "Initial VM Setup"
- log_info "This setup runs once and is fully interactive."
- log_info "Hostname: $(hostname)"
-}
-
-main() {
- ensure_tty
- ensure_root "$@"
- welcome
-
- if detect_storage_stack; then
- log_ok "Detected LVM on LUKS storage layout."
- else
- log_warn "Storage layout detection incomplete; some steps may be skipped."
- fi
-
- TASK_TITLES=()
- TASK_FUNCS=()
-
- add_task "Resize LVM on LUKS (if free space exists)" resize_lvm_on_luks
- add_task "Configure swap file" setup_swap
- add_task "Change LUKS passphrase (slot 0)" change_luks_passphrase
- add_task "Clevis/Tang setup (placeholder)" setup_clevis
- add_task "Configure Tailscale" setup_tailscale
- add_task "Configure CrowdSec" setup_crowdsec
- add_task "Reboot recommendation" prompt_reboot
-
- run_tasks
- log_ok "Initial setup finished."
-}
-
-main "$@"
diff --git a/debian/13-trixie-luks/scripts/crowdsec-configuration.sh b/debian/13-trixie-luks/scripts/crowdsec-configuration.sh
deleted file mode 100644
index 6ac3f7a..0000000
--- a/debian/13-trixie-luks/scripts/crowdsec-configuration.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-set -euf -o pipefail
-
-export DEBIAN_FRONTEND=noninteractive
-
-# Enable write-ahead-logging (wal -- allowing more concurrency in SQLite that will improve performances in most scenarios.)
-sed -i -E '/^db_config:/,/^[^[:space:]]/{s/^([[:space:]]*)type:[[:space:]]*sqlite$/&\
-\1use_wal: true/}' /etc/crowdsec/config.yaml
diff --git a/debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh b/debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh
deleted file mode 100644
index 7b2e815..0000000
--- a/debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh
+++ /dev/null
@@ -1,370 +0,0 @@
-#!/bin/sh
-#
-# Inspired from packagecloud installation scripts
-#
-# #MIT License
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# Crowdsec repositories installation script
-#
-# This script:
-# - Requires `root` or `sudo` privileges to run
-# - Attempts to detect your Linux distribution and version and configure your
-# package management system for you.
-# - Installs dependencies and recommendations without asking for confirmation.
-# - Is POSIX compliant and can be run using bash or any POSIX-compliant shell
-
-
-unknown_os() {
- echo "Unfortunately, your operating system distribution and version are not supported by this script."
- echo
- echo "You can override the OS detection by setting os= and dist= prior to running this script."
- echo "You can find a list of supported OSes and distributions on our website: https://packagecloud.io/docs#os_distro_version"
- echo
- echo "For example, to force Ubuntu Trusty: os=ubuntu dist=trusty ./script.sh"
- echo
- echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
- exit 1
-}
-
-detect_os() {
- if [ -z "$os" ] && [ -z "$dist" ]; then
- if [ -e /etc/os-release ]; then
- . /etc/os-release
- os=$ID
- if [ "$os" = "poky" ]; then
- dist="$VERSION_ID"
- elif [ "$os" = "sles" ]; then
- dist="$VERSION_ID"
- os=opensuse
- elif [ "$os" = "opensuse" ]; then
- dist="$VERSION_ID"
- elif [ "$os" = "opensuse-leap" ]; then
- os=opensuse
- dist="$VERSION_ID"
- elif [ "$os" = "amzn" ]; then
- dist="$VERSION_ID"
- else
- dist=$(echo "$VERSION_ID" | awk -F '.' '{ print $1 }')
- fi
-
- elif command -v lsb_release >/dev/null; then
- # get major version (e.g. '5' or '6')
- dist=$(lsb_release -r | cut -f2 | awk -F '.' '{ print $1 }')
-
- # get os (e.g. 'centos', 'redhatenterpriseserver', etc)
- os=$(lsb_release -i | cut -f2 | awk '{ print tolower($1) }')
-
- elif [ -e /etc/oracle-release ]; then
- dist=$(cut -f5 --delimiter=' ' /etc/oracle-release | awk -F '.' '{ print $1 }')
- os='ol'
-
- elif [ -e /etc/fedora-release ]; then
- dist=$(cut -f3 --delimiter=' ' /etc/fedora-release)
- os='fedora'
-
- elif [ -e /etc/redhat-release ]; then
- os_hint=$(awk '{ print tolower($1) }' /etc/redhat-release)
- if [ "$os_hint" = "centos" ]; then
- dist=$(awk '{ print $3 }' /etc/redhat-release | awk -F '.' '{ print $1 }')
- os='centos'
- elif [ "$os_hint" = "scientific" ]; then
- dist=$(awk '{ print $4 }' /etc/redhat-release | awk -F '.' '{ print $1 }')
- os='scientific'
- else
- dist=$(awk '{ print tolower($7) }' /etc/redhat-release | cut -f1 --delimiter='.')
- os='redhatenterpriseserver'
- fi
-
- elif grep -q Amazon /etc/issue; then
- dist='6'
- os='aws'
- else
- unknown_os
- fi
- fi
-
- # remove whitespace from OS and dist name and transform to lowercase
- os=$(echo "$os" | tr -d ' ' | tr '[:upper:]' '[:lower:]')
- dist=$(echo "$dist" | tr -d ' ' | tr '[:upper:]' '[:lower:]')
-
- if [ -z "$dist" ]; then
- echo "Detected operating system as $os."
- else
- echo "Detected operating system as $os/$dist."
- fi
-
- if [ "$os" = "ol" ] || [ "$os" = "el" ] && [ "$dist" -gt 7 ]; then
- _skip_pygpgme=1
- else
- _skip_pygpgme=0
- fi
-
-}
-
-gpg_check_deb() {
- echo "Checking for gpg..."
- if command -v gpg >/dev/null; then
- echo "Detected gpg..."
- else
- echo "Installing gnupg for GPG verification..."
- if ! apt-get install -y gnupg; then
- echo "Unable to install GPG! Your base system has a problem; please check your default OS's package repositories because GPG should work."
- echo "Repository installation aborted."
- echo
- echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
- exit 1
- fi
- fi
-}
-
-curl_check_deb() {
- echo "Checking for curl..."
- if command -v curl >/dev/null; then
- echo "Detected curl..."
- else
- echo "Installing curl..."
-
- if apt-get install -q -y curl; then
- echo "Unable to install curl! Your base system has a problem; please check your default OS's package repositories because curl should work."
- echo "Repository installation aborted."
- echo
- echo "Please file an issue at https://github.com/crowdsecurity/crowdsec"
- exit 1
- fi
- fi
-}
-
-curl_check_rpm() {
- echo "Checking for curl..."
- if command -v curl >/dev/null; then
- echo "Detected curl..."
- else
- echo "Installing curl..."
- yum install -d0 -e0 -y curl
- fi
-}
-
-curl_check_zypper() {
- echo "Checking for curl..."
- if command -v curl >/dev/null; then
- echo "Detected curl..."
- else
- echo "Installing curl..."
- zypper install curl
- fi
-}
-
-finalize_yum_repo() {
- if [ "$_skip_pygpgme" = 0 ]; then
- echo "Installing pygpgme to verify GPG signatures..."
- yum install -y pygpgme --disablerepo="crowdsec_${repo}"
- if ! rpm -qa | grep -qw pygpgme; then
- echo
- echo "WARNING: "
- echo "The pygpgme package could not be installed. This means GPG verification is not possible for any RPM installed on your system. "
- echo "To fix this, add a repository with pygpgme. Usually, the EPEL repository for your system will have this. "
- echo "More information: https://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F"
- echo
-
- # set the repo_gpgcheck option to 0
- sed -i'' 's/repo_gpgcheck=1/repo_gpgcheck=0/' "/etc/yum.repos.d/crowdsec_${repo}.repo"
- fi
- fi
-
- echo "Installing yum-utils..."
- yum install -y yum-utils --disablerepo="crowdsec_${repo}"
- if ! rpm -qa | grep -qw yum-utils; then
- echo
- echo "WARNING: "
- echo "The yum-utils package could not be installed. This means you may not be able to install source RPMs or use other yum features."
- echo
- fi
-
- echo "Generating yum cache for crowdsec..."
- yum -q makecache -y --disablerepo='*' --enablerepo="crowdsec_${repo}"
-}
-
-install_debian_keyring() {
- if [ "$os" = "debian" ]; then
- echo "Installing debian-archive-keyring which is needed for installing "
- echo "apt-transport-https on many Debian systems."
- apt-get install -y debian-archive-keyring >/dev/null 2>&1
- fi
-}
-
-detect_apt_version() {
- apt_version_full=$(apt-get -v | head -1 | awk '{ print $2 }')
- apt_version_major=$(echo "$apt_version_full" | cut -d. -f1)
- apt_version_minor=$(echo "$apt_version_full" | cut -d. -f2)
- apt_version_modified="${apt_version_major}${apt_version_minor}0"
-
- echo "Detected apt version as $apt_version_full"
-}
-
-main() {
- if [ -z "$repo" ]; then
- repo="crowdsec"
- fi
-
- detect_os
- case $os in
- ubuntu | debian | raspbian | linuxmint)
- detect_apt_version
- gpg_check_deb
- curl_check_deb
- apt_source_path="/etc/apt/sources.list.d/crowdsec_${repo}.list"
- pre_reqs="apt-transport-https ca-certificates curl"
- if [ -f "$apt_source_path" ]; then
- echo
- echo "The file $apt_source_path already exists: overwriting it."
- echo
- fi
- # needed dependencies
- apt-get update -qq >/dev/null
- #shellcheck disable=SC2086
- DEBIAN_FRONTEND=noninteractive apt-get install -y -qq $pre_reqs >/dev/null
- # gpg keys
- gpg_key_url="https://packagecloud.io/crowdsec/${repo}/gpgkey"
- apt_keyrings_dir="/etc/apt/keyrings"
- gpg_keyring_path="$apt_keyrings_dir/crowdsec_${repo}-archive-keyring.gpg"
- gpg_key_path_old="/etc/apt/trusted.gpg.d/crowdsec_${repo}.gpg"
- echo
- echo "Importing packagecloud gpg key... "
- echo
-
- # move gpg key to old path if apt version is older than 1.1
- if [ "$apt_version_modified" -lt 110 ]; then
- curl -fsSL "$gpg_key_url" | gpg --dearmor >"$gpg_key_path_old"
- # grant 644 permisions to gpg key path old
- chmod 0644 "$gpg_key_path_old"
-
- # deletes the keyrings directory if it is empty
- echo "Packagecloud gpg key imported to $gpg_key_path_old"
- else
- if [ ! -d "$apt_keyrings_dir" ]; then
- install -d -m 0755 "$apt_keyrings_dir"
- fi
- # import the gpg key
- curl -fsSL "$gpg_key_url" | gpg --dearmor >"$gpg_keyring_path"
- # grant 644 permisions to gpg keyring path
- chmod 0644 "$gpg_keyring_path"
-
- echo "Packagecloud gpg key imported to $gpg_keyring_path"
- fi
- echo
- echo "Installing ${apt_source_path}..."
- echo
- echo "deb [signed-by=/etc/apt/keyrings/crowdsec_${repo}-archive-keyring.gpg] https://packagecloud.io/crowdsec/${repo}/any/ any main" >"$apt_source_path"
- echo "deb-src [signed-by=/etc/apt/keyrings/crowdsec_${repo}-archive-keyring.gpg] https://packagecloud.io/crowdsec/${repo}/any/ any main" >>"$apt_source_path"
- apt-get update -qq >/dev/null
-
- ;;
- centos | rhel | fedora | redhatentrepriseserver | amzn | cloudlinux | almalinux | rocky | opensuse | ol)
- if [ "$os" = "ol" ] && [ "$dist" = "7" ] || [ "$os" = "amzn" ] && [ "$dist" = "2" ]; then
- rpm_repo_config_url="https://packagecloud.io/install/repositories/crowdsec/${repo}/config_file.repo?os=${os}&dist=${dist}&source=script"
- else
- rpm_repo_config_url="https://packagecloud.io/install/repositories/crowdsec/${repo}/config_file.repo?os=rpm_any&dist=rpm_any&source=script"
- fi
- if [ "$os" = "opensuse" ]; then
- curl_check_zypper
- rpm_repo_path=/etc/zypp/repos.d/crowdsec_${repo}.repo
- else
- curl_check_rpm
- rpm_repo_path=/etc/yum.repos.d/crowdsec_${repo}.repo
- fi
-
- echo "Downloading repository file: $rpm_repo_config_url"
-
- curl -sSf "$rpm_repo_config_url" >"$rpm_repo_path"
- curl_exit_code=$?
- if [ "$curl_exit_code" = "22" ]; then
- echo
- echo
- echo "Unable to download repo config from: "
- echo "$rpm_repo_config_url"
- echo
- echo "This usually happens if your operating system is not supported by "
- echo "packagecloud.io, or this script's OS detection failed."
- echo
- echo "You can override the OS detection by setting os= and dist= prior to running this script."
- echo "You can find a list of supported OSes and distributions on our website: https://packagecloud.io/docs#os_distro_version"
- echo
- echo "For example, to force CentOS 6: os=el dist=6 ./script.sh"
- echo
- echo "If you are running a supported OS, please file an issue at https://github.com/crowdsecurity/crowdsec."
- [ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
- exit 1
- elif [ "$curl_exit_code" = "35" ] || [ "$curl_exit_code" = "60" ]; then
- echo
- echo "curl is unable to connect to packagecloud.io over TLS when running: "
- echo " curl $rpm_repo_config_url"
- echo
- echo "This is usually due to one of two things:"
- echo
- echo " 1.) Missing CA root certificates (make sure the ca-certificates package is installed)"
- echo " 2.) An old version of libssl. Try upgrading libssl on your system to a more recent version"
- echo
- echo "Contact support@crowdsec.net with information about your system for help."
- [ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
- exit 1
- elif [ "$curl_exit_code" -gt "0" ]; then
- echo
- echo "Unable to run: "
- echo " curl $rpm_repo_config_url"
- echo
- echo "Double check your curl installation and try again."
- echo
- echo "Please file an issue at https://github.com/crowdsecurity/crowdsec if you think the behavior is not intended"
- [ -e "$rpm_repo_path" ] && rm "$rpm_repo_path"
- exit 1
- else
- echo "done."
- fi
- if [ "$os" = "opensuse" ]; then
- zypper --gpg-auto-import-keys refresh "crowdsec_${repo}"
- zypper --gpg-auto-import-keys refresh "crowdsec_${repo}-source"
- else
- echo "$os"
- finalize_yum_repo
- fi
- ;;
- *)
- echo "Error This system is not supported (yet) by this script."
- echo "Please have a look at documentation https://docs.crowdsec.net/ or"
- echo "file an issue at https://github.com/crowdsecurity/crowdsec if you think"
- echo "the behavior is not intended"
-
- exit 1
- ;;
- esac
-
- echo
-}
-
-if [ "$(id -u)" -ne 0 ]; then
- echo "This script must be run as root"
- echo
- echo "file an issue at https://github.com/crowdsecurity/crowdsec if you think"
- echo "the behavior is not intended"
- exit 1
-fi
-
-main
diff --git a/debian/13-trixie-luks/scripts/tailscale.sh b/debian/13-trixie-luks/scripts/tailscale.sh
deleted file mode 100644
index 8ffd3f5..0000000
--- a/debian/13-trixie-luks/scripts/tailscale.sh
+++ /dev/null
@@ -1,726 +0,0 @@
-#!/bin/sh
-# Copyright (c) Tailscale Inc & contributors
-# SPDX-License-Identifier: BSD-3-Clause
-#
-# This script detects the current operating system, and installs
-# Tailscale according to that OS's conventions.
-#
-# Environment variables:
-# TRACK: Set to "stable" or "unstable" (default: stable)
-# TAILSCALE_VERSION: Pin to a specific version (e.g., "1.88.4")
-#
-# Examples:
-# curl -fsSL https://tailscale.com/install.sh | sh
-# curl -fsSL https://tailscale.com/install.sh | TAILSCALE_VERSION=1.88.4 sh
-# curl -fsSL https://tailscale.com/install.sh | TRACK=unstable sh
-
-set -eu
-
-# All the code is wrapped in a main function that gets called at the
-# bottom of the file, so that a truncated partial download doesn't end
-# up executing half a script.
-main() {
- # Step 1: detect the current linux distro, version, and packaging system.
- #
- # We rely on a combination of 'uname' and /etc/os-release to find
- # an OS name and version, and from there work out what
- # installation method we should be using.
- #
- # The end result of this step is that the following three
- # variables are populated, if detection was successful.
- OS=""
- VERSION=""
- PACKAGETYPE=""
- APT_KEY_TYPE="" # Only for apt-based distros
- APT_SYSTEMCTL_START=false # Only needs to be true for Kali
- TRACK="${TRACK:-stable}"
- TAILSCALE_VERSION="${TAILSCALE_VERSION:-}"
-
- case "$TRACK" in
- stable|unstable)
- ;;
- *)
- echo "unsupported track $TRACK"
- exit 1
- ;;
- esac
-
- if [ -f /etc/os-release ]; then
- # /etc/os-release populates a number of shell variables. We care about the following:
- # - ID: the short name of the OS (e.g. "debian", "freebsd")
- # - VERSION_ID: the numeric release version for the OS, if any (e.g. "18.04")
- # - VERSION_CODENAME: the codename of the OS release, if any (e.g. "buster")
- # - UBUNTU_CODENAME: if it exists, use instead of VERSION_CODENAME
- . /etc/os-release
- VERSION_MAJOR="${VERSION_ID:-}"
- VERSION_MAJOR="${VERSION_MAJOR%%.*}"
- case "$ID" in
- ubuntu|pop|neon|zorin|tuxedo)
- OS="ubuntu"
- if [ "${UBUNTU_CODENAME:-}" != "" ]; then
- VERSION="$UBUNTU_CODENAME"
- else
- VERSION="$VERSION_CODENAME"
- fi
- PACKAGETYPE="apt"
- # Third-party keyrings became the preferred method of
- # installation in Ubuntu 20.04.
- if [ "$VERSION_MAJOR" -lt 20 ]; then
- APT_KEY_TYPE="legacy"
- else
- APT_KEY_TYPE="keyring"
- fi
- ;;
- debian)
- OS="$ID"
- VERSION="$VERSION_CODENAME"
- PACKAGETYPE="apt"
- # Third-party keyrings became the preferred method of
- # installation in Debian 11 (Bullseye).
- if [ -z "${VERSION_ID:-}" ]; then
- # rolling release. If you haven't kept current, that's on you.
- APT_KEY_TYPE="keyring"
- # Parrot Security is a special case that uses ID=debian
- elif [ "$NAME" = "Parrot Security" ]; then
- # All versions new enough to have this behaviour prefer keyring
- # and their VERSION_ID is not consistent with Debian.
- APT_KEY_TYPE="keyring"
- # They don't specify the Debian version they're based off in os-release
- # but Parrot 6 is based on Debian 12 Bookworm.
- VERSION=bookworm
- elif [ "$VERSION_MAJOR" -lt 11 ]; then
- APT_KEY_TYPE="legacy"
- else
- APT_KEY_TYPE="keyring"
- fi
- ;;
- linuxmint)
- if [ "${UBUNTU_CODENAME:-}" != "" ]; then
- OS="ubuntu"
- VERSION="$UBUNTU_CODENAME"
- elif [ "${DEBIAN_CODENAME:-}" != "" ]; then
- OS="debian"
- VERSION="$DEBIAN_CODENAME"
- else
- OS="ubuntu"
- VERSION="$VERSION_CODENAME"
- fi
- PACKAGETYPE="apt"
- if [ "$VERSION_MAJOR" -lt 5 ]; then
- APT_KEY_TYPE="legacy"
- else
- APT_KEY_TYPE="keyring"
- fi
- ;;
- elementary)
- OS="ubuntu"
- VERSION="$UBUNTU_CODENAME"
- PACKAGETYPE="apt"
- if [ "$VERSION_MAJOR" -lt 6 ]; then
- APT_KEY_TYPE="legacy"
- else
- APT_KEY_TYPE="keyring"
- fi
- ;;
- industrial-os)
- OS="debian"
- PACKAGETYPE="apt"
- if [ "$VERSION_MAJOR" -lt 5 ]; then
- VERSION="buster"
- APT_KEY_TYPE="legacy"
- else
- VERSION="bullseye"
- APT_KEY_TYPE="keyring"
- fi
- ;;
- parrot|mendel)
- OS="debian"
- PACKAGETYPE="apt"
- if [ "$VERSION_MAJOR" -lt 5 ]; then
- VERSION="buster"
- APT_KEY_TYPE="legacy"
- else
- VERSION="bullseye"
- APT_KEY_TYPE="keyring"
- fi
- ;;
- galliumos)
- OS="ubuntu"
- PACKAGETYPE="apt"
- VERSION="bionic"
- APT_KEY_TYPE="legacy"
- ;;
- pureos|kaisen)
- OS="debian"
- PACKAGETYPE="apt"
- VERSION="bullseye"
- APT_KEY_TYPE="keyring"
- ;;
- raspbian)
- OS="$ID"
- VERSION="$VERSION_CODENAME"
- PACKAGETYPE="apt"
- # Third-party keyrings became the preferred method of
- # installation in Raspbian 11 (Bullseye).
- if [ "$VERSION_MAJOR" -lt 11 ]; then
- APT_KEY_TYPE="legacy"
- else
- APT_KEY_TYPE="keyring"
- fi
- ;;
- kali)
- OS="debian"
- PACKAGETYPE="apt"
- APT_SYSTEMCTL_START=true
- # Third-party keyrings became the preferred method of
- # installation in Debian 11 (Bullseye), which Kali switched
- # to in roughly 2021.x releases
- if [ "$VERSION_MAJOR" -lt 2021 ]; then
- # Kali VERSION_ID is "kali-rolling", which isn't distinguishing
- VERSION="buster"
- APT_KEY_TYPE="legacy"
- else
- VERSION="bullseye"
- APT_KEY_TYPE="keyring"
- fi
- ;;
- Deepin|deepin) # https://github.com/tailscale/tailscale/issues/7862
- OS="debian"
- PACKAGETYPE="apt"
- if [ "$VERSION_MAJOR" -lt 20 ]; then
- APT_KEY_TYPE="legacy"
- VERSION="buster"
- else
- APT_KEY_TYPE="keyring"
- VERSION="bullseye"
- fi
- ;;
- pika)
- PACKAGETYPE="apt"
- # All versions of PikaOS are new enough to prefer keyring
- APT_KEY_TYPE="keyring"
- # Older versions of PikaOS are based on Ubuntu rather than Debian
- if [ "$VERSION_MAJOR" -lt 4 ]; then
- OS="ubuntu"
- VERSION="$UBUNTU_CODENAME"
- else
- OS="debian"
- VERSION="$DEBIAN_CODENAME"
- fi
- ;;
- sparky)
- OS="debian"
- PACKAGETYPE="apt"
- VERSION="$DEBIAN_CODENAME"
- APT_KEY_TYPE="keyring"
- ;;
- centos)
- OS="$ID"
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="dnf"
- if [ "$VERSION" = "7" ]; then
- PACKAGETYPE="yum"
- fi
- ;;
- ol)
- OS="oracle"
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="dnf"
- if [ "$VERSION" = "7" ]; then
- PACKAGETYPE="yum"
- fi
- ;;
- rhel|miraclelinux)
- OS="$ID"
- if [ "$ID" = "miraclelinux" ]; then
- OS="rhel"
- fi
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="dnf"
- if [ "$VERSION" = "7" ]; then
- PACKAGETYPE="yum"
- fi
- ;;
- fedora)
- OS="$ID"
- VERSION=""
- PACKAGETYPE="dnf"
- ;;
- rocky|almalinux|nobara|openmandriva|sangoma|risios|cloudlinux|alinux|fedora-asahi-remix|ultramarine)
- OS="fedora"
- VERSION=""
- PACKAGETYPE="dnf"
- ;;
- amzn)
- OS="amazon-linux"
- VERSION="$VERSION_ID"
- PACKAGETYPE="yum"
- ;;
- xenenterprise)
- OS="centos"
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="yum"
- ;;
- opensuse-leap|sles)
- OS="opensuse"
- VERSION="leap/$VERSION_ID"
- PACKAGETYPE="zypper"
- ;;
- opensuse-tumbleweed)
- OS="opensuse"
- VERSION="tumbleweed"
- PACKAGETYPE="zypper"
- ;;
- sle-micro-rancher)
- OS="opensuse"
- VERSION="leap/15.4"
- PACKAGETYPE="zypper"
- ;;
- arch|archarm|endeavouros|blendos|garuda|archcraft|cachyos)
- OS="arch"
- VERSION="" # rolling release
- PACKAGETYPE="pacman"
- ;;
- manjaro|manjaro-arm|biglinux)
- OS="manjaro"
- VERSION="" # rolling release
- PACKAGETYPE="pacman"
- ;;
- alpine)
- OS="$ID"
- VERSION="$VERSION_ID"
- PACKAGETYPE="apk"
- ;;
- postmarketos)
- OS="alpine"
- VERSION="$VERSION_ID"
- PACKAGETYPE="apk"
- ;;
- nixos)
- echo "Please add Tailscale to your NixOS configuration directly:"
- echo
- echo "services.tailscale.enable = true;"
- exit 1
- ;;
- bazzite)
- echo "Bazzite comes with Tailscale installed by default."
- echo "Please enable Tailscale by running the following commands as root:"
- echo
- echo "ujust enable-tailscale"
- echo "tailscale up"
- exit 1
- ;;
- void)
- OS="$ID"
- VERSION="" # rolling release
- PACKAGETYPE="xbps"
- ;;
- gentoo)
- OS="$ID"
- VERSION="" # rolling release
- PACKAGETYPE="emerge"
- ;;
- freebsd)
- OS="$ID"
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="pkg"
- ;;
- osmc)
- OS="debian"
- PACKAGETYPE="apt"
- VERSION="bullseye"
- APT_KEY_TYPE="keyring"
- ;;
- photon)
- OS="photon"
- VERSION="$VERSION_MAJOR"
- PACKAGETYPE="tdnf"
- ;;
- steamos)
- echo "To install Tailscale on SteamOS, please follow the instructions here:"
- echo "https://github.com/tailscale-dev/deck-tailscale"
- exit 1
- ;;
-
- # TODO: wsl?
- # TODO: synology? qnap?
- esac
- fi
-
- # If we failed to detect something through os-release, consult
- # uname and try to infer things from that.
- if [ -z "$OS" ]; then
- if type uname >/dev/null 2>&1; then
- case "$(uname)" in
- FreeBSD)
- # FreeBSD before 12.2 doesn't have
- # /etc/os-release, so we wouldn't have found it in
- # the os-release probing above.
- OS="freebsd"
- VERSION="$(freebsd-version | cut -f1 -d.)"
- PACKAGETYPE="pkg"
- ;;
- OpenBSD)
- OS="openbsd"
- VERSION="$(uname -r)"
- PACKAGETYPE=""
- ;;
- Darwin)
- OS="macos"
- VERSION="$(sw_vers -productVersion | cut -f1-2 -d.)"
- PACKAGETYPE="appstore"
- ;;
- Linux)
- OS="other-linux"
- VERSION=""
- PACKAGETYPE=""
- ;;
- esac
- fi
- fi
-
- # Ideally we want to use curl, but on some installs we
- # only have wget. Detect and use what's available.
- CURL=
- if type curl >/dev/null; then
- CURL="curl -fsSL"
- elif type wget >/dev/null; then
- CURL="wget -q -O-"
- fi
- if [ -z "$CURL" ]; then
- echo "The installer needs either curl or wget to download files."
- echo "Please install either curl or wget to proceed."
- exit 1
- fi
-
- TEST_URL="https://pkgs.tailscale.com/"
- RC=0
- TEST_OUT=$($CURL "$TEST_URL" 2>&1) || RC=$?
- if [ $RC != 0 ]; then
- echo "The installer cannot reach $TEST_URL"
- echo "Please make sure that your machine has internet access."
- echo "Test output:"
- echo $TEST_OUT
- exit 1
- fi
-
- # Step 2: having detected an OS we support, is it one of the
- # versions we support?
- OS_UNSUPPORTED=
- case "$OS" in
- ubuntu|debian|raspbian|centos|oracle|rhel|amazon-linux|opensuse|photon)
- # Check with the package server whether a given version is supported.
- URL="https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/installer-supported"
- $CURL "$URL" 2> /dev/null | grep -q OK || OS_UNSUPPORTED=1
- ;;
- fedora)
- # All versions supported, no version checking required.
- ;;
- arch)
- # Rolling release, no version checking needed.
- ;;
- manjaro)
- # Rolling release, no version checking needed.
- ;;
- alpine)
- # All versions supported, no version checking needed.
- # TODO: is that true? When was tailscale packaged?
- ;;
- void)
- # Rolling release, no version checking needed.
- ;;
- gentoo)
- # Rolling release, no version checking needed.
- ;;
- freebsd)
- if [ "$VERSION" != "12" ] && \
- [ "$VERSION" != "13" ] && \
- [ "$VERSION" != "14" ] && \
- [ "$VERSION" != "15" ]
- then
- OS_UNSUPPORTED=1
- fi
- ;;
- openbsd)
- OS_UNSUPPORTED=1
- ;;
- macos)
- # We delegate macOS installation to the app store, it will
- # perform version checks for us.
- ;;
- other-linux)
- OS_UNSUPPORTED=1
- ;;
- *)
- OS_UNSUPPORTED=1
- ;;
- esac
- if [ "$OS_UNSUPPORTED" = "1" ]; then
- case "$OS" in
- other-linux)
- echo "Couldn't determine what kind of Linux is running."
- echo "You could try the static binaries at:"
- echo "https://pkgs.tailscale.com/$TRACK/#static"
- ;;
- "")
- echo "Couldn't determine what operating system you're running."
- ;;
- *)
- echo "$OS $VERSION isn't supported by this script yet."
- ;;
- esac
- echo
- echo "If you'd like us to support your system better, please email support@tailscale.com"
- echo "and tell us what OS you're running."
- echo
- echo "Please include the following information we gathered from your system:"
- echo
- echo "OS=$OS"
- echo "VERSION=$VERSION"
- echo "PACKAGETYPE=$PACKAGETYPE"
- if type uname >/dev/null 2>&1; then
- echo "UNAME=$(uname -a)"
- else
- echo "UNAME="
- fi
- echo
- if [ -f /etc/os-release ]; then
- cat /etc/os-release
- else
- echo "No /etc/os-release"
- fi
- exit 1
- fi
-
- # Step 3: work out if we can run privileged commands, and if so,
- # how.
- CAN_ROOT=
- SUDO=
- if [ "$(id -u)" = 0 ]; then
- CAN_ROOT=1
- SUDO=""
- elif type sudo >/dev/null; then
- CAN_ROOT=1
- SUDO="sudo"
- elif type doas >/dev/null; then
- CAN_ROOT=1
- SUDO="doas"
- fi
- if [ "$CAN_ROOT" != "1" ]; then
- echo "This installer needs to run commands as root."
- echo "We tried looking for 'sudo' and 'doas', but couldn't find them."
- echo "Either re-run this script as root, or set up sudo/doas."
- exit 1
- fi
-
-
- # Step 4: run the installation.
- OSVERSION="$OS"
- [ "$VERSION" != "" ] && OSVERSION="$OSVERSION $VERSION"
-
- # Prepare package name with optional version
- PACKAGE_NAME="tailscale"
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Installing Tailscale $TAILSCALE_VERSION for $OSVERSION, using method $PACKAGETYPE"
- else
- echo "Installing Tailscale for $OSVERSION, using method $PACKAGETYPE"
- fi
- case "$PACKAGETYPE" in
- apt)
- export DEBIAN_FRONTEND=noninteractive
- if [ "$APT_KEY_TYPE" = "legacy" ] && ! type gpg >/dev/null; then
- $SUDO apt-get update
- $SUDO apt-get install -y gnupg
- fi
-
- set -x
- $SUDO mkdir -p --mode=0755 /usr/share/keyrings
- case "$APT_KEY_TYPE" in
- legacy)
- $CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.asc" | $SUDO apt-key add -
- $CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list
- $SUDO chmod 0644 /etc/apt/sources.list.d/tailscale.list
- ;;
- keyring)
- $CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.noarmor.gpg" | $SUDO tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
- $SUDO chmod 0644 /usr/share/keyrings/tailscale-archive-keyring.gpg
- $CURL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION.tailscale-keyring.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list
- $SUDO chmod 0644 /etc/apt/sources.list.d/tailscale.list
- ;;
- esac
- $SUDO apt-get update
- if [ -n "$TAILSCALE_VERSION" ]; then
- $SUDO apt-get install -y "tailscale=$TAILSCALE_VERSION" tailscale-archive-keyring
- else
- $SUDO apt-get install -y tailscale tailscale-archive-keyring
- fi
- if [ "$APT_SYSTEMCTL_START" = "true" ]; then
- $SUDO systemctl enable --now tailscaled
- $SUDO systemctl start tailscaled
- fi
- set +x
- ;;
- yum)
- set -x
- $SUDO yum install yum-utils -y
- $SUDO yum-config-manager -y --add-repo "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
- if [ -n "$TAILSCALE_VERSION" ]; then
- $SUDO yum install "tailscale-$TAILSCALE_VERSION" -y
- else
- $SUDO yum install tailscale -y
- fi
- $SUDO systemctl enable --now tailscaled
- set +x
- ;;
- dnf)
- # DNF 5 has a different argument format; determine which one we have.
- DNF_VERSION="3"
- if LANG=C.UTF-8 dnf --version | grep -q '^dnf5 version'; then
- DNF_VERSION="5"
- fi
-
- # The 'config-manager' plugin wasn't implemented when
- # DNF5 was released; detect that and use the old
- # version if necessary.
- if [ "$DNF_VERSION" = "5" ]; then
- set -x
- $SUDO dnf install -y 'dnf-command(config-manager)' && DNF_HAVE_CONFIG_MANAGER=1 || DNF_HAVE_CONFIG_MANAGER=0
- set +x
-
- if [ "$DNF_HAVE_CONFIG_MANAGER" != "1" ]; then
- if type dnf-3 >/dev/null; then
- DNF_VERSION="3"
- else
- echo "dnf 5 detected, but 'dnf-command(config-manager)' not available and dnf-3 not found"
- exit 1
- fi
- fi
- fi
-
- set -x
- if [ "$DNF_VERSION" = "3" ]; then
- $SUDO dnf install -y 'dnf-command(config-manager)'
- $SUDO dnf config-manager --add-repo "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
- elif [ "$DNF_VERSION" = "5" ]; then
- # Already installed config-manager, above.
- $SUDO dnf config-manager addrepo --overwrite --from-repofile="https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
- else
- echo "unexpected: unknown dnf version $DNF_VERSION"
- exit 1
- fi
- if [ -n "$TAILSCALE_VERSION" ]; then
- $SUDO dnf install -y "tailscale-$TAILSCALE_VERSION"
- else
- $SUDO dnf install -y tailscale
- fi
- $SUDO systemctl enable --now tailscaled
- set +x
- ;;
- tdnf)
- set -x
- curl -fsSL "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo" > /etc/yum.repos.d/tailscale.repo
- if [ -n "$TAILSCALE_VERSION" ]; then
- $SUDO tdnf install -y "tailscale-$TAILSCALE_VERSION"
- else
- $SUDO tdnf install -y tailscale
- fi
- $SUDO systemctl enable --now tailscaled
- set +x
- ;;
- zypper)
- set -x
- $SUDO rpm --import "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/repo.gpg"
- $SUDO zypper --non-interactive ar -g -r "https://pkgs.tailscale.com/$TRACK/$OS/$VERSION/tailscale.repo"
- $SUDO zypper --non-interactive --gpg-auto-import-keys refresh
- if [ -n "$TAILSCALE_VERSION" ]; then
- $SUDO zypper --non-interactive install "tailscale=$TAILSCALE_VERSION"
- else
- $SUDO zypper --non-interactive install tailscale
- fi
- $SUDO systemctl enable --now tailscaled
- set +x
- ;;
- pacman)
- set -x
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Warning: Arch Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
- $SUDO pacman -S "tailscale=$TAILSCALE_VERSION" --noconfirm
- else
- $SUDO pacman -S tailscale --noconfirm
- fi
- $SUDO systemctl enable --now tailscaled
- set +x
- ;;
- pkg)
- set -x
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Warning: FreeBSD maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
- $SUDO pkg install --yes "tailscale-$TAILSCALE_VERSION"
- else
- $SUDO pkg install --yes tailscale
- fi
- $SUDO service tailscaled enable
- $SUDO service tailscaled start
- set +x
- ;;
- apk)
- set -x
- if ! grep -Eq '^http.*/community$' /etc/apk/repositories; then
- if type setup-apkrepos >/dev/null; then
- $SUDO setup-apkrepos -c -1
- else
- echo "installing tailscale requires the community repo to be enabled in /etc/apk/repositories"
- exit 1
- fi
- fi
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Warning: Alpine Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
- $SUDO apk add "tailscale=$TAILSCALE_VERSION"
- else
- $SUDO apk add tailscale
- fi
- $SUDO rc-update add tailscale
- $SUDO rc-service tailscale start
- set +x
- ;;
- xbps)
- set -x
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Warning: Void Linux maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
- $SUDO xbps-install "tailscale-$TAILSCALE_VERSION" -y
- else
- $SUDO xbps-install tailscale -y
- fi
- set +x
- ;;
- emerge)
- set -x
- if [ -n "$TAILSCALE_VERSION" ]; then
- echo "Warning: Gentoo maintains their own Tailscale package. Version pinning may not work as expected, as the target version may no longer be available."
- $SUDO emerge --ask=n "=net-vpn/tailscale-$TAILSCALE_VERSION"
- else
- $SUDO emerge --ask=n net-vpn/tailscale
- fi
- set +x
- ;;
- appstore)
- set -x
- open "https://apps.apple.com/us/app/tailscale/id1475387142"
- set +x
- ;;
- *)
- echo "unexpected: unknown package type $PACKAGETYPE"
- exit 1
- ;;
- esac
-
- echo "Installation complete! Log in to start using Tailscale by running:"
- echo
- if [ -z "$SUDO" ]; then
- echo "tailscale up"
- else
- echo "$SUDO tailscale up"
- fi
-}
-
-main
diff --git a/debian/13-trixie-luks/variables-common.pkr.hcl b/debian/13-trixie-luks/variables-common.pkr.hcl
deleted file mode 120000
index f97f3d6..0000000
--- a/debian/13-trixie-luks/variables-common.pkr.hcl
+++ /dev/null
@@ -1 +0,0 @@
-../../variables-common.pkr.hcl
\ No newline at end of file
diff --git a/debian/13-trixie-luks/variables.pkr.hcl b/debian/13-trixie-luks/variables.pkr.hcl
deleted file mode 100644
index 346e5c3..0000000
--- a/debian/13-trixie-luks/variables.pkr.hcl
+++ /dev/null
@@ -1,67 +0,0 @@
-# Variables
-variable "template_vm_id" {
- type = string
- default = "65000"
- description = "The VM ID of the Proxmox template to use for building the image"
-}
-
-variable "mac_address" {
- type = string
- default = "BC:24:11:00:13:37"
- description = "The MAC address to assign to the VM's network adapter"
-}
-
-variable "iso_url" {
- type = string
- default = "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.3.0-amd64-netinst.iso"
- description = "The URL to download the Debian 13 Trixie ISO"
-}
-
-variable "iso_checksum" {
- type = string
- default = "file:https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS"
- description = "ISO checksum (SHA256 or checksum file URL)"
-}
-
-variable "disk_storage_pool" {
- type = string
- default = "ceph-pool"
- description = "The Proxmox storage pool to use for the VM disk"
-}
-
-variable "iso_storage_pool" {
- type = string
- default = "cephfs"
- description = "The Proxmox storage pool to use for the ISO"
-}
-
-variable "template_cpu_type" {
- type = string
- default = "host"
- description = "The CPU type for the Proxmox template"
-}
-
-variable "network_bridge" {
- type = string
- default = "vmbr9"
- description = "The network bridge to attach the VM to"
-}
-
-variable "proxmox_node" {
- type = string
- default = "sbx0pve02"
- description = "The Proxmox node to use for building the image"
-}
-
-variable "install_finished_inform_port" {
- type = string
- default = "10000"
- description = "The server port to inform when installation is finished"
-}
-
-
-
-# local values
-local "timestamp" {
- expression = formatdate("YYYYMMDD-hhMMss-ZZZ", timestamp())
-}
diff --git a/debian/13-trixie/debian-trixie.pkr.hcl b/debian/13-trixie/debian-trixie.pkr.hcl
index 0e278b8..8109b80 100644
--- a/debian/13-trixie/debian-trixie.pkr.hcl
+++ b/debian/13-trixie/debian-trixie.pkr.hcl
@@ -7,6 +7,20 @@ packer {
}
}
+locals {
+ image_slug = var.enable_luks ? "debian-13-trixie-luks" : "debian-13-trixie"
+ template_description = var.enable_luks ? "Debian 13 Trixie, LUKS encrypted, built with Packer on ${local.timestamp}\n\nLUKS default passphrase: `${var.default_luks_passphrase}`" : "Debian 13 Trixie, built with Packer on ${local.timestamp}"
+ luks_boot_args = var.enable_luks ? [
+ "partman-crypto/passphrase='${var.default_luks_passphrase}' ",
+ "partman-crypto/passphrase-again='${var.default_luks_passphrase}' ",
+ "INSTALL_FINISHED_INFORM_URL='http://{{ .HTTPIP }}:${var.install_finished_inform_port}/install_finished' ",
+ ] : []
+ clevis_install_commands = var.enable_luks ? [
+ "apt-get update",
+ "apt-get install -y clevis clevis-luks clevis-initramfs",
+ ] : ["true"]
+}
+
source "proxmox-iso" "debian-13-trixie" {
# Proxmox Connection Settings
proxmox_url = "${var.proxmox_api_url}"
@@ -19,8 +33,8 @@ source "proxmox-iso" "debian-13-trixie" {
# VM General Settings
node = "${var.proxmox_node}"
vm_id = "${var.template_vm_id}"
- vm_name = "debian-13-trixie-${local.timestamp}"
- template_description = "Debian 13 Trixie, built with Packer on ${local.timestamp}"
+ vm_name = "${local.image_slug}-${local.timestamp}"
+ template_description = "${local.template_description}"
os = "l26"
qemu_agent = true
@@ -78,42 +92,26 @@ source "proxmox-iso" "debian-13-trixie" {
boot = "order=scsi0;scsi1"
boot_wait = "10s"
communicator = "ssh"
- boot_command = [
+ boot_command = concat([
"c",
"linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
"DEBIAN_FRONTEND=text ",
"console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
"passwd/root-password='${var.default_root_passphrase}' ",
"passwd/root-password-again='${var.default_root_passphrase}' ",
+ ], local.luks_boot_args, [
"preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg noprompt",
"initrd /install.amd/initrd.gz",
"DEBCONF_DEBUG=5",
- "boot"
- ]
- # Static IP
- # boot_command = [
- # "c",
- # "linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
- # "DEBIAN_FRONTEND=text ",
- # "console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
- # "passwd/root-password='${var.default_root_passphrase}' ",
- # "passwd/root-password-again='${var.default_root_passphrase}' ",
- # "netcfg/disable_autoconfig=true ",
- # "netcfg/get_ipaddress=172.16.2.254 ",
- # "netcfg/get_netmask=255.255.255.0 ",
- # "netcfg/get_gateway=172.16.2.3 ",
- # "netcfg/get_nameservers=172.16.2.3 ",
- # "netcfg/confirm_static=true ",
- # "netcfg/get_hostname=debian-installer ",
- # "netcfg/get_domain=local ",
- # "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg noprompt",
- # "initrd /install.amd/initrd.gz",
- # "DEBCONF_DEBUG=5",
- # "boot"
- # ]
+ "boot",
+ ])
# PACKER Autoinstall Settings
- http_directory = "debian/13-trixie/http"
+ http_content = {
+ "/preseed.cfg" = templatefile("${abspath(path.root)}/http/preseed.cfg.pkrtpl", {
+ enable_luks = var.enable_luks
+ })
+ }
http_interface = "${var.source_proxmox_http_interface}"
# SSH Settings
@@ -124,7 +122,7 @@ source "proxmox-iso" "debian-13-trixie" {
}
build {
- name = "debian-13-trixie-image"
+ name = "${local.image_slug}-image"
sources = ["source.proxmox-iso.debian-13-trixie"]
# Install dependencies and default packages
@@ -197,6 +195,11 @@ build {
]
}
+ # Install Clevis for LUKS builds
+ provisioner "shell" {
+ inline = local.clevis_install_commands
+ }
+
# Setup Serial Console for xterm.js in Proxmox VE
provisioner "shell" {
inline = [
diff --git a/debian/13-trixie/files/initial-setup.sh b/debian/13-trixie/files/initial-setup.sh
index b78d695..acd62f6 100644
--- a/debian/13-trixie/files/initial-setup.sh
+++ b/debian/13-trixie/files/initial-setup.sh
@@ -5,12 +5,18 @@ IFS=$'\n\t'
SCRIPT_NAME="$(basename "$0")"
TASK_INDEX=0
TASK_TOTAL=0
+TEMP_FILES=()
STORAGE_DETECTED=0
+STORAGE_MODE=""
ROOT_SOURCE=""
VG_NAME=""
LV_NAME=""
PV_NAME=""
+LUKS_DEV=""
+LUKS_NAME=""
+LUKS_PART=""
+RESIZE_PART=""
DISK_DEV=""
PART_NUM=""
@@ -56,6 +62,18 @@ section() {
echo "${DIM}------------------------------------------------------------${RESET}"
}
+add_temp_file() {
+ TEMP_FILES+=("$1")
+}
+
+cleanup() {
+ local file
+ for file in "${TEMP_FILES[@]:-}"; do
+ [ -f "$file" ] && rm -f "$file"
+ done
+}
+trap cleanup EXIT
+
ensure_tty() {
if [ ! -t 0 ] || [ ! -t 1 ]; then
die "This setup must run interactively in a TTY."
@@ -227,6 +245,29 @@ infer_disk_part_from_partition() {
return 1
}
+resolve_luks_backing_partition() {
+ local mapper_path="$1"
+ local mapper_name="$2"
+ local mapper_name_alt="$3"
+ local part=""
+
+ if command -v cryptsetup >/dev/null 2>&1; then
+ part="$(cryptsetup status "$mapper_name" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
+ if [ -z "$part" ] && [ -n "$mapper_name_alt" ] && [ "$mapper_name_alt" != "$mapper_name" ]; then
+ part="$(cryptsetup status "$mapper_name_alt" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
+ fi
+ if [ -z "$part" ]; then
+ part="$(cryptsetup status "$mapper_path" 2>/dev/null | awk '/^[[:space:]]*device:/ {print $2; exit}' | xargs || true)"
+ fi
+ fi
+
+ if [ -z "$part" ]; then
+ part="$(lsblk -nro PATH,TYPE -s "$mapper_path" 2>/dev/null | awk '$2=="part" {print $1; exit}' | xargs || true)"
+ fi
+
+ printf '%s' "$part"
+}
+
refresh_partition_table() {
local disk="$1"
if command -v partprobe >/dev/null 2>&1; then
@@ -324,8 +365,20 @@ show_disk_layout() {
fi
}
+resize_open_luks_mapping() {
+ if [ -n "$LUKS_NAME" ] && cryptsetup resize "$LUKS_NAME" >/dev/null 2>&1; then
+ return 0
+ fi
+ cryptsetup resize "$LUKS_DEV" >/dev/null 2>&1
+}
+
detect_storage_stack() {
STORAGE_DETECTED=0
+ STORAGE_MODE=""
+ LUKS_DEV=""
+ LUKS_NAME=""
+ LUKS_PART=""
+ RESIZE_PART=""
DISK_DEV=""
PART_NUM=""
@@ -358,10 +411,29 @@ detect_storage_stack() {
return 1
fi
+ local pv_type
+ pv_type="$(lsblk_attr "$PV_NAME" TYPE)"
+ if [ "$pv_type" = "crypt" ]; then
+ STORAGE_MODE="luks_lvm"
+ LUKS_DEV="$PV_NAME"
+ LUKS_NAME="$(basename "$LUKS_DEV")"
+ local mapper_name_alt
+ mapper_name_alt="$(lsblk_attr "$LUKS_DEV" NAME)"
+ LUKS_PART="$(resolve_luks_backing_partition "$LUKS_DEV" "$LUKS_NAME" "$mapper_name_alt")"
+ if [ -z "$LUKS_PART" ] || [ ! -b "$LUKS_PART" ]; then
+ log_warn "Unable to detect LUKS backing partition."
+ return 1
+ fi
+ RESIZE_PART="$LUKS_PART"
+ else
+ STORAGE_MODE="lvm"
+ RESIZE_PART="$PV_NAME"
+ fi
+
local inferred
local inferred_disk=""
local inferred_part=""
- inferred="$(infer_disk_part_from_partition "$PV_NAME" || true)"
+ inferred="$(infer_disk_part_from_partition "$RESIZE_PART" || true)"
if [ -n "$inferred" ]; then
inferred_disk="$(printf '%s\n' "$inferred" | sed -n '1p')"
inferred_part="$(printf '%s\n' "$inferred" | sed -n '2p')"
@@ -372,21 +444,21 @@ detect_storage_stack() {
if [ -z "$DISK_DEV" ]; then
local disk_parent
- disk_parent="$(lsblk_attr "$PV_NAME" PKNAME)"
+ disk_parent="$(lsblk_attr "$RESIZE_PART" PKNAME)"
if [ -n "$disk_parent" ]; then
DISK_DEV="/dev/${disk_parent}"
else
- DISK_DEV="$(lsblk -nro PATH,TYPE -s "$PV_NAME" 2>/dev/null | awk '$2=="disk" {print $1; exit}' | xargs || true)"
+ DISK_DEV="$(lsblk -nro PATH,TYPE -s "$RESIZE_PART" 2>/dev/null | awk '$2=="disk" {print $1; exit}' | xargs || true)"
fi
fi
if [ -z "$PART_NUM" ]; then
- PART_NUM="$(lsblk_attr "$PV_NAME" PARTNUM)"
+ PART_NUM="$(lsblk_attr "$RESIZE_PART" PARTNUM)"
fi
if [ -z "$DISK_DEV" ] || [ ! -b "$DISK_DEV" ] || [ -z "$PART_NUM" ] || ! [[ "$PART_NUM" =~ ^[0-9]+$ ]]; then
log_warn "Unable to detect disk device or partition number."
- log_warn "Detected values: PV_NAME=${PV_NAME:-} DISK_DEV=${DISK_DEV:-} PART_NUM=${PART_NUM:-}"
+ log_warn "Detected values: RESIZE_PART=${RESIZE_PART:-} DISK_DEV=${DISK_DEV:-} PART_NUM=${PART_NUM:-}"
return 1
fi
@@ -394,7 +466,7 @@ detect_storage_stack() {
return 0
}
-resize_lvm() {
+resize_lvm_storage() {
if [ "$STORAGE_DETECTED" -ne 1 ]; then
log_warn "Storage layout not detected; skipping resize."
return 0
@@ -402,12 +474,21 @@ resize_lvm() {
require_cmd parted || return 0
require_cmd blockdev || return 0
+ if [ "$STORAGE_MODE" = "luks_lvm" ]; then
+ require_cmd cryptsetup || return 0
+ fi
require_cmd pvresize || return 0
require_cmd lvextend || return 0
log_info "Root LV: ${ROOT_SOURCE}"
log_info "VG: ${VG_NAME} | LV: ${LV_NAME}"
+ log_info "Storage mode: ${STORAGE_MODE}"
log_info "LVM PV: ${PV_NAME}"
+ if [ "$STORAGE_MODE" = "luks_lvm" ]; then
+ log_info "LUKS device: ${LUKS_DEV}"
+ log_info "LUKS partition: ${LUKS_PART}"
+ [ -n "$LUKS_NAME" ] && log_info "LUKS mapper name: ${LUKS_NAME}"
+ fi
log_info "Disk: ${DISK_DEV} | Partition number: ${PART_NUM}"
if ! repair_gpt_backup_header "$DISK_DEV"; then
@@ -422,7 +503,7 @@ resize_lvm() {
local part_size_before
local free_bytes
- part_size_before="$(blockdev --getsize64 "$PV_NAME" 2>/dev/null || echo 0)"
+ part_size_before="$(blockdev --getsize64 "$RESIZE_PART" 2>/dev/null || echo 0)"
free_bytes="$(get_trailing_free_bytes "$DISK_DEV" "$PART_NUM" || true)"
if [ -z "$free_bytes" ]; then
log_warn "Unable to determine free disk space."
@@ -436,22 +517,36 @@ resize_lvm() {
log_info "Unallocated space available: $(human_bytes "$free_bytes")"
show_disk_layout "$DISK_DEV"
- if ! confirm "Extend partition, VG, and root LV now?" "yes"; then
+ local resize_prompt
+ if [ "$STORAGE_MODE" = "luks_lvm" ]; then
+ resize_prompt="Extend partition, LUKS device, VG, and root LV now?"
+ else
+ resize_prompt="Extend partition, VG, and root LV now?"
+ fi
+ if ! confirm "$resize_prompt" "yes"; then
log_warn "Skipped resize."
return 0
fi
- log_info "Extending partition ${PV_NAME} to 100% of disk..."
+ log_info "Extending partition ${RESIZE_PART} to 100% of disk..."
if ! parted -s "$DISK_DEV" resizepart "$PART_NUM" 100%; then
log_warn "Partition resize failed."
return 0
fi
refresh_partition_table "$DISK_DEV"
- if [ "$part_size_before" -gt 0 ] && ! wait_for_partition_growth "$PV_NAME" "$part_size_before"; then
+ if [ "$part_size_before" -gt 0 ] && ! wait_for_partition_growth "$RESIZE_PART" "$part_size_before"; then
log_warn "Kernel has not reported the new partition size yet; continuing anyway."
fi
+ if [ "$STORAGE_MODE" = "luks_lvm" ]; then
+ log_info "Resizing LUKS device..."
+ if ! resize_open_luks_mapping; then
+ log_warn "LUKS resize failed."
+ return 0
+ fi
+ fi
+
log_info "Resizing LVM physical volume..."
if ! pvresize "$PV_NAME"; then
log_warn "pvresize failed."
@@ -549,6 +644,62 @@ setup_swap() {
log_ok "Swap enabled."
}
+change_luks_passphrase() {
+ if [ "$STORAGE_MODE" != "luks_lvm" ]; then
+ log_info "Root storage is not LUKS-backed; skipping LUKS passphrase change."
+ return 0
+ fi
+ if [ -z "$LUKS_PART" ] || [ ! -e "$LUKS_PART" ]; then
+ log_warn "LUKS partition not found; skipping."
+ return 0
+ fi
+ require_cmd cryptsetup || return 0
+
+ if ! confirm "Change LUKS passphrase in slot 0 now?" "yes"; then
+ log_warn "Skipped LUKS passphrase change."
+ return 0
+ fi
+
+ local old_pass
+ local new_pass
+ local tmp_old
+ local tmp_new
+
+ old_pass="$(prompt_secret "Enter current LUKS passphrase")"
+ new_pass="$(prompt_secret_confirm "Enter new LUKS passphrase" "Confirm new LUKS passphrase")"
+
+ tmp_old="$(mktemp)"
+ tmp_new="$(mktemp)"
+ add_temp_file "$tmp_old"
+ add_temp_file "$tmp_new"
+
+ printf '%s' "$old_pass" >"$tmp_old"
+ printf '%s' "$new_pass" >"$tmp_new"
+
+ log_info "Updating LUKS passphrase in slot 0..."
+ if cryptsetup luksChangeKey --batch-mode --key-slot 0 --key-file "$tmp_old" "$LUKS_PART" "$tmp_new"; then
+ log_ok "LUKS passphrase updated."
+ else
+ log_warn "Failed to update LUKS passphrase."
+ fi
+}
+
+setup_clevis() {
+ if [ "$STORAGE_MODE" != "luks_lvm" ]; then
+ log_info "Root storage is not LUKS-backed; skipping Clevis/Tang setup."
+ return 0
+ fi
+
+ log_info "Clevis/Tang setup is not implemented in this template yet."
+ if confirm "Would you like to configure Clevis with a Tang server now? (will be skipped)" "no"; then
+ local tang
+ tang="$(prompt_input "Tang server URL" "http://tang.int.r3w.de")"
+ log_warn "Clevis setup for ${tang} is not implemented yet. Skipping."
+ else
+ log_info "Skipping Clevis setup."
+ fi
+}
+
setup_tailscale() {
if ! require_cmd tailscale; then
log_warn "Tailscale is not installed; skipping."
@@ -639,7 +790,7 @@ main() {
welcome
if detect_storage_stack; then
- log_ok "Detected LVM storage layout."
+ log_ok "Detected ${STORAGE_MODE} storage layout."
else
log_warn "Storage layout detection incomplete; some steps may be skipped."
fi
@@ -647,8 +798,12 @@ main() {
TASK_TITLES=()
TASK_FUNCS=()
- add_task "Resize LVM (if free space exists)" resize_lvm
+ add_task "Resize LVM storage (if free space exists)" resize_lvm_storage
add_task "Configure swap file" setup_swap
+ if [ "$STORAGE_MODE" = "luks_lvm" ]; then
+ add_task "Change LUKS passphrase (slot 0)" change_luks_passphrase
+ add_task "Clevis/Tang setup (placeholder)" setup_clevis
+ fi
add_task "Configure Tailscale" setup_tailscale
add_task "Configure CrowdSec" setup_crowdsec
add_task "Reboot recommendation" prompt_reboot
diff --git a/debian/13-trixie/http/preseed.cfg b/debian/13-trixie/http/preseed.cfg
deleted file mode 100644
index 39a08dd..0000000
--- a/debian/13-trixie/http/preseed.cfg
+++ /dev/null
@@ -1,161 +0,0 @@
-#_preseed_V1
-
-### Localization
-d-i debian-installer/locale string en_US.UTF-8
-d-i keyboard-configuration/xkb-keymap select us
-
-### Unattended
-d-i auto-install/enable boolean true
-d-i debconf/priority select critical
-d-i debian-installer/framebuffer boolean false
-
-### Network
-d-i netcfg/choose_interface select ens18
-d-i netcfg/get_hostname string debian-13-template
-d-i netcfg/get_domain string
-d-i netcfg/wireless_wep string
-d-i netcfg/disable_dhcp boolean false
-
-### Root Password (no user)
-d-i passwd/make-user boolean false
-# Root password is set via kernel cmdline in debian-trixie.pkr.hcl; these lines are ignored but left here for reference:
-# d-i passwd/root-password password "$PACKER_ROOT_PASS"
-# d-i passwd/root-password-again password "$PACKER_ROOT_PASS"
-
-### Mirror / APT
-d-i apt-setup/cdrom/set-first boolean false
-d-i apt-setup/cdrom/set-next boolean false
-d-i apt-setup/cdrom/set-failed boolean false
-
-d-i mirror/country string manual
-d-i mirror/http/hostname string ftp.de.debian.org
-d-i mirror/http/directory string /debian
-d-i mirror/http/proxy string
-
-# If you want an explicit suite:
-# d-i mirror/suite string trixie
-
-# Your extra repo line (updated to also include non-free-firmware for trixie)
-d-i apt-setup/local0/repository string http://ftp.de.debian.org/debian/ trixie main contrib non-free non-free-firmware
-popularity-contest popularity-contest/participate boolean false
-
-d-i apt-setup/contrib boolean true
-d-i apt-setup/non-free boolean true
-d-i apt-setup/non-free-firmware boolean true
-d-i apt-setup/security_host string security.debian.org
-d-i apt-setup/services-select multiselect security, updates
-
-### Timezone
-d-i clock-setup/utc boolean true
-d-i time/zone string UTC
-d-i clock-setup/ntp boolean true
-
-### Storage (UEFI + /boot + LUKS/LVM)
-# Pick first detected disk automatically
-d-i preseed/early_command string \
- DISK="$(list-devices disk | head -n1)"; \
- debconf-set partman-auto/disk "$DISK";
-
-# "crypto" = LVM within an encrypted partition [oai_citation:3‡Debian](https://www.debian.org/releases/stable/amd64/apbs04.en.html)
-# "lvm" = LVM without encryption
-d-i partman-auto/method string lvm
-d-i partman-auto-lvm/guided_size string max
-d-i partman-auto-lvm/new_vg_name string vg0
-
-# Cleanup old metadata if present
-d-i partman-lvm/device_remove_lvm boolean true
-d-i partman-md/device_remove_md boolean true
-
-# Confirmations
-d-i partman-lvm/confirm boolean true
-d-i partman-lvm/confirm_nooverwrite boolean true
-d-i partman-md/confirm boolean true
-d-i partman-md/confirm_nooverwrite boolean true
-
-# # LUKS password
-# # LUKS passphrase is set via kernel cmdline in debian-trixie.pkr.hcl; these lines are ignored but left here for reference:
-# # d-i partman-crypto/passphrase password "$PACKER_LUKS_PASS"
-# # d-i partman-crypto/passphrase-again password "$PACKER_LUKS_PASS"
-# d-i partman-crypto/weak_passphrase boolean true
-# d-i partman-crypto/confirm boolean true
-# d-i partman-auto-crypto/erase_disks boolean false
-
-# Ensure GPT
-d-i partman-partitioning/choose_label select gpt
-d-i partman-partitioning/default_label string gpt
-
-# Force UEFI (if needed in your environment)
-d-i partman-efi/non_efi_system boolean true
-
-# Do NOT go back to partitioning menu if a partition/LV has no filesystem
-d-i partman-basicmethods/method_only boolean false
-
-# Accept installing without swap (answer "No" to the warning)
-d-i partman-basicfilesystems/no_swap boolean false
-d-i partman-basicfilesystems/no_swap seen true
-
-# Custom recipe
-# NOTE: Avoid putting comments inside this expert_recipe block; d-i can ignore it. [oai_citation:4‡Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/796185/debian-preseed-install-auto-creates-swap)
-d-i partman-auto/choose_recipe select luks-lvm
-d-i partman-auto/expert_recipe string \
- luks-lvm :: \
- 1075 1075 1075 fat32 \
- $primary{ } \
- $iflabel{ gpt } \
- $reusemethod{ } \
- method{ efi } \
- format{ } \
- filesystem{ fat32 } \
- mountpoint{ /boot/efi } \
- . \
- 1075 1075 1075 ext4 \
- $primary{ } \
- $defaultignore{ } \
- method{ format } \
- format{ } \
- use_filesystem{ } \
- filesystem{ ext4 } \
- mountpoint{ /boot } \
- . \
- 25770 25770 -1 ext4 \
- $lvmok{ } \
- lv_name{ root } \
- method{ format } \
- format{ } \
- use_filesystem{ } \
- filesystem{ ext4 } \
- mountpoint{ / } \
- .
-
-d-i partman-partitioning/confirm_write_new_label boolean true
-d-i partman/choose_partition select finish
-d-i partman/confirm boolean true
-d-i partman/confirm_nooverwrite boolean true
-
-### Software
-d-i debconf/frontend select noninteractive
-tasksel tasksel/first multiselect standard, ssh-server
-
-d-i pkgsel/include string cloud-init curl qemu-guest-agent sudo vim
-d-i pkgsel/upgrade select full-upgrade
-d-i pkgsel/update-policy select none
-d-i pkgsel/updatedb boolean true
-
-### Bootloader
-d-i grub-installer/only_debian boolean true
-d-i grub-installer/with_other_os boolean true
-d-i grub-installer/bootdev string default
-
-### Late command (single declaration; multiple commands chained)
-# 1) Remove filler LV so vg0 has free space after install
-# 2) Enable root ssh login (same intent as your original)
-d-i preseed/late_command string \
- lvremove -f /dev/vg0/reserved || true; \
- in-target sed -i 's/^#PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config || true
-
-# Eject the installation media before rebooting
-d-i cdrom-detect/eject boolean true
-d-i cdrom-detect/eject seen true
-
-### Finish
-d-i finish-install/reboot_in_progress note
diff --git a/debian/13-trixie-luks/http/preseed.cfg b/debian/13-trixie/http/preseed.cfg.pkrtpl
similarity index 94%
rename from debian/13-trixie-luks/http/preseed.cfg
rename to debian/13-trixie/http/preseed.cfg.pkrtpl
index b93751e..ed632f4 100644
--- a/debian/13-trixie-luks/http/preseed.cfg
+++ b/debian/13-trixie/http/preseed.cfg.pkrtpl
@@ -57,7 +57,8 @@ d-i preseed/early_command string \
debconf-set partman-auto/disk "$DISK";
# "crypto" = LVM within an encrypted partition [oai_citation:3‡Debian](https://www.debian.org/releases/stable/amd64/apbs04.en.html)
-d-i partman-auto/method string crypto
+# "lvm" = LVM without encryption
+d-i partman-auto/method string ${enable_luks ? "crypto" : "lvm"}
d-i partman-auto-lvm/guided_size string max
d-i partman-auto-lvm/new_vg_name string vg0
@@ -71,6 +72,7 @@ d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-md/confirm boolean true
d-i partman-md/confirm_nooverwrite boolean true
+%{ if enable_luks ~}
# LUKS password
# LUKS passphrase is set via kernel cmdline in debian-trixie.pkr.hcl; these lines are ignored but left here for reference:
# d-i partman-crypto/passphrase password "$PACKER_LUKS_PASS"
@@ -78,6 +80,7 @@ d-i partman-md/confirm_nooverwrite boolean true
d-i partman-crypto/weak_passphrase boolean true
d-i partman-crypto/confirm boolean true
d-i partman-auto-crypto/erase_disks boolean false
+%{ endif ~}
# Ensure GPT
d-i partman-partitioning/choose_label select gpt
@@ -95,9 +98,9 @@ d-i partman-basicfilesystems/no_swap seen true
# Custom recipe
# NOTE: Avoid putting comments inside this expert_recipe block; d-i can ignore it. [oai_citation:4‡Unix & Linux Stack Exchange](https://unix.stackexchange.com/questions/796185/debian-preseed-install-auto-creates-swap)
-d-i partman-auto/choose_recipe select luks-lvm
+d-i partman-auto/choose_recipe select debian-lvm
d-i partman-auto/expert_recipe string \
- luks-lvm :: \
+ debian-lvm :: \
1075 1075 1075 fat32 \
$primary{ } \
$iflabel{ gpt } \
@@ -150,8 +153,8 @@ d-i grub-installer/bootdev string default
# 2) Enable root ssh login (same intent as your original)
d-i preseed/late_command string \
lvremove -f /dev/vg0/reserved || true; \
- in-target sed -i 's/^#PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config || true; \
- in-target curl -X POST "$INSTALL_FINISHED_INFORM_URL"
+ in-target sed -i 's/^#PermitRootLogin .*/PermitRootLogin yes/' /etc/ssh/sshd_config || true%{ if enable_luks }; \
+ in-target curl -X POST "$INSTALL_FINISHED_INFORM_URL"%{ endif }
# Eject the installation media before rebooting
d-i cdrom-detect/eject boolean true
diff --git a/debian/13-trixie/variables.pkr.hcl b/debian/13-trixie/variables.pkr.hcl
index ede3f32..5a20bc5 100644
--- a/debian/13-trixie/variables.pkr.hcl
+++ b/debian/13-trixie/variables.pkr.hcl
@@ -59,7 +59,11 @@ variable "install_finished_inform_port" {
description = "The server port to inform when installation is finished"
}
-
+variable "enable_luks" {
+ type = bool
+ default = false
+ description = "Build Debian with LUKS encrypted root storage."
+}
# local values
local "timestamp" {
diff --git a/debian/13-trixie/variants/luks.pkrvars.hcl b/debian/13-trixie/variants/luks.pkrvars.hcl
new file mode 100644
index 0000000..e19e059
--- /dev/null
+++ b/debian/13-trixie/variants/luks.pkrvars.hcl
@@ -0,0 +1,2 @@
+enable_luks = true
+template_vm_id = "65001"
diff --git a/mise.toml b/mise.toml
index 9f90a58..db54c10 100644
--- a/mise.toml
+++ b/mise.toml
@@ -17,14 +17,15 @@ run = "packer fmt --recursive ${usage_dir?}"
[tasks.build]
usage = '''
arg "" help="Directory containing the Packer template to build e.g. debian/13-trixie"
+flag "--var-file " help="HCL var-file to pass to Packer"
flag "-i --install-finished-inform-port " help="Server port to inform when installation is finished" hide=#true
'''
run = '''
mise run lint ${usage_dir?}
-[[ -z "${usage_install_finished_inform_port}" ]] && packer build ${usage_dir?} || true
-[[ -n "${usage_install_finished_inform_port}" ]] && packer build \
- -var "install_finished_inform_port=${usage_install_finished_inform_port?}" \
- ${usage_dir?} || true
+build_args=()
+[[ -n "${usage_var_file}" ]] && build_args+=("-var-file=${usage_var_file?}")
+[[ -n "${usage_install_finished_inform_port}" ]] && build_args+=("-var" "install_finished_inform_port=${usage_install_finished_inform_port?}")
+packer build "${build_args[@]}" ${usage_dir?} || true
'''
[tasks.build-luks]
@@ -33,7 +34,7 @@ arg "" help="Directory containing the Packer template to build e.g. debian/
flag "--luks-wait-seconds " help="Seconds to wait for the LUKS password prompt after installation before sending the password" default="45"
'''
run = '''
-_scripts/unlock-luks-after-install.py -t ${usage_dir?} --luks-wait-seconds ${usage_luks_wait_seconds?}
+_scripts/unlock-luks-after-install.py -t ${usage_dir?} --var-file ${usage_dir?}/variants/luks.pkrvars.hcl --luks-wait-seconds ${usage_luks_wait_seconds?}
'''
[tasks.init]