You've already forked auto-update-ubuntu
260 lines
5.5 KiB
Plaintext
260 lines
5.5 KiB
Plaintext
|
|
#!/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 <<EOF
|
|||
|
|
Usage: $0 <mode>
|
|||
|
|
|
|||
|
|
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" <<EOF
|
|||
|
|
#
|
|||
|
|
# Managed by: auto-update-ubuntu
|
|||
|
|
# Purpose : OPS-controlled unattended upgrades
|
|||
|
|
# Schedule : Every Friday at 03:00
|
|||
|
|
#
|
|||
|
|
0 3 * * 5 root /usr/bin/apt update && /usr/bin/unattended-upgrade -v >/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
|