Mã hóa ổ đĩa Linux với LUKS: Bảo vệ dữ liệu khi server bị mất hoặc bị đánh cắp

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Khi bảo mật mạng không đủ — vấn đề từ physical access

Mình từng bị brute-force SSH và phải xử lý gấp lúc nửa đêm. Sau sự cố đó, mình setup firewall, fail2ban, đổi port SSH — đủ thứ. Nhưng có một kịch bản mình hay bỏ qua: chuyện gì xảy ra nếu ai đó cầm vật lý ổ cứng của server đi?

Với VPS, rủi ro này nghe có vẻ xa vời. Nhưng với server bare-metal đặt tại cơ quan, colocation, hoặc home server — đây là mối đe dọa thật. Không cần crack password root, không cần bypass firewall. Chỉ cần tháo ổ cứng ra, cắm vào máy khác, mount lên là đọc được hết.

Đó là lý do LUKS (Linux Unified Key Setup) ra đời. Dữ liệu trên partition được mã hóa AES-256 ở tầng block device — nghĩa là ngay cả OS cũng không biết gì khi chưa unlock. Không có passphrase hoặc keyfile, ổ cứng chỉ là một đống byte ngẫu nhiên — cắm vào máy nào cũng vậy.

Cài đặt cryptsetup

cryptsetup là package quản lý LUKS. Ubuntu thường cài sẵn; các distro khác thêm một lệnh là xong:

# Ubuntu / Debian
sudo apt update && sudo apt install cryptsetup -y

# CentOS / RHEL / Rocky Linux
sudo dnf install cryptsetup -y

# Kiểm tra version
cryptsetup --version
# cryptsetup 2.6.1

Kernel module dm-crypt cần được load. Kiểm tra nhanh:

lsmod | grep dm_crypt
# Nếu rỗng thì load thủ công:
sudo modprobe dm-crypt

Cấu hình LUKS từng bước

Bước 1 — Chuẩn bị partition hoặc ổ đĩa

Giả sử mình có một ổ đĩa phụ /dev/sdb hoặc partition /dev/sdb1 cần mã hóa. Dùng lsblk để xác định đúng thiết bị trước — lệnh cryptsetup luksFormat sẽ xóa sạch dữ liệu cũ, không có undo.

lsblk
# NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
# sda      8:0    0   50G  0 disk
# └─sda1   8:1    0   50G  0 part /
# sdb      8:16   0   20G  0 disk   ← đây là ổ cần mã hóa

Bước 2 — Format partition với LUKS

sudo cryptsetup luksFormat /dev/sdb

Lệnh này hỏi xác nhận YES (chữ hoa) và yêu cầu nhập passphrase. Passphrase này không thể khôi phục nếu quên — dùng passphrase đủ mạnh (20+ ký tự) và lưu vào password manager ngay.

Nếu muốn chỉ định rõ thuật toán mã hóa:

# AES-256 với XTS mode — mặc định trên cryptsetup >= 2.x
sudo cryptsetup luksFormat --type luks2 \
  --cipher aes-xts-plain64 \
  --key-size 512 \
  --hash sha256 \
  /dev/sdb

Bước 3 — Mở encrypted volume

Format xong, LUKS đã mã hóa partition nhưng chưa thể dùng được. Cần “unlock” trước — luksOpen giải mã và ánh xạ partition vào một block device ảo tại /dev/mapper/<tên>:

# "data_encrypted" là tên tùy chọn — sẽ xuất hiện tại /dev/mapper/data_encrypted
sudo cryptsetup luksOpen /dev/sdb data_encrypted
# Nhập passphrase...

# Kiểm tra
ls -la /dev/mapper/data_encrypted
# lrwxrwxrwx 1 root root 7 ... /dev/mapper/data_encrypted -> ../dm-0

Bước 4 — Format filesystem và mount

Từ đây, /dev/mapper/data_encrypted trông và hoạt động y hệt partition thường — format filesystem, mount, dùng bình thường:

# Format ext4
sudo mkfs.ext4 /dev/mapper/data_encrypted

# Tạo mount point
sudo mkdir -p /mnt/secure_data

# Mount
sudo mount /dev/mapper/data_encrypted /mnt/secure_data

# Kiểm tra
df -h /mnt/secure_data
# /dev/mapper/data_encrypted   20G  45M   19G   1% /mnt/secure_data

Bước 5 — Cấu hình auto-mount khi khởi động

Đây là phần nhiều người bỏ qua. Để LUKS volume tự mount sau reboot, cần cấu hình hai file: /etc/crypttab/etc/fstab.

Trước tiên, lấy UUID của partition gốc (không phải device mapper):

sudo blkid /dev/sdb
# /dev/sdb: UUID="a1b2c3d4-e5f6-7890-abcd-ef1234567890" TYPE="crypto_LUKS"

Thêm vào /etc/crypttab:

