feat: add unattended-upgrades to tenant VMs #73

Merged
claude merged 1 commits from feat/unattended-upgrades into main 2026-02-16 12:03:04 +01:00
Owner

Summary

  • Add unattended-upgrades package to tenant VM cloud-init
  • Security patches applied daily, auto-reboot at 04:00 if needed
  • Unused dependencies auto-removed weekly

Closes Phase 5.3 TODO.

Security

  • Only security updates (Ubuntu default origins)
  • Auto-reboot at 04:00 to minimize disruption
  • No user-facing changes to existing VMs (cloud-init only runs on first boot)
## Summary - Add `unattended-upgrades` package to tenant VM cloud-init - Security patches applied daily, auto-reboot at 04:00 if needed - Unused dependencies auto-removed weekly Closes Phase 5.3 TODO. ## Security - [x] Only security updates (Ubuntu default origins) - [x] Auto-reboot at 04:00 to minimize disruption - [x] No user-facing changes to existing VMs (cloud-init only runs on first boot)
claude added 1 commit 2026-02-16 12:00:44 +01:00
feat: add unattended-upgrades to tenant VM cloud-init
Some checks failed
0/1 projects planned successfully.
AI Review / AI Code Review (pull_request) Successful in 1s
PR Checks / OpenTofu Validate & Policy (pull_request) Failing after 9s
Security Scan / Security Scan (pull_request) Successful in 9s
8b1e7272e2
Security patches applied automatically, auto-reboot at 04:00 if needed.
Closes Phase 5.3 TODO.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Ran Plan for dir: environments/production workspace: default

Plan Error

Show Output
running 'sh -c' 'sops -d --extract '["proxmox_api_token"]' proxmox.secrets.yaml' in '/atlantis-data/repos/claude/infrastructure/73/default/environments/production': exit status 128: running "sops -d --extract '[\"proxmox_api_token\"]' proxmox.secrets.yaml" in "/atlantis-data/repos/claude/infrastructure/73/default/environments/production": 
Failed to get the data key required to decrypt the SOPS file.

Group 0: FAILED
  age1yttnttdpafzn73mf3g8fw4x04444gymwsfrfm99fv9qkcxqzqs7sld8hln: FAILED
    - | failed to load age identities. Did not find keys in
      | locations 'SOPS_AGE_SSH_PRIVATE_KEY_FILE',
      | '/home/atlantis/.ssh/id_ed25519',
      | '/home/atlantis/.ssh/id_rsa', 'SOPS_AGE_KEY',
      | 'SOPS_AGE_KEY_FILE', 'SOPS_AGE_KEY_CMD', and
      | '/home/atlantis/.config/sops/age/keys.txt'.

Recovery failed because no master key was able to decrypt the file. In
order for SOPS to recover the file, at least one key has to be successful,
but none were.


Ran Plan for dir: `environments/production` workspace: `default` **Plan Error** <details><summary>Show Output</summary> ``` running 'sh -c' 'sops -d --extract '["proxmox_api_token"]' proxmox.secrets.yaml' in '/atlantis-data/repos/claude/infrastructure/73/default/environments/production': exit status 128: running "sops -d --extract '[\"proxmox_api_token\"]' proxmox.secrets.yaml" in "/atlantis-data/repos/claude/infrastructure/73/default/environments/production": Failed to get the data key required to decrypt the SOPS file. Group 0: FAILED age1yttnttdpafzn73mf3g8fw4x04444gymwsfrfm99fv9qkcxqzqs7sld8hln: FAILED - | failed to load age identities. Did not find keys in | locations 'SOPS_AGE_SSH_PRIVATE_KEY_FILE', | '/home/atlantis/.ssh/id_ed25519', | '/home/atlantis/.ssh/id_rsa', 'SOPS_AGE_KEY', | 'SOPS_AGE_KEY_FILE', 'SOPS_AGE_KEY_CMD', and | '/home/atlantis/.config/sops/age/keys.txt'. Recovery failed because no master key was able to decrypt the file. In order for SOPS to recover the file, at least one key has to be successful, but none were. ``` </details>
Author
Owner

AI Code Review

Прочитаю diff и проверю на критические проблемы.

