1. Lựa chọn Backend Mã hóa cho PostgreSQL
Trong môi trường phân tán, việc chọn backend mã hóa quyết định tính an toàn và hiệu năng. Chúng ta có 3 lựa chọn chính: sử dụng thư viện mã hóa nội bộ, dùng OpenSSL hệ thống, hoặc kết nối với HSM (Hardware Security Module).
Đối với yêu cầu TDE (Transparent Data Encryption) cho dữ liệu nghỉ (Data at Rest) trên PostgreSQL, phương án thực tế nhất và được hỗ trợ tốt nhất qua extension là sử dụng pgcrypto kết hợp với OpenSSL của hệ điều hành để tạo Master Key, sau đó dùng extension pg_enc (hoặc tương tự) để quản lý khóa cấp dữ liệu.
Chúng ta sẽ loại bỏ phương án HSM trong phần này để tập trung vào phần mềm, vì HSM yêu cầu phần cứng vật lý và driver đặc thù, tuy nhiên kiến trúc key store sẽ được thiết kế sẵn sàng để tích hợp sau này.
Bước đầu tiên là xác nhận hệ thống đã cài đặt các thư viện cần thiết.
sudo apt-get update && sudo apt-get install -y libpq-dev postgresql-server-dev-14 openssl libssl-dev
Kết quả mong đợi: Các gói phần mềm được cài đặt thành công, không báo lỗi thiếu dependency.
2. Tạo và Quản lý Master Key An toàn
Master Key (Khóa gốc) là thành phần quan trọng nhất. Nếu mất Master Key, toàn bộ dữ liệu trong cluster sẽ không thể khôi phục. Trong kiến trúc phân tán, Master Key cần được lưu trữ ở nơi an toàn, tách biệt khỏi data directory của database.
Chúng ta sẽ tạo Master Key sử dụng thuật toán AES-256-CBC thông qua OpenSSL, lưu trữ dưới dạng file nhị phân và đặt quyền truy cập nghiêm ngặt chỉ cho user postgres.
Tạo thư mục riêng cho key management nằm ngoài data directory của PostgreSQL.
sudo mkdir -p /opt/pg-secure/keys && sudo chown postgres:postgres /opt/pg-secure/keys
Kết quả mong đợi: Thư mục được tạo, quyền sở hữu thuộc về user postgres.
Chuyển sang user postgres để thực hiện tạo key, đảm bảo không bị rò rỉ key qua sudo.
sudo -u postgres openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 -out /opt/pg-secure/keys/master.key -pass pass:YOUR_STRONG_PASSWORD_HERE /dev/urandom
Lưu ý: Thay thế "YOUR_STRONG_PASSWORD_HERE" bằng một chuỗi mật khẩu cực mạnh (ít nhất 32 ký tự, bao gồm chữ hoa, thường, số và ký tự đặc biệt). Trong môi trường sản xuất, bạn nên dùng script để nhập password qua stdin thay vì truyền qua command line.
Đặt quyền truy cập file key chỉ cho chủ sở hữu (mode 600).
sudo -u postgres chmod 600 /opt/pg-secure/keys/master.key
Kết quả mong đợi: File master.key được tạo, chỉ user postgres có quyền đọc/viết.
Để kiểm tra tính toàn vẹn của key, tạo một file checksum (SHA256) để verify sau này.
sudo -u postgres sha256sum /opt/pg-secure/keys/master.key > /opt/pg-secure/keys/master.key.sha256
Kết quả mong đợi: File checksum được tạo, nội dung là chuỗi hash của master key.
3. Cấu hình Extension và Bật TDE
PostgreSQL không có tính năng TDE "out-of-the-box" như Oracle hay SQL Server. Để đạt được TDE, chúng ta cần sử dụng extension pg_enc (hoặc pgcrypto với logic tự viết) để mã hóa các file data hoặc các column cụ thể. Trong phần này, chúng ta sẽ cấu hình để mã hóa toàn bộ data directory bằng cách sử dụng một wrapper script hoặc cấu hình mount point mã hóa (dm-crypt), nhưng để minh họa rõ nhất về mặt logic database, chúng ta sẽ dùng extension pg_enc để mã hóa các file data tablespace.
Tuy nhiên, để mô phỏng TDE cho toàn bộ directory (Data at Rest) theo cách hiệu quả nhất trong PostgreSQL, phương án chuẩn là sử dụng Filesystem Encryption (LUKS) cho data directory, kết hợp với pgcrypto để mã hóa các giá trị nhạy cảm (PII). Ở đây, chúng ta sẽ tập trung vào việc cấu hình pg_enc để mã hóa các file tablespace, đây là bước trung gian quan trọng trước khi tích hợp Raft.
Đầu tiên, cài đặt extension pg_enc vào cluster.
sudo -u postgres psql -c "CREATE EXTENSION pg_enc;"
Kết quả mong đợi: Extension được tạo thành công, hiển thị "CREATE EXTENSION".
Cấu hình biến môi trường để PostgreSQL biết đường dẫn đến Master Key. Chúng ta sẽ tạo một file config riêng trong thư mục pg_enc hoặc đặt trong postgresql.conf.
Chỉnh sửa file cấu hình PostgreSQL để thêm tham số tìm kiếm key.
echo "pg_enc.key_directory = '/opt/pg-secure/keys'" | sudo -u postgres tee -a /var/lib/postgresql/14/main/postgresql.conf
Kết quả mong đợi: Dòng cấu hình được thêm vào file postgresql.conf.
Khởi động lại dịch vụ PostgreSQL để áp dụng cấu hình.
sudo systemctl restart postgresql
Kết quả mong đợi: Dịch vụ khởi động lại thành công, không báo lỗi về quyền truy cập file key.
Tạo một tablespace mới được mã hóa sử dụng extension pg_enc. Đây là bước chứng minh TDE hoạt động.
sudo -u postgres psql -c "CREATE TABLESPACE enc_tbs ENCRYPTION 'AES-256' LOCATION '/var/lib/postgresql/14/main/enc_tbs' OWNER postgres;"
Lưu ý: Tùy vào version của pg_enc, cú pháp có thể thay đổi. Nếu pg_enc yêu cầu key name cụ thể, hãy dùng lệnh: CREATE TABLESPACE enc_tbs LOCATION ... ENCRYPTION KEY 'master.key';
Kết quả mong đợi: Tablespace được tạo thành công, các file trong thư mục /var/lib/postgresql/14/main/enc_tbs sẽ là dữ liệu đã mã hóa.
Verify bằng cách tạo một bảng trong tablespace này và kiểm tra nội dung file thô.
sudo -u postgres psql -c "CREATE TABLE secure_data (id int, secret text) TABLESPACE enc_tbs; INSERT INTO secure_data VALUES (1, 'Secret Data'); SELECT * FROM secure_data;"
Sau đó, kiểm tra file dữ liệu thô trên hệ thống file.
sudo -u postgres strings /var/lib/postgresql/14/main/enc_tbs/base/*/16384 | grep "Secret Data"
Kết quả mong đợi: Lệnh SELECT trả về dữ liệu bình thường, nhưng lệnh strings trên file thô KHÔNG tìm thấy chuỗi "Secret Data" (vì nó đã được mã hóa thành binary noise).
4. Kiểm tra Hiệu năng khi Bật Mã hóa
Việc bật mã hóa toàn bộ data directory (hoặc tablespace) sẽ gây ra overhead cho CPU (do thuật toán mã hóa/giải mã) và I/O (do kích thước block có thể thay đổi). Chúng ta cần benchmark để đảm bảo hệ thống phân tán không bị nghẽn cổ chai.
Sử dụng công cụ pgbench để so sánh hiệu năng giữa tablespace thường và tablespace mã hóa.
Chuẩn bị môi trường test bằng cách tạo bảng trong tablespace mặc định (không mã hóa).
sudo -u postgres psql -c "CREATE TABLE plain_data (id int, secret text); INSERT INTO plain_data SELECT g, md5(random()::text) FROM generate_series(1, 100000) g;"
Thực hiện benchmark đọc/ghi trên bảng không mã hóa.
sudo -u postgres pgbench -T 60 -c 4 -j 4 -f /tmp/select.sql -n -t 1000 -P 1000 plain_data
Lưu ý: Cần tạo file /tmp/select.sql trước với nội dung "SELECT * FROM plain_data LIMIT 1000;".
Thực hiện cùng kịch bản trên bảng đã mã hóa (trong enc_tbs).
sudo -u postgres pgbench -T 60 -c 4 -j 4 -f /tmp/select.sql -n -t 1000 -P 1000 secure_data
Kết quả mong đợi: Bạn sẽ thấy chỉ số transactions per second (tps) trên bảng mã hóa thấp hơn khoảng 10-15% so với bảng không mã hóa, tùy thuộc vào CPU của server.
Kiểm tra tải CPU trong quá trình chạy benchmark để xác định độ trễ do mã hóa.
top -bn1 | grep postgres
Kết quả mong đợi: User CPU usage tăng lên đáng kể khi chạy benchmark trên bảng mã hóa, chứng tỏ CPU đang thực hiện thuật toán AES.
Để giảm thiểu impact, hãy cân nhắc sử dụng hardware acceleration (AES-NI) nếu CPU hỗ trợ, hoặc cân bằng workload giữa các node trong cluster Raft.
5. Verify Kết quả và Chuẩn bị cho Phần 5
Để đảm bảo TDE đã được cấu hình đúng và an toàn trước khi tích hợp với Raft, thực hiện các bước kiểm tra cuối cùng.
1. Kiểm tra tính nhất quán dữ liệu: Đảm bảo dữ liệu có thể đọc/ghi bình thường từ ứng dụng.
sudo -u postgres psql -c "SELECT COUNT(*) FROM secure_data;"
Kết quả mong đợi: Trả về số lượng hàng đúng (ví dụ: 1).
2. Kiểm tra quyền truy cập file: Đảm bảo chỉ user postgres có thể đọc file dữ liệu.
ls -l /var/lib/postgresql/14/main/enc_tbs/base/*/16384
Kết quả mong đợi: Owner là postgres, group là postgres, mode là 0600.
3. Kiểm tra khôi phục Master Key: Giả lập mất key bằng cách đổi tên file key, restart service, và xem lỗi.
sudo mv /opt/pg-secure/keys/master.key /opt/pg-secure/keys/master.key.bak && sudo systemctl restart postgresql
Kết quả mong đợi: PostgreSQL khởi động thất bại hoặc không thể truy cập vào tablespace enc_tbs, báo lỗi "key not found" hoặc "decryption failed".
Khôi phục lại file key để đảm bảo hệ thống hoạt động bình thường.
sudo mv /opt/pg-secure/keys/master.key.bak /opt/pg-secure/keys/master.key && sudo systemctl restart postgresql
Kết quả mong đợi: Dịch vụ khởi động lại thành công, truy cập dữ liệu bình thường.
4. Xác nhận checksum của Master Key không bị thay đổi.
cd /opt/pg-secure/keys && sha256sum -c master.key.sha256
Kết quả mong đợi: Hiển thị "master.key: OK".
Hệ thống TDE đã sẵn sàng. Trong phần tiếp theo, chúng ta sẽ giải quyết bài toán quản lý khóa trong môi trường phân tán Raft, đảm bảo khi node mới join cluster, nó có thể truy cập Master Key một cách an toàn mà không vi phạm nguyên tắc bảo mật.
Điều hướng series:
Mục lục: Series: Xây dựng Database phân tán an toàn với PostgreSQL, Raft và TDE
« Phần 3: Triển khai cơ chế đồng bộ Raft cho tính nhất quán dữ liệu
Phần 5: Kết hợp Raft và TDE: Xử lý khóa mã hóa trong môi trường phân tán »