You've already forked auto-update-ubuntu
260 lines
5.5 KiB
Bash
Executable File
260 lines
5.5 KiB
Bash
Executable File
#!/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
|