서버 침해의 대부분은 교묘한 exploit이 아니라 몇 달 전에 이미 패치가 나온 취약점을 통해 일어납니다. 이유는 대개 게으름이 아닙니다. 가동 중인 서버에서 손으로 업데이트하는 일은 무섭습니다. apt upgrade가 아무도 부탁하지 않은 것을 재시작하는 일이 있으니까요. 자동 업데이트는 이 문제를 정리해 주지만 평판이 좋지 않습니다 — 그리고 그 평판은 급하게 설정된 만큼 정확히 정당합니다.

보안 패치가 스스로 도착하면서도 PHP 버전이 하룻밤 사이에 바뀌지 않는 구성을 살펴봅시다.

설치

sudo apt install unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades

이 대화 상자가 /etc/apt/apt.conf.d/20auto-upgrades를 만듭니다. 무엇이 나왔는지 확인하세요.

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

1은 「매일」을 뜻합니다. 이 모든 것을 움직이는 것은 고전적인 cron이 아니라 systemd의 타이머입니다.

systemctl list-timers | grep apt

가장 중요한 것: 보안만

주요 파일은 /etc/apt/apt.conf.d/50unattended-upgrades입니다. 거기에는 Allowed-Origins 목록이 있고(Debian에서는 Origins-Pattern), 기본으로는 보안 저장소 켜져 있습니다. 그대로 두세요.

-updates 줄의 주석을 지우고 싶은 유혹 — 「다 업데이트되게 하자」 — 은 강합니다. 하지 마세요. updates 저장소는 수정만이 아니라 새 버전을 들여옵니다. 그리고 한밤중의 놀라움은 바로 거기에서 옵니다. 보안과 최신성은 다른 일이며, 두 번째는 당신이 키보드 앞에 있을 때 하는 편이 낫습니다.

자동으로 업데이트되면 안 되는 패키지가 있다면 그것을 위한 제외 목록이 있습니다.

Unattended-Upgrade::Package-Blacklist {
    "mariadb-server";
    "php8.3-fpm";
};

의식적으로 쓰세요. 여기의 각 줄은 「이건 내가 직접 업데이트한다」는 뜻이며 — 그것은 지켜야 할 약속입니다.

재부팅

핵심 줄:

Unattended-Upgrade::Automatic-Reboot "false";

사이트가 있는 서버라면 이것을 false로 두는 것이 옳습니다. 예고 없는 새벽 세 시의 재부팅은 하루 미뤄진 패치보다 나쁘니까요. 다만 이 결정에는 필수적인 후반부가 있고, 잊히는 것이 바로 그 후반부입니다.

커널, libc, openssl이 업데이트되면 시스템은 파일 /var/run/reboot-required를 만듭니다. 재부팅 전까지 고쳐진 버전은 디스크에 있고 옛 버전은 메모리에서 계속 돕니다 — 즉 패키지는 업데이트된 것으로 세어지지만 취약점은 어디로도 가지 않았습니다. 명시적으로 확인하세요.

ls -l /var/run/reboot-required
cat /var/run/reboot-required.pkgs

두 번째 파일에는 무엇 때문에 재부팅이 필요해졌는지 정확히 적혀 있습니다. 규칙은 단순합니다. 표시를 보면 「언젠가」가 아니라 앞으로 하루이틀 안의 시간대를 잡으세요.

라이브러리는 별개의 경우입니다. openssl은 업데이트되고 nginx와 PHP-FPM은 옛 버전을 메모리에 담은 채 계속 돌며, 재부팅 표시는 아예 나타나지 않습니다. 누구에게 재시작이 필요한지는 needrestart가 알려 줍니다.

sudo apt install needrestart
sudo needrestart -b

다만 「보고하되 묻지 말 것」 모드로 두세요. 그러지 않으면 비대화식 설치 도중에 질문을 시작해 설치를 멈춰 세웁니다. 이를 위해 /etc/needrestart/conf.d/$nrconf{restart} = 'l'; 한 줄을 담은 파일을 두세요.

실제로 작동하는지 확인하기

설치 없이 시험 실행:

sudo unattended-upgrade --dry-run --debug

출력에는 어떤 패키지가 규칙에 맞고 어떤 것이 왜 걸러졌는지 나옵니다. 실제로 무슨 일이 있었는지는 로그에 있습니다.

sudo tail -50 /var/log/unattended-upgrades/unattended-upgrades.log

지금 몇 건의 업데이트가 기다리고 있는가:

apt list --upgradable 2>/dev/null | grep -i security

이 마지막 명령이 그중 가장 유용합니다. 설정된 자동 업데이트에는 조용히 망가지는 버릇이 있습니다. /boot의 공간이 떨어졌다, 저장소가 키를 바꿨다, 손으로 수정한 뒤 타이머가 꺼졌다. 겉으로는 다 괜찮아 보이고, 패치는 몇 달째 설치되지 않았습니다.

/boot의 공간

전형적인 상황입니다. 옛 커널이 지워지지 않아 /boot 파티션이 차고, 새 커널 설치가 실패하며, 업데이트 전체가 멈춥니다. 몇 달에 한 번은 들여다볼 가치가 있습니다.

df -h /boot
sudo apt autoremove --purge

또는 같은 50unattended-upgrades에서 자동 정리를 켜세요: Remove-Unused-Kernel-Packages "true"Remove-Unused-Dependencies "true".

사람에게 남는 것

자동 업데이트는 반복 작업을 없애 주지만 지켜보는 일을 없애 주지는 않습니다. 언제든 답할 수 있어야 할 질문이 둘입니다. 보안 업데이트가 몇 건 기다리고 있는가, 그리고 재부팅 표시가 서 있는가. 두 답 모두 페이지의 한 줄이며, 의미의 전부는 그 한 줄이 분기에 한 번 당신이 찾아 나서는 것이 아니라 스스로 눈에 들어오는 데 있습니다.