#!/usr/bin/env bash # Author : Allan Christensen # First Created : 23-06-2022 (DD-MM-YYYY) # Description : OPS-controlled unattended-upgrades policy configuration for Ubuntu 24.04 # License : MIT License # # Are we root # if [[ $(id -u) -ne 0 ]]; then echo "" echo "Must be root or use sudo" echo "" exit 1 fi # # Variables # mode="${1:-}" config1="/etc/apt/apt.conf.d/20auto-upgrades" config1alt="/usr/share/unattended-upgrades/20auto-upgrades" config2="/etc/apt/apt.conf.d/50unattended-upgrades" config2alt="/usr/share/unattended-upgrades/50unattended-upgrades" cronfile="/etc/cron.d/updatesystem" # # Functions # die () { echo "Error: $*" >&2 exit 1 } usage () { cat < Please select ONE of the following modes: 1 Security + software updates Automatic reboot immediately after upgrades complete 2 Security + software updates No automatic reboot Users will be notified on next login if a reboot is required 3 Security updates only Automatic reboot immediately after upgrades complete 4 Security updates only No automatic reboot Users will be notified on next login if a reboot is required EOF exit 1 } chkcfg () { if [[ ! -f "$1" ]]; then [[ -f "$2" ]] || die "Missing source config: $2" cp -Rp "$2" "$1" || die "Failed to copy $2 to $1" fi } mkorig () { if [[ ! -f "${1}.orig" ]]; then cp -Rp "$1" "${1}.orig" || die "Failed to create backup: ${1}.orig" fi } # # Disable Ubuntu automatic timers (OPS owns scheduling) # disable_apt_timers () { systemctl disable --now apt-daily.timer apt-daily-upgrade.timer >/dev/null 2>&1 || true systemctl mask apt-daily.service apt-daily-upgrade.service >/dev/null 2>&1 || true } # # Ensure periodic jobs are disabled (cron owns execution) # set_20auto () { sed -i 's|^\s*APT::Periodic::Update-Package-Lists.*|APT::Periodic::Update-Package-Lists "0";|' "$config1" sed -i 's|^\s*APT::Periodic::Unattended-Upgrade.*|APT::Periodic::Unattended-Upgrade "0";|' "$config1" } # # Allowed origins – explicit, Bash-native # set_allowed_origins () { local allow_updates="$1" # # Always enable security updates # sed -i \ '/^\s*\/\/\s*"\${distro_id}:\${distro_codename}-security"/ s|^\s*//\s*||' \ "$config2" # # Enable or disable non-security updates # if [[ "$allow_updates" == "true" ]]; then sed -i \ '/^\s*\/\/\s*"\${distro_id}:\${distro_codename}-updates"/ s|^\s*//\s*||' \ "$config2" else sed -i \ '/^\s*"\${distro_id}:\${distro_codename}-updates"/ s|^|// |' \ "$config2" fi } # # Reboot policy – immediate reboot after upgrades # set_reboot_policy () { local reboot="$1" local reboot_with_users="$2" # # Automatic-Reboot (exact key only) # sed -i \ '/^\s*\/\/\s*Unattended-Upgrade::Automatic-Reboot\s/ s|^\s*//\s*||' \ "$config2" sed -i \ 's|^\s*Unattended-Upgrade::Automatic-Reboot\s*".*";|Unattended-Upgrade::Automatic-Reboot "'"$reboot"'";|' \ "$config2" # # Automatic-Reboot-WithUsers (exact key only) # sed -i \ '/^\s*\/\/\s*Unattended-Upgrade::Automatic-Reboot-WithUsers\s/ s|^\s*//\s*||' \ "$config2" sed -i \ 's|^\s*Unattended-Upgrade::Automatic-Reboot-WithUsers\s*".*";|Unattended-Upgrade::Automatic-Reboot-WithUsers "'"$reboot_with_users"'";|' \ "$config2" # # Ensure reboot-time stays commented (cron defines timing) # sed -i \ '/^\s*Unattended-Upgrade::Automatic-Reboot-Time/ s|^|// |' \ "$config2" } # # Cron – authoritative schedule # write_cron () { cat > "$cronfile" </dev/null 2>&1 EOF chmod 644 "$cronfile" || die "Failed chmod on $cronfile" chown root:root "$cronfile" || die "Failed chown on $cronfile" } restart_services () { systemctl restart unattended-upgrades.service >/dev/null 2>&1 || die "Failed to restart unattended-upgrades" systemctl restart cron.service >/dev/null 2>&1 || die "Failed to restart cron" } # # Validate mode # case "$mode" in 1|2|3|4) ;; *) usage ;; esac # # Informational output (configuration-time only) # echo "Applying unattended-upgrades policy:" echo "" case "$mode" in 1) echo " Mode: 1" echo " Updates: Security + software updates" echo " Reboot: Immediate reboot after upgrades complete" ;; 2) echo " Mode: 2" echo " Updates: Security + software updates" echo " Reboot: Disabled" echo " User notification: On next login if a reboot is required" ;; 3) echo " Mode: 3" echo " Updates: Security updates only" echo " Reboot: Immediate reboot after upgrades complete" ;; 4) echo " Mode: 4" echo " Updates: Security updates only" echo " Reboot: Disabled" echo " User notification: On next login if a reboot is required" ;; esac echo "" # # Packages (no implicit apt update) # apt-get -y -qq install unattended-upgrades update-notifier-common >/dev/null \ || die "Package install failed" # # Ensure configs exist # chkcfg "$config1" "$config1alt" chkcfg "$config2" "$config2alt" # # Backup originals (once) # mkorig "$config1" mkorig "$config2" # # OPS-owned execution model # set_20auto disable_apt_timers # # Apply policy # case "$mode" in 1|2) set_allowed_origins "true" ;; 3|4) set_allowed_origins "false" ;; esac case "$mode" in 1|3) set_reboot_policy "true" "true" ;; 2|4) set_reboot_policy "false" "false" ;; esac # # Cron + services # write_cron restart_services exit 0