Runbook: khóa `age` cho backup
Áp dụng cho backup database, media và cấu hình (.env + credentials). Một
recipient trong BACKUP_AGE_PUBLIC_KEY có thể giải mã mọi bản backup được mã
hóa khi recipient đó có mặt. Không để private identity trên VPS.
Người giữ và nơi cất
Phần tiêu đề “Người giữ và nơi cất”| Bản khóa | Người giữ | Nơi cất |
|---|---|---|
| Vận hành hằng ngày | Tên người vận hành chính: PO cần điền trước khi go-live | Password manager của người đó |
| Break-glass | Tên người vận hành chính: PO cần điền trước khi go-live | Bản giấy hoặc USB ngoại tuyến, cất tách biệt với máy vận hành |
S-D8 đã chốt cách custody nhưng chưa cung cấp tên cá nhân. Không đánh dấu AC5/Phase S hoàn tất cho tới khi PO điền tên thật, xác nhận người đó đã nhận cả hai bản, và cập nhật bảng trên.
Tạo hai khóa
Phần tiêu đề “Tạo hai khóa”Thực hiện trên máy người vận hành, không chạy trên VPS. Cất mỗi identity vào nơi bảo vệ phù hợp ngay sau khi tạo; không commit hoặc gửi qua chat/email.
umask 077age-keygen -o age-portal-ops.txtage-keygen -y age-portal-ops.txtLưu dòng age1... do lệnh age-keygen -y in ra. Chỉ public key này được đưa
lên VPS, trong .env:
BACKUP_AGE_PUBLIC_KEY=age1...opsMột khóa là đủ (S-D13, chốt 2026-10-10). Có thể thêm khóa dự phòng
(age1...ops,age1...breakglass, tạo bằng age-keygen như trên) nếu muốn,
nhưng script không bắt buộc. Với một khóa, cất private key ở hai nơi tách
biệt (password manager + USB/giấy): mất nó là không mở được bất kỳ backup
nào. Cả ba job backup_database.sh, backup_media.sh và backup_config.sh
chỉ từ chối chạy khi biến này trống.
Manifest lấy hash trong cùng lượt đọc tạo tar; xác minh hash bằng nội dung file trong archive đã giải mã nếu nguồn trên VPS có thể đã thay đổi sau backup.
Không đặt nội dung private identity (AGE-SECRET-KEY-1...) trong .env,
/opt/web_admin, hoặc /opt/backups. Khóa public sai định dạng khiến backup
thất bại và phát cảnh báo; không xóa recipient đang hoạt động cho tới khi
kiểm tra recipient mới giải mã được một bản backup.
Kiểm tra hàng tháng
Phần tiêu đề “Kiểm tra hàng tháng”Trên máy vận hành, dùng thư mục backup đã kéo về máy mã hóa (S-D7), hoặc tải
một bản mã hóa về trước khi chạy. Xác minh bằng identity (và từng khóa dự phòng nếu có), để file giải
mã chỉ tồn tại tạm trong thư mục riêng quyền 700:
umask 077mkdir -m 700 -p ~/portal-key-checkage -d -i age-portal-ops.txt -o ~/portal-key-check/config.tar \ /path/to/config_YYYYMMDD_HHMMSS.tar.agetar -tf ~/portal-key-check/config.tarrm -f ~/portal-key-check/config.tar# Nếu có cấu hình khóa dự phòng, lặp lại với identity đó.Kết quả phải liệt kê .env, docker-compose.prod.yml, nginx/,
crontab.txt, và các credential đang dùng. Lặp lại với bản DB hoặc media
nếu cần kiểm tra đủ loại artifact. Xóa thư mục tạm sau khi xác minh. S.7 sẽ
lặp bài kiểm tra này trong diễn tập khôi phục hằng quý.
Luân chuyển recipient
Phần tiêu đề “Luân chuyển recipient”- Tạo identity mới trên máy người vận hành và chuyển custody an toàn cho người giữ đã được PO chỉ định.
- Thêm public key mới vào
BACKUP_AGE_PUBLIC_KEY, phân tách bằng dấu phẩy; giữ recipient cũ trong danh sách ít nhất 30 ngày (S-D3). - Tạo backup DB, media, config mới và giải mã thử từng loại bằng identity mới.
- Sau khi đủ 30 ngày và kiểm tra thành công, gỡ recipient cũ khỏi
.env. Chỉ hủy identity cũ khi mọi bản mã hóa bằng nó đã hết hạn, bao gồm bản đã kéo về máy người vận hành.
Nếu nghi lộ private key: coi toàn bộ backup 30 ngày gần nhất có thể bị đọc,
thêm recipient mới và loại key bị lộ ngay, sau đó rotate secrets trong .env
theo Task F.3. Đặc
biệt, không đổi MFA_ENCRYPTION_KEY đơn lẻ: cần quy trình migrate và mã hóa
lại MFA secret trong database như Task F.3 mô tả.
Mất khóa
Phần tiêu đề “Mất khóa”Nếu mất một identity, dùng identity còn lại để giải mã backup mới nhất, tạo identity thay thế, cập nhật recipient và xác minh như quy trình luân chuyển. Nếu mất cả hai, backup hiện có không thể giải mã; phải dựng lại secrets và credential bên thứ ba theo quy trình khôi phục. Báo cho PO trước khi tuyên bố khả năng khôi phục.
Áp dụng cho Portal v1.2.2