Untitled

 avatar
unknown
plain_text
10 months ago
5.7 kB
12
Indexable
#!/usr/bin/env bash
# Create separate LVs for /var, /var/log, /var/log/audit, /var/tmp
# AlmaLinux 9.6 — CIS-ish mount options (nosuid,noexec + nodev)
set -euo pipefail

# ---------- Tunables ----------
# Sizes (change as needed)
VAR_SIZE="${VAR_SIZE:-20G}"
VAR_LOG_SIZE="${VAR_LOG_SIZE:-4G}"
VAR_AUDIT_SIZE="${VAR_AUDIT_SIZE:-2G}"
VAR_TMP_SIZE="${VAR_TMP_SIZE:-4G}"

# Mount options
# Per your ask: nosuid+noexec everywhere. nodev added as a safe default.
# If you *don't* want noexec on /var, set VAR_NOEXEC=0 before running.
VAR_NOEXEC="${VAR_NOEXEC:-1}"

# Filesystem type
FS_TYPE="${FS_TYPE:-xfs}"

# ---------- Helpers ----------
die(){ echo "[!] $*" >&2; exit 1; }
ok(){ echo "[+] $*"; }
run(){ echo "[*] $*"; eval "$@"; }

[[ $EUID -eq 0 ]] || die "Run as root."

# Find a VG with free space (first match)
VG_NAME="${VG_NAME:-$(vgs --noheadings -o vg_name,vg_free --units m --nosuffix \
  | awk '$2+0>0 {print $1; exit}')}"

[[ -n "${VG_NAME}" ]] || die "No LVM volume group with free space found. Set VG_NAME=your_vg and ensure free extents."

ok "Using VG: ${VG_NAME}"

# Device paths
LV_VAR="/dev/${VG_NAME}/var"
LV_LOG="/dev/${VG_NAME}/var_log"
LV_AUD="/dev/${VG_NAME}/var_log_audit"
LV_TMP="/dev/${VG_NAME}/var_tmp"

# Create LVs if missing
maybe_lvcreate () {
  local lv="$1" size="$2" name="$(basename "$lv")"
  if lvdisplay "$lv" &>/dev/null; then
    ok "LV $lv already exists"
  else
    run "lvcreate -L ${size} -n ${name} ${VG_NAME}"
  fi
}

maybe_lvcreate "$LV_VAR" "$VAR_SIZE"
maybe_lvcreate "$LV_LOG" "$VAR_LOG_SIZE"
maybe_lvcreate "$LV_AUD" "$VAR_AUDIT_SIZE"
maybe_lvcreate "$LV_TMP" "$VAR_TMP_SIZE"

# Make filesystems if needed
maybe_mkfs () {
  local dev="$1"
  if blkid "$dev" &>/dev/null; then
    ok "Filesystem already present on $dev"
  else
    run "mkfs.${FS_TYPE} -f $dev"
  fi
}
maybe_mkfs "$LV_VAR"
maybe_mkfs "$LV_LOG"
maybe_mkfs "$LV_AUD"
maybe_mkfs "$LV_TMP"

# Temp mount points
mkdir -p /mnt/newvar /mnt/newvarlog /mnt/newaudit /mnt/newvartmp

# Mount new filesystems to staging
mountpoint -q /mnt/newvar     || run "mount $LV_VAR /mnt/newvar"
mountpoint -q /mnt/newvarlog  || run "mount $LV_LOG /mnt/newvarlog"
mountpoint -q /mnt/newaudit   || run "mount $LV_AUD /mnt/newaudit"
mountpoint -q /mnt/newvartmp  || run "mount $LV_TMP /mnt/newvartmp"

# First pass copy (preserve ACLs, xattrs, selinux)
ok "Copying data (first pass)…"
run "rsync -aAXH --numeric-ids /var/ /mnt/newvar/"
run "rsync -aAXH --numeric-ids /var/log/ /mnt/newvarlog/"
mkdir -p /var/log/audit
run "rsync -aAXH --numeric-ids /var/log/audit/ /mnt/newaudit/"
run "rsync -aAXH --numeric-ids /var/tmp/ /mnt/newvartmp/"

