Compare commits
6 commits
cea8812dbd
...
f6785b69ac
| Author | SHA1 | Date | |
|---|---|---|---|
| f6785b69ac | |||
| b05a45f6eb | |||
| 687775a5e5 | |||
| 4142a521ba | |||
| ebffbbb548 | |||
| 074334b355 |
9 changed files with 1963 additions and 50 deletions
102
debian/13-trixie-luks/debian-trixie.pkr.hcl
vendored
102
debian/13-trixie-luks/debian-trixie.pkr.hcl
vendored
|
|
@ -20,7 +20,7 @@ source "proxmox-iso" "debian-13-trixie-luks" {
|
||||||
node = "${var.proxmox_node}"
|
node = "${var.proxmox_node}"
|
||||||
vm_id = "${var.template_vm_id}"
|
vm_id = "${var.template_vm_id}"
|
||||||
vm_name = "debian-13-trixie-luks-${local.timestamp}"
|
vm_name = "debian-13-trixie-luks-${local.timestamp}"
|
||||||
template_description = "Debian 13 Trixie, LUKS encrypted, built with Packer on ${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"
|
os = "l26"
|
||||||
qemu_agent = true
|
qemu_agent = true
|
||||||
|
|
||||||
|
|
@ -45,6 +45,10 @@ source "proxmox-iso" "debian-13-trixie-luks" {
|
||||||
efi_type = "4m"
|
efi_type = "4m"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serials = [
|
||||||
|
"socket"
|
||||||
|
]
|
||||||
|
|
||||||
# Download ISO
|
# Download ISO
|
||||||
boot_iso {
|
boot_iso {
|
||||||
type = "scsi"
|
type = "scsi"
|
||||||
|
|
@ -75,6 +79,7 @@ source "proxmox-iso" "debian-13-trixie-luks" {
|
||||||
"<wait3>c<wait3>",
|
"<wait3>c<wait3>",
|
||||||
"linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
|
"linux /install.amd/vmlinuz auto-install/enable=true priority=critical ",
|
||||||
"DEBIAN_FRONTEND=text ",
|
"DEBIAN_FRONTEND=text ",
|
||||||
|
"console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 ",
|
||||||
"passwd/root-password='${var.default_root_passphrase}' ",
|
"passwd/root-password='${var.default_root_passphrase}' ",
|
||||||
"passwd/root-password-again='${var.default_root_passphrase}' ",
|
"passwd/root-password-again='${var.default_root_passphrase}' ",
|
||||||
"partman-crypto/passphrase='${var.default_luks_passphrase}' ",
|
"partman-crypto/passphrase='${var.default_luks_passphrase}' ",
|
||||||
|
|
@ -101,21 +106,38 @@ build {
|
||||||
name = "debian-13-trixie-luks-image"
|
name = "debian-13-trixie-luks-image"
|
||||||
sources = ["source.proxmox-iso.debian-13-trixie-luks"]
|
sources = ["source.proxmox-iso.debian-13-trixie-luks"]
|
||||||
|
|
||||||
# Provisioning the VM Template for Cloud-Init Integration in Proxmox #1
|
# Install dependencies and default packages
|
||||||
provisioner "shell" {
|
provisioner "shell" {
|
||||||
inline = [
|
inline = [
|
||||||
"rm /etc/ssh/ssh_host_*",
|
"export DEBIAN_FRONTEND=noninteractive",
|
||||||
"truncate -s 0 /etc/machine-id",
|
"apt-get update",
|
||||||
"apt -y autoremove --purge 2> /dev/null",
|
"apt-get install -y age apt-transport-https aria2 bat bc bmon btop ca-certificates curl duf eza fastfetch fzf 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"
|
||||||
"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"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 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
|
# Provisioning the VM Template for Cloud-Init Integration in Proxmox #2
|
||||||
provisioner "file" {
|
provisioner "file" {
|
||||||
source = "debian/13-trixie-luks/files/99-pve.cfg"
|
source = "debian/13-trixie-luks/files/99-pve.cfg"
|
||||||
|
|
@ -137,4 +159,62 @@ build {
|
||||||
source = "debian/13-trixie-luks/files/debian.sources"
|
source = "debian/13-trixie-luks/files/debian.sources"
|
||||||
destination = "/etc/apt/sources.list.d/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"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
debian/13-trixie-luks/files/90-initial-login-setup.sh
vendored
Normal file
26
debian/13-trixie-luks/files/90-initial-login-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#! /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
|
||||||
|
#DEBUG touch SENTINEL before running the setup script to prevent infinite loops during development
|
||||||
|
sudo /usr/local/bin/initial-setup.sh
|
||||||
|
sudo touch "$SENTINEL"
|
||||||
|
fi
|
||||||
740
debian/13-trixie-luks/files/initial-setup.sh
vendored
Normal file
740
debian/13-trixie-luks/files/initial-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,740 @@
|
||||||
|
#!/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
|
||||||
|
value="${value:-$default}"
|
||||||
|
else
|
||||||
|
read -r -p "${label}: " value </dev/tty
|
||||||
|
fi
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_secret() {
|
||||||
|
local label="$1"
|
||||||
|
local value=""
|
||||||
|
while true; do
|
||||||
|
read -r -s -p "${label}: " value </dev/tty
|
||||||
|
printf '\n' >/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
|
||||||
|
printf '\n' >/dev/tty
|
||||||
|
read -r -s -p "${confirm_label}: " b </dev/tty
|
||||||
|
printf '\n' >/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/tty
|
||||||
|
if [ -z "$answer" ]; then
|
||||||
|
answer="$default"
|
||||||
|
fi
|
||||||
|
case "${answer,,}" in
|
||||||
|
y|yes) return 0 ;;
|
||||||
|
n|no) return 1 ;;
|
||||||
|
*) log_warn "Please answer yes or no." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
human_bytes() {
|
||||||
|
local bytes="$1"
|
||||||
|
if command -v numfmt >/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
|
||||||
|
}
|
||||||
|
|
||||||
|
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:-<empty>} DISK_DEV=${DISK_DEV:-<empty>} PART_NUM=${PART_NUM:-<empty>}"
|
||||||
|
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 ! 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 "$@"
|
||||||
0
debian/13-trixie-luks/http/meta-data
vendored
0
debian/13-trixie-luks/http/meta-data
vendored
9
debian/13-trixie-luks/http/preseed.cfg
vendored
9
debian/13-trixie-luks/http/preseed.cfg
vendored
|
|
@ -116,7 +116,7 @@ d-i partman-auto/expert_recipe string \
|
||||||
filesystem{ ext4 } \
|
filesystem{ ext4 } \
|
||||||
mountpoint{ /boot } \
|
mountpoint{ /boot } \
|
||||||
. \
|
. \
|
||||||
25770 25770 25770 ext4 \
|
25770 25770 -1 ext4 \
|
||||||
$lvmok{ } \
|
$lvmok{ } \
|
||||||
lv_name{ root } \
|
lv_name{ root } \
|
||||||
method{ format } \
|
method{ format } \
|
||||||
|
|
@ -124,11 +124,6 @@ d-i partman-auto/expert_recipe string \
|
||||||
use_filesystem{ } \
|
use_filesystem{ } \
|
||||||
filesystem{ ext4 } \
|
filesystem{ ext4 } \
|
||||||
mountpoint{ / } \
|
mountpoint{ / } \
|
||||||
. \
|
|
||||||
1 10000 -1 ext4 \
|
|
||||||
$lvmok{ } \
|
|
||||||
lv_name{ reserved } \
|
|
||||||
method{ keep } \
|
|
||||||
.
|
.
|
||||||
|
|
||||||
d-i partman-partitioning/confirm_write_new_label boolean true
|
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||||
|
|
@ -140,7 +135,7 @@ d-i partman/confirm_nooverwrite boolean true
|
||||||
d-i debconf/frontend select noninteractive
|
d-i debconf/frontend select noninteractive
|
||||||
tasksel tasksel/first multiselect standard, ssh-server
|
tasksel tasksel/first multiselect standard, ssh-server
|
||||||
|
|
||||||
d-i pkgsel/include string qemu-guest-agent cloud-init curl vim
|
d-i pkgsel/include string cloud-init curl qemu-guest-agent sudo vim
|
||||||
d-i pkgsel/upgrade select full-upgrade
|
d-i pkgsel/upgrade select full-upgrade
|
||||||
d-i pkgsel/update-policy select none
|
d-i pkgsel/update-policy select none
|
||||||
d-i pkgsel/updatedb boolean true
|
d-i pkgsel/updatedb boolean true
|
||||||
|
|
|
||||||
32
debian/13-trixie-luks/http/user-data
vendored
32
debian/13-trixie-luks/http/user-data
vendored
|
|
@ -1,32 +0,0 @@
|
||||||
#cloud-config
|
|
||||||
autoinstall:
|
|
||||||
version: 1
|
|
||||||
locale: en_US
|
|
||||||
keyboard:
|
|
||||||
layout: us
|
|
||||||
ssh:
|
|
||||||
install-server: true
|
|
||||||
allow-pw: false
|
|
||||||
disable_root: true
|
|
||||||
ssh_quiet_keygen: true
|
|
||||||
allow_public_ssh_keys: true
|
|
||||||
apt:
|
|
||||||
preserve_sources_list: false
|
|
||||||
packages:
|
|
||||||
- qemu-guest-agent
|
|
||||||
- sudo
|
|
||||||
storage:
|
|
||||||
layout:
|
|
||||||
name: direct
|
|
||||||
swap:
|
|
||||||
size: 0
|
|
||||||
user-data:
|
|
||||||
package_upgrade: false
|
|
||||||
timezone: UTC
|
|
||||||
users:
|
|
||||||
- name: root
|
|
||||||
groups: [adm, sudo]
|
|
||||||
lock-passwd: true #Disable password login
|
|
||||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
|
||||||
shell: /bin/bash
|
|
||||||
passwd: "" # Remove password
|
|
||||||
8
debian/13-trixie-luks/scripts/crowdsec-configuration.sh
vendored
Normal file
8
debian/13-trixie-luks/scripts/crowdsec-configuration.sh
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/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
|
||||||
370
debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh
vendored
Normal file
370
debian/13-trixie-luks/scripts/crowdsec-repo-setup.sh
vendored
Normal file
|
|
@ -0,0 +1,370 @@
|
||||||
|
#!/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
|
||||||
726
debian/13-trixie-luks/scripts/tailscale.sh
vendored
Normal file
726
debian/13-trixie-luks/scripts/tailscale.sh
vendored
Normal file
|
|
@ -0,0 +1,726 @@
|
||||||
|
#!/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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue