Bài 57. (Lab) Sao lưu, khôi phục và kiểm thử restore
Khóa học CompTIA Security+ SY0-801 · Phần 3: Kiến trúc bảo mật · Bài 57 · 🎯 Objective 3.4 · ⏱️ Thực hành khoảng 2 giờ · 🧪 Có lab · 📝 5 câu bài tập cuối bài
🎯 Mục tiêu bài học
- Thực hành sao lưu full, incremental và differential bằng
tar, rồi khôi phục theo đúng chuỗi bản sao lưu. - Sao lưu có mã hóa và loại bỏ trùng lặp bằng restic, kiểm tra tính toàn vẹn kho sao lưu.
- Minh họa ý tưởng bản sao lưu bất biến bằng thuộc tính chống xóa của hệ thống tệp, và hiểu giới hạn của nó.
- Giả lập sự cố, khôi phục và đo thời gian, đối chiếu hash để chứng minh dữ liệu khôi phục đúng.
- Viết một script kiểm thử khôi phục định kỳ và ghi log kết quả.
📎 Vị trí trong đề thi: lab này biến Bài 54 (sao lưu, 3-2-1, immutable, restoration testing) và Bài 55 (RTO, RPO) thành thao tác thật. Bạn sẽ đo được một con số RTO thực tế và thấy tận mắt RPO thực tế là dữ liệu tạo ra sau lần sao lưu cuối.
⚠️ An toàn khi thực hành: chỉ làm trên máy ảo do chính bạn dựng. Lab có lệnh định dạng ổ đĩa (
mkfs) và lệnh xóa file: hãy kiểm tra kỹ tên thiết bị bằnglsblktrước khi chạy, và tuyệt đối không chạy trên máy thật chứa dữ liệu quan trọng. Phần "giả lập ransomware" chỉ đổi tên và ghi đè vài file mẫu của bạn, không phải mã độc.
💡 Liên hệ thực tế: lần đầu tiên thử khôi phục
Sau sự cố ở Bài 54 và cuộc họp về RTO, RPO ở Bài 55, chị Lan quyết định làm đúng thứ tự: thử khôi phục trước, tin tưởng sau. Nam dựng một máy chủ thử nghiệm với một ổ đĩa sao lưu riêng, sao lưu dữ liệu mẫu, rồi cố tình làm hỏng nó. Anh muốn trả lời ba câu hỏi bằng số liệu thật: dữ liệu có về đủ không, mất bao lâu, và mất bao nhiêu dữ liệu. Đây là tình huống minh họa, không phải vụ việc có thật.
🧪 Hình 57a. Năm bước của bài lab; bước kiểm chứng bằng hash mới là bằng chứng sao lưu dùng được.
🧰 Chuẩn bị
Bạn cần 1 máy ảo Ubuntu Server (VirtualBox hoặc VMware) với 2 ổ đĩa ảo: ổ hệ điều hành và một ổ thứ hai khoảng 5 GB đóng vai phương tiện sao lưu riêng (tương ứng "2 loại phương tiện" trong quy tắc 3-2-1). Máy ảo cần ra được Internet để cài restic. Mở một shell quyền root cho cả bài (chỉ trên VM lab):
bash
sudo -i
💡 Muốn thực hành thêm khía cạnh "ngoài site", bạn có thể dựng máy ảo thứ hai làm kho từ xa và dùng restic qua SFTP (
restic -r sftp:user@host:/duong/dan/repo init). Phần này là tùy chọn và không bắt buộc cho bài lab.
💽 Phần 1: Chuẩn bị ổ sao lưu
bash
lsblk # xác định ổ mới, trống (thường là /dev/sdb) mkfs.ext4 /dev/sdb # CẨN THẬN: chỉ chạy trên ổ trống của VM lab mkdir -p /mnt/backup mount /dev/sdb /mnt/backup df -h /mnt/backup
🗃️ Phần 2: Tạo dữ liệu mẫu và ghi hash
bash
mkdir -p /srv/data && cd /srv/data
for i in $(seq 1 20); do echo "invoice $i" > invoice-$i.txt; done
head -c 2M /dev/urandom > report.bin
cd /srv
find data -type f -exec sha256sum {} + | sort -k2 > /srv/manifest-v1.sha256
sha256sum --quiet -c /srv/manifest-v1.sha256 && echo "HASH KHOP"
File manifest-v1.sha256 là bản ghi băm của dữ liệu (khái niệm hash ở Bài 10). Về sau, so khớp bản khôi phục với manifest này là cách chứng minh dữ liệu về đúng từng byte. Manifest nằm ngoài thư mục /srv/data để không bị sao lưu lẫn vào dữ liệu.
🗂️ Phần 3: Sao lưu full, incremental, differential bằng tar
GNU tar hỗ trợ sao lưu tăng dần qua file snapshot (.snar) ghi nhớ trạng thái lần sao lưu trước.
Ngày 1: full (level 0). Chưa có file .snar nên tar sao lưu toàn bộ:
bash
mkdir -p /mnt/backup/tar
tar --listed-incremental=/mnt/backup/tar/data.snar \
-czf /mnt/backup/tar/full-0.tar.gz -C /srv data
cp /mnt/backup/tar/data.snar /mnt/backup/tar/data.level0.snar # giữ mốc full để làm differential
Ngày 2: thay đổi dữ liệu rồi sao lưu incremental #1.
bash
echo "invoice 21" > /srv/data/invoice-21.txt
echo "chinh sua" >> /srv/data/invoice-1.txt
rm /srv/data/invoice-2.txt
tar --listed-incremental=/mnt/backup/tar/data.snar \
-czf /mnt/backup/tar/incr-1.tar.gz -C /srv data
Ngày 3: thay đổi tiếp, sao lưu incremental #2 và differential.
bash
echo "invoice 22" > /srv/data/invoice-22.txt
# Incremental: so với lần sao lưu gần nhất (file data.snar đã được cập nhật sau Ngày 2)
tar --listed-incremental=/mnt/backup/tar/data.snar \
-czf /mnt/backup/tar/incr-2.tar.gz -C /srv data
# Differential: so với lần FULL, nên dùng lại bản sao của mốc level 0
cp /mnt/backup/tar/data.level0.snar /mnt/backup/tar/data.diff.snar
tar --listed-incremental=/mnt/backup/tar/data.diff.snar \
-czf /mnt/backup/tar/diff-2.tar.gz -C /srv data
cd /srv
find data -type f -exec sha256sum {} + | sort -k2 > /srv/manifest-v2.sha256
ls -lh /mnt/backup/tar
Quan sát kích thước: incr-2 chỉ chứa thay đổi của Ngày 3, còn diff-2 chứa mọi thay đổi từ lần full (cả Ngày 2 lẫn Ngày 3), nên lớn hơn.
🔗 Hình 57b. Số bộ cần khi khôi phục phụ thuộc kiểu sao lưu đã chọn.
Khôi phục bằng chuỗi incremental (đúng thứ tự: full, rồi từng incremental). Tùy chọn --listed-incremental=/dev/null cho tar biết đây là khôi phục từ bản tăng dần, nhờ đó các file đã xóa cũng được xử lý đúng:
bash
mkdir -p /restore/chain tar -xzf /mnt/backup/tar/full-0.tar.gz --listed-incremental=/dev/null -C /restore/chain tar -xzf /mnt/backup/tar/incr-1.tar.gz --listed-incremental=/dev/null -C /restore/chain tar -xzf /mnt/backup/tar/incr-2.tar.gz --listed-incremental=/dev/null -C /restore/chain cd /restore/chain && sha256sum --quiet -c /srv/manifest-v2.sha256 && echo "CHAIN KHOP" ls /restore/chain/data/invoice-2.txt # mong đợi: không tồn tại (đã xóa ở Ngày 2)
Khôi phục bằng differential (chỉ full + differential mới nhất):
bash
mkdir -p /restore/diff tar -xzf /mnt/backup/tar/full-0.tar.gz --listed-incremental=/dev/null -C /restore/diff tar -xzf /mnt/backup/tar/diff-2.tar.gz --listed-incremental=/dev/null -C /restore/diff cd /restore/diff && sha256sum --quiet -c /srv/manifest-v2.sha256 && echo "DIFF KHOP"
Hai cách cho cùng kết quả, nhưng differential chỉ cần 2 bộ, incremental cần 3 bộ và sai thứ tự là hỏng.
🔐 Phần 4: Sao lưu có mã hóa bằng restic
restic là công cụ sao lưu mã nguồn mở: mã hóa dữ liệu trong kho, loại bỏ trùng lặp và lưu theo snapshot nên mỗi lần sao lưu trông như một bản đầy đủ nhưng chỉ lưu phần thay đổi.
bash
apt update && apt install -y restic
echo 'MatKhauLab-DoiNgay!' > /root/.restic-pass && chmod 600 /root/.restic-pass
export RESTIC_REPOSITORY=/mnt/backup/restic-repo
export RESTIC_PASSWORD_FILE=/root/.restic-pass
restic init
restic backup /srv/data
echo "invoice 23" > /srv/data/invoice-23.txt
cd /srv && find data -type f -exec sha256sum {} + | sort -k2 > /srv/manifest-v3.sha256
restic backup /srv/data
restic snapshots
restic check
⚠️ Mất mật khẩu kho là mất toàn bộ dữ liệu sao lưu, vì dữ liệu đã mã hóa. Ngoài lab, hãy lưu mật khẩu ở nơi tách biệt và an toàn (ví dụ két mật khẩu của doanh nghiệp hoặc bản in cất kho), và đưa việc này vào quy trình khôi phục thảm họa (Bài 55).
restic check kiểm tra tính toàn vẹn của kho sao lưu. Muốn kiểm tra sâu hơn, có thể đọc lại dữ liệu thật (ví dụ restic check --read-data-subset=10% kiểm tra một phần dữ liệu để cân bằng giữa độ kỹ và thời gian).
Chính sách lưu giữ (retention) cũng làm được ngay:
bash
restic forget --keep-daily 7 --keep-weekly 4 --prune
🔒 Phần 5: Minh họa bản sao lưu "bất biến"
Hệ tệp ext4 có thuộc tính immutable khiến file không sửa, xóa hay đổi tên được, kể cả bởi root, cho đến khi thuộc tính bị gỡ:
bash
chattr +i /mnt/backup/tar/full-0.tar.gz lsattr /mnt/backup/tar/full-0.tar.gz rm /mnt/backup/tar/full-0.tar.gz # mong đợi: Operation not permitted chattr -i /mnt/backup/tar/full-0.tar.gz # gỡ thuộc tính khi làm xong
Hãy chú ý giới hạn: root vẫn gỡ được thuộc tính này, nên kẻ tấn công chiếm quyền root cũng gỡ được. Đây chỉ là bản minh họa ý tưởng. Sao lưu bất biến thật (WORM, object lock) được thực thi ở tầng lưu trữ hoặc dịch vụ, nơi ngay cả quản trị viên cũng không thể xóa trước khi hết thời gian lưu giữ đã đặt. Khi chọn giải pháp thật, hãy kiểm tra đúng điểm này.
💥 Phần 6: Giả lập sự cố, khôi phục và đo RTO
Trước khi gây sự cố, tạo một file sau lần sao lưu cuối để quan sát RPO:
bash
echo "invoice 24 - chua sao luu" > /srv/data/invoice-24.txt
Giả lập "ransomware" (chỉ ghi đè và đổi tên file mẫu):
bash
for f in /srv/data/*.txt; do echo "ENCRYPTED" > "$f"; mv "$f" "$f.locked"; done ls /srv/data | head
Khôi phục từ restic và đo thời gian:
bash
time restic restore latest --target /restore/after-incident cd /restore/after-incident/srv && sha256sum --quiet -c /srv/manifest-v3.sha256 && echo "RESTORE KHOP" ls /restore/after-incident/srv/data/invoice-24.txt # mong đợi: không có
Ghi lại hai kết quả:
| Chỉ số | Cách đo trong lab | Ý nghĩa với Bài 55 |
|---|---|---|
| Thời gian khôi phục | Kết quả real của lệnh time |
So với RTO mục tiêu: lab nhỏ nên rất ngắn, nhưng hãy nhân theo dung lượng thật để ước lượng |
| Dữ liệu mất | invoice-24.txt không có trong bản khôi phục |
Đó chính là RPO thực tế: dữ liệu tạo ra từ lần sao lưu cuối tới lúc sự cố |
⏰ Phần 7: Script kiểm thử khôi phục định kỳ
Tạo /usr/local/bin/restore-test.sh:
bash
#!/usr/bin/env bash set -euo pipefail export RESTIC_REPOSITORY=/mnt/backup/restic-repo export RESTIC_PASSWORD_FILE=/root/.restic-pass LOG=/var/log/restore-test.log TARGET=$(mktemp -d /tmp/restore-test.XXXXXX) trap 'echo "$(date -Is) RESTORE TEST FAILED" >> "$LOG"; rm -rf "$TARGET"' ERR START=$(date +%s) restic check restic restore latest --target "$TARGET" > /dev/null diff -r --brief "$TARGET/srv/data" /srv/data END=$(date +%s) echo "$(date -Is) RESTORE TEST OK in $((END-START))s" >> "$LOG" rm -rf "$TARGET"
bash
chmod +x /usr/local/bin/restore-test.sh /usr/local/bin/restore-test.sh && tail -1 /var/log/restore-test.log (crontab -l 2>/dev/null; echo "0 3 * * 0 /usr/local/bin/restore-test.sh") | crontab -
Cron chạy script vào 3 giờ sáng Chủ nhật hằng tuần. Lưu ý: script này so sánh bản khôi phục với dữ liệu đang chạy, nên chỉ đúng khi dữ liệu không đổi kể từ lần sao lưu cuối. Trong môi trường thật, hãy so với một manifest hash đáng tin hoặc dùng bộ dữ liệu kiểm thử cố định, và gửi cảnh báo khi kiểm thử thất bại.
✅ Bảng kiểm tra kết quả
| Kiểm tra | Kết quả mong đợi |
|---|---|
sha256sum -c trên /restore/chain |
Khớp với manifest-v2 |
invoice-2.txt trong bản khôi phục incremental |
Không tồn tại (đã xóa ở Ngày 2) |
sha256sum -c trên /restore/diff |
Khớp với manifest-v2 |
restic snapshots |
Có ít nhất 2 snapshot |
restic check |
Không báo lỗi |
rm file đã chattr +i |
Operation not permitted |
| Khôi phục sau sự cố | Khớp manifest-v3, không có invoice-24.txt |
restore-test.sh |
Ghi dòng RESTORE TEST OK vào log |
🛠️ Lỗi thường gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
sha256sum -c báo không tìm thấy file |
Chạy lệnh sai thư mục | Manifest dùng đường dẫn tương đối data/...: phải cd vào thư mục chứa data (hoặc srv với restic) |
| Khôi phục incremental sai nội dung | Giải nén sai thứ tự hoặc thiếu một bản | Luôn full trước, rồi incremental 1, 2 theo thứ tự |
restic: Fatal: wrong password |
Sai mật khẩu hoặc sai đường dẫn kho | Kiểm tra RESTIC_PASSWORD_FILE và RESTIC_REPOSITORY (biến môi trường mất khi mở shell mới) |
mkfs.ext4 báo thiết bị đang bận |
Chọn nhầm ổ hoặc ổ đã mount | Dừng lại, kiểm tra lsblk; chỉ định dạng ổ trống mới |
diff -r trong script báo khác biệt |
Dữ liệu đổi sau lần sao lưu cuối | Sao lưu lại trước khi kiểm thử, hoặc so với manifest |
🎯 Mẹo làm bài: "Phải áp dụng theo đúng thứ tự full rồi từng bản tăng dần" → incremental. "Chỉ cần full và bản mới nhất" → differential. "Dữ liệu tạo sau lần sao lưu cuối bị mất" → ranh giới RPO. "Đo thời gian thực tế để so với RTO" → restoration testing. "Admin cũng không xóa được trong thời gian lưu giữ" → immutable/WORM (khác với cờ chống xóa có thể gỡ bởi root). "So hash để xác nhận dữ liệu khôi phục đúng" → kiểm tra tính toàn vẹn.
🧠 Áp vào câu chuyện của Nam
| Câu hỏi của chị Lan | Kết quả trong lab |
|---|---|
| "Bản sao lưu có dùng được không?" | Có: hash khôi phục khớp manifest |
| "Mất bao lâu để có lại dữ liệu?" | Đo bằng time, rồi ước lượng theo dung lượng thật so với RTO |
| "Mất bao nhiêu dữ liệu?" | File tạo sau lần sao lưu cuối không có lại: đó là RPO thực tế |
| "Kẻ tấn công có xóa được bản sao lưu không?" | Phải dùng bản bất biến ở tầng lưu trữ, không chỉ cờ chống xóa |
| "Làm sao nhớ kiểm tra thường xuyên?" | Script restore-test chạy định kỳ và ghi log |
📖 Thuật ngữ cần nhớ
| Thuật ngữ | Nghĩa |
|---|---|
| Manifest hash | Danh sách giá trị băm của file, dùng để kiểm tra dữ liệu khôi phục có đúng không. |
.snar |
File snapshot của GNU tar, ghi nhớ trạng thái để sao lưu tăng dần. |
| restic | Công cụ sao lưu mã nguồn mở: mã hóa, loại trùng lặp, lưu theo snapshot. |
| Snapshot (restic) | Một điểm thời gian trong kho sao lưu, có thể khôi phục độc lập. |
| Retention | Chính sách giữ bao nhiêu bản sao lưu trong bao lâu. |
| WORM | Ghi một lần, đọc nhiều lần: nền tảng của sao lưu bất biến. |
| Restoration testing | Thử khôi phục định kỳ để xác nhận bản sao lưu dùng được. |
📌 Tóm tắt nhanh
- Khôi phục incremental cần full + mọi bản incremental theo thứ tự; differential cần full + bản differential mới nhất.
- Sao lưu hiện đại nên mã hóa và có cơ chế kiểm tra toàn vẹn (
restic check); giữ mật khẩu kho ở nơi an toàn, tách biệt. - Cờ
chattr +ichỉ minh họa: bất biến thật phải do tầng lưu trữ thực thi, kể cả quản trị viên cũng không gỡ được trong thời gian lưu giữ. - RTO thực tế đo bằng thời gian khôi phục; RPO thực tế là dữ liệu từ lần sao lưu cuối tới lúc sự cố.
- Đưa kiểm thử khôi phục vào lịch định kỳ và ghi log kết quả.
💬 Hỏi & Đáp nhanh
❓ Vì sao phải dùng --listed-incremental=/dev/null khi khôi phục? Tùy chọn này báo cho tar rằng bạn đang khôi phục từ chuỗi sao lưu tăng dần. Nhờ vậy tar xử lý đúng cả các file đã bị xóa giữa các lần sao lưu, thay vì chỉ ghi chồng file lên thư mục.
❓ Lab này đã đủ quy tắc 3-2-1 chưa? Chưa. Lab có bản gốc và bản sao lưu trên đĩa thứ hai (một phương tiện khác), nhưng chưa có bản ngoài site. Bạn có thể mở rộng bằng kho restic trên máy khác qua SFTP hoặc dịch vụ lưu trữ đám mây.
❓ Có nên so sánh bản khôi phục với dữ liệu đang chạy như script mẫu không? Chỉ trong lab. Ngoài thực tế, dữ liệu sống luôn thay đổi nên phép so sánh sẽ báo sai. Hãy dùng manifest hash lập tại thời điểm sao lưu hoặc một tập dữ liệu kiểm thử cố định.
📝 Bài tập đánh giá
Tự chọn đáp án cho từng câu, rồi đối chiếu với phần đáp án ở cuối bài.
Câu 1. Khi khôi phục từ chuỗi sao lưu incremental bằng tar, thứ tự đúng là gì?
- A. Giải nén bản incremental mới nhất trước, bản full sau cùng
- B. Giải nén các bản theo thứ tự ngẫu nhiên
- C. Giải nén bản full trước, rồi từng bản incremental theo thứ tự thời gian
- D. Chỉ cần giải nén bản full
Câu 2. Vì sao trong lab phải dùng lệnh time khi khôi phục?
- A. Để tăng tốc độ khôi phục
- B. Để đo thời gian khôi phục thực tế và so với RTO mục tiêu
- C. Để mã hóa dữ liệu khôi phục
- D. Để xóa bản sao lưu cũ
Câu 3. Lệnh chattr +i trên một file sao lưu có hạn chế quan trọng nào khi nói về "sao lưu bất biến"?
- A. Root vẫn có thể gỡ thuộc tính này, nên không bảo vệ trước kẻ tấn công có quyền root
- B. Nó làm file bị mã hóa tự động
- C. Nó chỉ hoạt động trên Windows
- D. Nó xóa file sau 24 giờ
Câu 4. Lệnh restic check dùng để làm gì?
- A. Tạo thêm bản sao lưu ngoài site
- B. Giải mã kho sao lưu ra thư mục tạm
- C. Đổi mật khẩu của kho sao lưu
- D. Kiểm tra tính toàn vẹn của kho sao lưu
Câu 5. Trong lab, file invoice-24.txt được tạo sau lần sao lưu cuối và không có trong bản khôi phục. Điều này minh họa khái niệm nào?
- A. RTO thực tế
- B. RPO thực tế: dữ liệu tạo ra sau lần sao lưu cuối bị mất
- C. Failover tự động
- D. Sao lưu differential
👉 Đáp án
Câu 1: C — Phải giải nén bản full trước, sau đó từng bản incremental theo thứ tự thời gian.
Câu 2: B — time cho biết thời gian khôi phục thực tế để so sánh với RTO mục tiêu.
Câu 3: A — Root có thể gỡ thuộc tính này. Sao lưu bất biến thật phải được thực thi ở tầng lưu trữ, nơi ngay cả quản trị viên cũng không xóa được trong thời gian lưu giữ.
Câu 4: D — restic check kiểm tra tính toàn vẹn của kho sao lưu.
Câu 5: B — Dữ liệu tạo sau lần sao lưu cuối không có trong bản khôi phục: đó là RPO thực tế.
📚 Bài viết thuộc khóa học CompTIA Security+ của VNExperts
🧭 Điều hướng
| ⬅️ Bài trước | 🏠 Mục lục khóa học | Bài kế tiếp ➡️ |
|---|---|---|
| Bài 56: (Lab) Mạng phân đoạn với pfSense: DMZ, firewall rule, VPN | Mục lục khóa học CompTIA Security+ | Bài 58: Ôn tập Phần 3 + Quiz tổng hợp 15 câu |