Add auto-updates-sec.sh
This commit is contained in:
177
auto-updates-sec.sh
Normal file
177
auto-updates-sec.sh
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
#!/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 "$@"
|
||||||
Reference in New Issue
Block a user