# Quiesce logging briefly for a clean second pass
run "systemctl stop rsyslog || true"
run "systemctl stop auditd || true"
sleep 1

# Second pass (catch deltas)
ok "Copying data (second pass)…"
run "rsync -aAXH --delete --numeric-ids /var/ /mnt/newvar/"
run "rsync -aAXH --delete --numeric-ids /var/log/ /mnt/newvarlog/"
run "rsync -aAXH --delete --numeric-ids /var/log/audit/ /mnt/newaudit/"
run "rsync -aAXH --delete --numeric-ids /var/tmp/ /mnt/newvartmp/"

# Ensure required directories exist on the new /var
mkdir -p /mnt/newvar/log /mnt/newvar/log/audit /mnt/newvar/tmp

# Start services back
run "systemctl start auditd || true"
run "systemctl start rsyslog || true"

# Get UUIDs
UUID_VAR="$(blkid -s UUID -o value "$LV_VAR")"
UUID_LOG="$(blkid -s UUID -o value "$LV_LOG")"
UUID_AUD="$(blkid -s UUID -o value "$LV_AUD")"
UUID_TMP="$(blkid -s UUID -o value "$LV_TMP")"

[[ -n "$UUID_VAR" && -n "$UUID_LOG" && -n "$UUID_AUD" && -n "$UUID_TMP" ]] || die "Could not read UUIDs."

# Compose mount options
VAR_OPTS="defaults,nodev"
if [[ "${VAR_NOEXEC}" -eq 1 ]]; then
  VAR_OPTS="${VAR_OPTS},nosuid,noexec"
fi
LOG_OPTS="defaults,nodev,nosuid,noexec"
AUD_OPTS="defaults,nodev,nosuid,noexec"
TMP_OPTS="defaults,nodev,nosuid,noexec"

# Backup fstab
cp -a /etc/fstab "/etc/fstab.bak.$(date +%Y%m%d-%H%M%S)"

# Remove any previous lines for these mountpoints (idempotent)
sed -i -r '/[[:space:]]\/var[[:space:]]/d' /etc/fstab
sed -i -r '/[[:space:]]\/var\/log[[:space:]]/d' /etc/fstab
sed -i -r '/[[:space:]]\/var\/log\/audit[[:space:]]/d' /etc/fstab
sed -i -r '/[[:space:]]\/var\/tmp[[:space:]]/d' /etc/fstab

# Append new entries
cat >>/etc/fstab <<EOF
UUID=${UUID_VAR}   /var               ${FS_TYPE}   ${VAR_OPTS}           0 2
UUID=${UUID_LOG}   /var/log           ${FS_TYPE}   ${LOG_OPTS}           0 2
UUID=${UUID_AUD}   /var/log/audit     ${FS_TYPE}   ${AUD_OPTS}           0 2
UUID=${UUID_TMP}   /var/tmp           ${FS_TYPE}   ${TMP_OPTS}           0 2
EOF

ok "Updated /etc/fstab with secure options."

# Create mountpoints (in case they don't exist) and mount the subtrees now
mkdir -p /var/log /var/log/audit /var/tmp

# Mount sub-mounts immediately (safe without reboot)
run "mount /var/log"
run "mount /var/log/audit"
run "mount /var/tmp"

# Restore SELinux context on mounted paths
run "restorecon -RFv /var/log /var/log/audit /var/tmp || true"

ok "Sub-mounts active. /var itself will switch at next reboot."

echo
echo "========================================================="
echo " Migration complete."
echo " - /var/log, /var/log/audit, /var/tmp are mounted now."
echo " - /var will switch to its new LV on the next reboot."
echo " - Verify: lsblk -f; findmnt /var/log /var/log/audit /var/tmp"
echo " *If you want to activate /var now anyway*, you can:"
echo "   1) ensure services are quiet, then"
echo "   2) run: mount /var   (NOT RECOMMENDED on a busy system)"
echo "========================================================="
Editor is loading...
Leave a Comment