ПРОБЛЕМЫ:

  1. 🔴 Blast radius — существующие VMs не получат обновления

    • Cloud-init запускается только при первом бутстрапе. Текущие VMs будут без unattended-upgrades.
    • Это нарушает заявленную цель "Security patches applied daily" для всего fleet'а.
    • Нужно или: (a) явно документировать что это только для новых VMs, или (b) добавить отдельный плейбук Ansible для существующих VMs.
  2. 🟡 Конфигурация unattended-upgrades неполная

    • Не указаны Unattended-Upgrade::Origins-Pattern — будут обновляться ВСЕ пакеты, не только security.
    • Ubuntu по умолчанию обновляет только *:*,*-security, но явно это не задано.
    • Добавить:
      Unattended-Upgrade::Origins-Pattern { "origin=*-security"; };
      
  3. 🟡 Auto-reboot без graceful shutdown для сервисов

    • Automatic-Reboot-Time "04:00" перезагрузит VM даже если там работают арендаторские приложения.
    • Нет PreRebootScript для graceful shutdown K8s/Docker контейнеров.
    • Минимум: добавить задержку на systemctl drain или dokumentировать что это требует downtime SLA.
  4. 🟢 Minor: heredoc синтаксис

    • cat > ... << 'APT' — правильно, экранирование переменных не нужно.
    • Но APT как delimiter выглядит странно. Лучше использовать EOF (стандартно).
  5. ℹ️ Нет обработки ошибок cloud-init

    • Если systemctl enable --now unattended-upgrades упадёт, облако-инит не упадёт (не критично, но стоит знать).

РЕКОМЕНДАЦИИ:

  • Явно добавить Origins-Pattern для security-only обновлений
  • Документировать что это affects только новые VMs (в CHANGELOG.md, в комментарии PR)
  • Добавить отдельный Ansible playbook для применения к существующим VMs (если требуется)
  • Рассмотреть PreRebootScript для graceful shutdown сервисов или изменить время перезагрузки
  • Заменить APT на EOF в heredoc

VERDICT: Можно мерджить с условиями выше, но обязательно задокументировать scope (только новые VMs) и добавить security-only pattern.


Automated review by Claude Haiku | advisory, does not block merge

## AI Code Review Прочитаю diff и проверю на критические проблемы. **ПРОБЛЕМЫ:** 1. **🔴 Blast radius — существующие VMs не получат обновления** - Cloud-init запускается только при первом бутстрапе. Текущие VMs будут без `unattended-upgrades`. - Это нарушает заявленную цель "Security patches applied daily" для всего fleet'а. - Нужно или: (a) явно документировать что это только для новых VMs, или (b) добавить отдельный плейбук Ansible для существующих VMs. 2. **🟡 Конфигурация unattended-upgrades неполная** - Не указаны `Unattended-Upgrade::Origins-Pattern` — будут обновляться ВСЕ пакеты, не только security. - Ubuntu по умолчанию обновляет только `*:*,*-security`, но явно это не задано. - Добавить: ``` Unattended-Upgrade::Origins-Pattern { "origin=*-security"; }; ``` 3. **🟡 Auto-reboot без graceful shutdown для сервисов** - `Automatic-Reboot-Time "04:00"` перезагрузит VM даже если там работают арендаторские приложения. - Нет PreRebootScript для graceful shutdown K8s/Docker контейнеров. - Минимум: добавить задержку на systemctl drain или dokumentировать что это требует downtime SLA. 4. **🟢 Minor: heredoc синтаксис** - `cat > ... << 'APT'` — правильно, экранирование переменных не нужно. - Но `APT` как delimiter выглядит странно. Лучше использовать `EOF` (стандартно). 5. **ℹ️ Нет обработки ошибок cloud-init** - Если `systemctl enable --now unattended-upgrades` упадёт, облако-инит не упадёт (не критично, но стоит знать). **РЕКОМЕНДАЦИИ:** - [ ] Явно добавить `Origins-Pattern` для security-only обновлений - [ ] Документировать что это affects только **новые VMs** (в CHANGELOG.md, в комментарии PR) - [ ] Добавить отдельный Ansible playbook для применения к существующим VMs (если требуется) - [ ] Рассмотреть PreRebootScript для graceful shutdown сервисов или изменить время перезагрузки - [ ] Заменить `APT` на `EOF` в heredoc **VERDICT:** Можно мерджить с условиями выше, но **обязательно** задокументировать scope (только новые VMs) и добавить security-only pattern. --- _Automated review by Claude Haiku | advisory, does not block merge_
claude merged commit 45806bc13f into main 2026-02-16 12:03:04 +01:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: claude/infrastructure#73
No description provided.