178 lines
5.0 KiB
Bash
178 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# setup-auto-updates-security-only.sh
|
|
#
|
|
# Debian/Ubuntu universal unattended-upgrades setup (SECURITY ONLY):
|
|
# - fixes locale (en_US.UTF-8) to avoid perl/locale warnings
|
|
# - installs & enables unattended-upgrades
|
|
# - installs ONLY security updates
|
|
# - smart reboot at 04:00 (only when needed, and no logged-in users)
|
|
# - no email configuration
|
|
# - optional self-deletion at end
|
|
|
|
set -Eeuo pipefail
|
|
trap 'echo "[ERROR] Line $LINENO failed" >&2' ERR
|
|
|
|
REBOOT_TIME="04:00"
|
|
TARGET_LOCALE="en_US.UTF-8"
|
|
|
|
require_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
echo "[ERROR] Run as root (sudo)" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
detect_os() {
|
|
if [[ ! -f /etc/os-release ]]; then
|
|
echo "[ERROR] /etc/os-release not found" >&2
|
|
exit 1
|
|
fi
|
|
. /etc/os-release
|
|
case "$ID" in
|
|
ubuntu) OS="ubuntu" ;;
|
|
debian) OS="debian" ;;
|
|
*) echo "[ERROR] Unsupported OS: $ID" >&2; exit 1 ;;
|
|
esac
|
|
CODENAME="${VERSION_CODENAME:-$UBUNTU_CODENAME}"
|
|
echo "[INFO] Detected: $PRETTY_NAME ($OS / $CODENAME)"
|
|
}
|
|
|
|
fix_locale() {
|
|
echo "[INFO] Ensuring locale ${TARGET_LOCALE} is generated…"
|
|
apt-get update -y >/dev/null 2>&1 || true
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y locales >/dev/null 2>&1 || true
|
|
|
|
if [[ -f /etc/locale.gen ]]; then
|
|
if grep -qE "^\s*#\s*${TARGET_LOCALE}\s+UTF-8" /etc/locale.gen; then
|
|
sed -ri "s/^\s*#\s*(${TARGET_LOCALE}\s+UTF-8)/\1/" /etc/locale.gen
|
|
elif ! grep -qE "^\s*${TARGET_LOCALE}\s+UTF-8" /etc/locale.gen; then
|
|
echo "${TARGET_LOCALE} UTF-8" >> /etc/locale.gen
|
|
fi
|
|
else
|
|
echo "${TARGET_LOCALE} UTF-8" > /etc/locale.gen
|
|
fi
|
|
|
|
locale-gen
|
|
update-locale LANG=${TARGET_LOCALE} LC_ALL=${TARGET_LOCALE}
|
|
export LANG=${TARGET_LOCALE}
|
|
export LC_ALL=${TARGET_LOCALE}
|
|
}
|
|
|
|
install_unattended() {
|
|
echo "[INFO] Updating apt cache…"
|
|
apt update
|
|
echo "[INFO] Installing unattended-upgrades…"
|
|
DEBIAN_FRONTEND=noninteractive apt install -y unattended-upgrades
|
|
}
|
|
|
|
enable_unattended() {
|
|
echo "[INFO] Enabling unattended-upgrades via debconf…"
|
|
echo 'unattended-upgrades unattended-upgrades/enable_auto_updates boolean true' | debconf-set-selections
|
|
DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -f noninteractive unattended-upgrades
|
|
}
|
|
|
|
write_50_conf_ubuntu() {
|
|
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<EOF
|
|
// Ubuntu: SECURITY-ONLY unattended upgrades
|
|
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"\${distro_id}:\${distro_codename}-security";
|
|
"\${distro_id}ESM:\${distro_codename}-infra-security";
|
|
"\${distro_id}ESMApps:\${distro_codename}-apps-security";
|
|
};
|
|
|
|
Unattended-Upgrade::Automatic-Reboot "true";
|
|
Unattended-Upgrade::Automatic-Reboot-Time "${REBOOT_TIME}";
|
|
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
|
|
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
|
|
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::SyslogEnable "true";
|
|
Unattended-Upgrade::Verbose "0";
|
|
EOF
|
|
}
|
|
|
|
write_50_conf_debian() {
|
|
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<EOF
|
|
// Debian: SECURITY-ONLY unattended upgrades
|
|
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"Debian:\${distro_codename}-security";
|
|
"Debian-Security:\${distro_codename}-security";
|
|
};
|
|
|
|
Unattended-Upgrade::Automatic-Reboot "true";
|
|
Unattended-Upgrade::Automatic-Reboot-Time "${REBOOT_TIME}";
|
|
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
|
|
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
|
|
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::SyslogEnable "true";
|
|
Unattended-Upgrade::Verbose "0";
|
|
EOF
|
|
}
|
|
|
|
write_20_conf() {
|
|
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
|
|
APT::Periodic::Update-Package-Lists "1";
|
|
APT::Periodic::Download-Upgradeable-Packages "1";
|
|
APT::Periodic::AutocleanInterval "7";
|
|
APT::Periodic::Unattended-Upgrade "1";
|
|
EOF
|
|
}
|
|
|
|
dry_run_test() {
|
|
echo "[INFO] Dry-run unattended-upgrades (debug)…"
|
|
unattended-upgrades --dry-run --debug > /tmp/unattended-upgrades-test.log 2>&1 || true
|
|
echo "[INFO] Tail of /tmp/unattended-upgrades-test.log:"
|
|
tail -n 30 /tmp/unattended-upgrades-test.log || true
|
|
}
|
|
|
|
show_status() {
|
|
echo "[INFO] apt timers:"
|
|
systemctl list-timers --all | grep -E 'apt-(daily|daily-upgrade)\.timer' || true
|
|
echo
|
|
echo "[INFO] Config files written:"
|
|
ls -l /etc/apt/apt.conf.d/20auto-upgrades /etc/apt/apt.conf.d/50unattended-upgrades
|
|
}
|
|
|
|
prompt_self_delete() {
|
|
echo
|
|
read -r -p "Remove this script? [Y/n] " confirm
|
|
case "$confirm" in
|
|
[nN]*) echo "[INFO] Script not removed." ;;
|
|
*) echo "[INFO] Removing script: $0"; rm -- "$0" ;;
|
|
esac
|
|
}
|
|
|
|
main() {
|
|
require_root
|
|
detect_os
|
|
fix_locale
|
|
install_unattended
|
|
enable_unattended
|
|
|
|
echo "[INFO] Writing /etc/apt/apt.conf.d/50unattended-upgrades…"
|
|
if [[ "$OS" == "ubuntu" ]]; then
|
|
write_50_conf_ubuntu
|
|
else
|
|
write_50_conf_debian
|
|
fi
|
|
|
|
echo "[INFO] Writing /etc/apt/apt.conf.d/20auto-upgrades…"
|
|
write_20_conf
|
|
|
|
dry_run_test
|
|
show_status
|
|
|
|
echo "[OK] Security-only unattended updates configured. Reboot @ ${REBOOT_TIME} if needed."
|
|
prompt_self_delete
|
|
}
|
|
|
|
main "$@"
|