sudo nano /etc/crypttab
# <tên_mapper>     <thiết_bị>                                  <keyfile>  <options>
data_encrypted   UUID=a1b2c3d4-e5f6-7890-abcd-ef1234567890   none       luks

Với none ở cột keyfile, hệ thống sẽ hỏi passphrase khi boot (tại console). Nếu muốn dùng keyfile tự động (không cần nhập tay):

# Tạo keyfile 4096-byte ngẫu nhiên
sudo dd if=/dev/urandom of=/root/luks_keyfile bs=4096 count=1
sudo chmod 400 /root/luks_keyfile

# Thêm keyfile vào LUKS (vẫn giữ passphrase cũ làm backup)
sudo cryptsetup luksAddKey /dev/sdb /root/luks_keyfile

# Cập nhật crypttab
# data_encrypted   UUID=...   /root/luks_keyfile   luks

Sau đó thêm vào /etc/fstab:

sudo nano /etc/fstab
/dev/mapper/data_encrypted   /mnt/secure_data   ext4   defaults   0   2

Kiểm tra và giám sát

Xem trạng thái LUKS

# Thông tin chi tiết về volume
sudo cryptsetup luksDump /dev/sdb
# LUKS header information
# Version:        2
# Epoch:          3
# Metadata area:  16384 [bytes]
# Keyslots area:  16744448 [bytes]
# UUID:           a1b2c3d4-...
# Label:          (no label)
# Subsystem:      (no subsystem)
# Flags:          (no flags)
# ...
# Keyslots:
#  0: luks2   ← passphrase
#  1: luks2   ← keyfile (nếu đã thêm)

# Trạng thái device mapper
sudo cryptsetup status data_encrypted
# /dev/mapper/data_encrypted is active.
#   type:    LUKS2
#   cipher:  aes-xts-plain64
#   keysize: 512 bits
#   key location: keyring
#   device:  /dev/sdb
#   ...

Backup LUKS header — bước bắt buộc

LUKS header nằm ở vùng đầu partition — nơi lưu metadata mã hóa, key slot, và salt. Bad sector đúng vùng đó, hay lỡ tay dd vào sai device, là xong. Dữ liệu mất vĩnh viễn dù passphrase vẫn đúng. Backup ngay sau khi setup, đừng để sau:

sudo cryptsetup luksHeaderBackup /dev/sdb \
  --header-backup-file /root/luks_header_backup_sdb.img

# Lưu file này ra ngoài server (USB, S3, encrypted cloud storage...)
# Kiểm tra backup hợp lệ
sudo cryptsetup luksDump /root/luks_header_backup_sdb.img

Đóng volume khi không dùng

# Unmount trước
sudo umount /mnt/secure_data

# Đóng LUKS
sudo cryptsetup luksClose data_encrypted

# Lúc này /dev/mapper/data_encrypted biến mất
# Ổ đĩa trở về trạng thái encrypted hoàn toàn

Quản lý passphrase — thêm, xóa, đổi

LUKS hỗ trợ tối đa 8 key slot — tức là có thể set nhiều passphrase hoặc keyfile khác nhau cùng lúc:

# Thêm passphrase mới (ví dụ: passphrase recovery cho team)
sudo cryptsetup luksAddKey /dev/sdb

# Xóa một passphrase cũ
sudo cryptsetup luksRemoveKey /dev/sdb

# Kiểm tra key slot nào đang dùng
sudo cryptsetup luksDump /dev/sdb | grep -E "Keyslots|[0-9]+:"

Một số điểm thực tế cần nhớ

  • Performance overhead: AES-NI (hardware acceleration) có trên hầu hết CPU từ 2010 trở đi. Kiểm tra bằng grep aes /proc/cpuinfo. Nếu có, overhead mã hóa gần như không đáng kể — benchmark thực tế thường dưới 3% throughput so với không mã hóa.
  • LUKS1 vs LUKS2: Dùng LUKS2 (mặc định từ cryptsetup 2.x) — hỗ trợ Argon2 key derivation, chống brute-force tốt hơn LUKS1.
  • Swap partition: RAM dump ra swap là plaintext. Ví dụ thực tế: SSH private key đang dùng trong memory, nếu bị swap ra /dev/sda3 thì ai có ổ cứng đọc được luôn. Dùng zram hoặc mã hóa swap riêng để tránh kịch bản này.
  • Full disk encryption vs partition encryption: Bài này hướng dẫn mã hóa partition dữ liệu (data partition). Mã hóa toàn bộ ổ (bao gồm /) phức tạp hơn và thường làm khi cài OS mới.

Từ cái đêm chạy vá SSH đó, mình không còn để security là việc hẹn lại. LUKS là một trong những thứ mình setup ngay khi deploy server mới có lưu trữ dữ liệu quan trọng. Mất 15 phút setup, đổi lại yên tâm hoàn toàn khi nghĩ đến kịch bản ổ cứng rơi vào tay người khác.

Share: