Cấu hình SSL/TLS cho kết nối giữa Client và Object Store
Bước này xác thực danh tính server và mã hóa dữ liệu truyền tải, ngăn chặn tấn công Man-in-the-Middle (MitM) khi client truy cập Object Store.
Chúng ta sẽ tạo chứng tự ký (Self-signed Certificate) bằng OpenSSL. Trong môi trường production, bạn nên thay bằng chứng chỉ từ CA uy tín, nhưng với môi trường nội bộ (internal network), chứng tự ký là đủ để mã hóa.
Đầu tiên, tạo thư mục chứa chứng chỉ và key riêng của PostgreSQL:
sudo mkdir -p /var/lib/postgresql/certs
Kết quả: Thư mục được tạo, chưa có file nào bên trong.
Tạo Private Key (2048 bit RSA) và đặt quyền truy cập chặt chẽ (chỉ owner root hoặc postgres được đọc):
sudo openssl genrsa -out /var/lib/postgresql/certs/postgresql.key 2048
sudo chmod 600 /var/lib/postgresql/certs/postgresql.key
sudo chown postgres:postgres /var/lib/postgresql/certs/postgresql.key
Kết quả: File key được tạo, quyền 600 đảm bảo không ai khác trên server đọc được.
Tạo Certificate Signing Request (CSR) và sau đó là Certificate (CRT) với thời hạn 10 năm:
sudo openssl req -new -key /var/lib/postgresql/certs/postgresql.key -out /var/lib/postgresql/certs/postgresql.csr -subj "/C=VN/ST=HCM/L=District 1/O=ITDept/OU=ObjectStore/CN=objectstore.local/emailAddress=admin@company.com"
sudo openssl x509 -req -days 3650 -in /var/lib/postgresql/certs/postgresql.csr -signkey /var/lib/postgresql/certs/postgresql.key -out /var/lib/postgresql/certs/postgresql.crt
sudo chmod 644 /var/lib/postgresql/certs/postgresql.crt
sudo chown postgres:postgres /var/lib/postgresql/certs/postgresql.crt
Kết quả: File .crt và .key nằm trong thư mục certs, sẵn sàng cho PostgreSQL sử dụng.
Cập nhật cấu hình PostgreSQL để bắt buộc sử dụng SSL (ssl = on) và chỉ định đường dẫn file:
sudo nano /etc/postgresql/16/main/postgresql.conf
Thêm hoặc sửa các dòng sau trong file (giả định version là 16 cho Ubuntu 24.04, điều chỉnh version nếu khác):
ssl = on
ssl_cert_file = '/var/lib/postgresql/certs/postgresql.crt'
ssl_key_file = '/var/lib/postgresql/certs/postgresql.key'
ssl_ciphers = 'HIGH:MEDIUM:!aNULL:!MD5:!RC4:!3DES:!CAMELLIA:256'
ssl_prefer_server_ciphers = on
Kết quả mong đợi: File cấu hình đã lưu, PostgreSQL sẽ yêu cầu kết nối SSL khi khởi động lại.
Khởi động lại dịch vụ PostgreSQL để áp dụng thay đổi:
sudo systemctl restart postgresql
Kết quả mong đợi: Dịch vụ chạy lại mà không báo lỗi (check bằng `systemctl status postgresql`).
Verify kết quả SSL:
psql -h localhost -U postgres -c "SELECT ssl, version();" --no-password
Kết quả mong đợi: Cột `ssl` trả về giá trị `t` (true). Nếu trả về `f`, cấu hình chưa áp dụng.
Thiết lập chính sách IAM và User Role cho truy cập Bucket
Object Store cần phân quyền rõ ràng giữa các user: Admin (toàn quyền), Owner (quản lý bucket), và Reader (chỉ đọc). Chúng ta sẽ sử dụng cơ chế Role của PostgreSQL để ánh xạ vào Object Store.
Tạo user mới cho Object Store với quyền hạn cụ thể. Ở đây tạo user `bucket_owner` có quyền đọc ghi dữ liệu bucket, và user `bucket_reader` chỉ có quyền đọc.
Đăng nhập vào PostgreSQL console để tạo role:
sudo -u postgres psql
Kết quả: Giao diện prompt `postgres=#` xuất hiện.
Thực thi các lệnh SQL để tạo role và phân quyền:
CREATE ROLE bucket_owner WITH LOGIN PASSWORD 'StrongOwnerPass123!' ENCRYPTED;
CREATE ROLE bucket_reader WITH LOGIN PASSWORD 'WeakReaderPass456!' ENCRYPTED;
-- Cấp quyền cho bucket_owner: đọc, ghi, xóa object trong schema object_store
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA object_store TO bucket_owner;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA object_store TO bucket_owner;
-- Cấp quyền cho bucket_reader: chỉ đọc object
GRANT SELECT ON ALL TABLES IN SCHEMA object_store TO bucket_reader;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA object_store TO bucket_reader;
-- Đảm bảo quyền áp dụng cho các bảng mới tạo trong tương lai
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA object_store GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO bucket_owner;
ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA object_store GRANT SELECT ON TABLES TO bucket_reader;
Kết quả mong đợi: Các role được tạo thành công, lệnh trả về `CREATE ROLE`.
Thoát khỏi console PostgreSQL:
\q
Cấu hình file `pg_hba.conf` để cho phép các role này truy cập qua TCP/IP với SSL:
sudo nano /etc/postgresql/16/main/pg_hba.conf
Thêm các dòng sau vào cuối file (trước dòng `local all all peer`):
# Object Store Access Control
hostssl object_store bucket_owner 127.0.0.1/32 md5
hostssl object_store bucket_reader 127.0.0.1/32 md5
# Nếu muốn cho phép truy cập từ mạng nội bộ thay vì localhost
hostssl object_store bucket_owner 192.168.1.0/24 md5
hostssl object_store bucket_reader 192.168.1.0/24 md5
Kết quả mong đợi: File cấu hình đã cập nhật, chỉ cho phép kết nối qua SSL (hostssl) cho các user này.
Reload cấu hình PostgreSQL (không cần restart):
sudo systemctl reload postgresql
Verify kết quả phân quyền:
psql -h localhost -U bucket_owner -d object_store -c "SELECT count(*) FROM buckets;" --password
Kết quả mong đợi: Khi nhập đúng password, query chạy thành công và trả về số lượng bucket.
psql -h localhost -U bucket_reader -d object_store -c "INSERT INTO buckets (name) VALUES ('test');" --password
Kết quả mong đợi: Query bị từ chối với lỗi `permission denied for table buckets`.
Cấu hình Firewall (UFW) để chỉ mở cổng cần thiết
Ubuntu 24.04 sử dụng UFW (Uncomplicated Firewall) mặc định. Chúng ta cần khóa mọi cổng không cần thiết, chỉ mở cổng cho Object Store (giả định là 8000 cho HTTP/S và 5432 cho DB nếu cần truy cập trực tiếp từ ngoài, tuy nhiên tốt nhất là DB chỉ chạy nội bộ).
Đảm bảo UFW đang tắt để tránh khóa chính mình khi cấu hình lần đầu:
sudo ufw status
Kết quả: Nếu thấy `Status: active`, cần reset hoặc cấu hình cẩn thận. Nếu `inactive`, tiến hành bật.
Bật UFW và thiết lập chính sách mặc định là từ chối (deny) tất cả kết nối vào (incoming), cho phép tất cả kết nối ra (outgoing):
sudo ufw default deny incoming
sudo ufw default allow outgoing
Kết quả mong đợi: UFW đã được kích hoạt với chính sách bảo mật cao.
Cho phép SSH (cổng 22) trước tiên để không bị khóa mất quyền truy cập remote:
sudo ufw allow 22/tcp
Kết quả mong đợi: Rule được thêm, SSH vẫn hoạt động.
Mở cổng cho Object Store API. Giả định Object Store chạy trên cổng 8000 (HTTP) và 8443 (HTTPS). Nếu bạn dùng cổng khác, hãy thay số tương ứng:
sudo ufw allow 8443/tcp comment "Object Store HTTPS API"
sudo ufw allow 8000/tcp comment "Object Store HTTP API"
Kết quả mong đợi: Các cổng API được mở. Lưu ý: Nếu đã cấu hình SSL ở phần 1, nên chỉ mở cổng 8443 và chặn 8000.
Bật UFW (nếu chưa bật):
sudo ufw enable
Kết quả mong đợi: System yêu cầu xác nhận `y/n`, nhập `y`. Sau đó thấy thông báo `Firewall is active and enabled on system startup`.
Verify cấu hình Firewall:
sudo ufw status verbose
Kết quả mong đợi: Danh sách các rule hiển thị chỉ có SSH (22), Object Store (8443/8000) và Allow Outgoing. Các cổng khác (như 5432) không được liệt kê trong phần Incoming.
Kiểm tra khả năng kết nối từ client (từ một máy khác hoặc localhost):
curl -k https://localhost:8443/health
Kết quả mong đợi: Trả về JSON health check (ví dụ `{"status":"ok"}`). Nếu dùng cổng 8000 mà chưa mở SSL, có thể thấy kết quả tương tự.
Bảo vệ mật khẩu và Key truy cập trong file cấu hình
File cấu hình của Object Store (thường là `.env`, `config.yaml`, hoặc `application.properties`) chứa thông tin nhạy cảm như `DB_PASSWORD`, `ACCESS_KEY`, `SECRET_KEY`. Việc để file này ở trạng thái đọc được bởi mọi user là lỗ hổng bảo mật nghiêm trọng.
Giả định file cấu hình nằm tại `/opt/object-store/config.env`. Chúng ta sẽ thay thế mật khẩu trực tiếp bằng biến môi trường hoặc file secret, và thiết lập quyền file.
Đầu tiên, kiểm tra file cấu hình hiện tại (mẫu ví dụ):
cat /opt/object-store/config.env
Nội dung mẫu (cần sửa):
DB_HOST=localhost
DB_PORT=5432
DB_NAME=object_store
DB_USER=bucket_owner
DB_PASSWORD=StrongOwnerPass123!
ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Thay đổi quyền truy cập của file này để chỉ owner (ví dụ user `objectstore` hoặc `root`) được đọc, không cho phép user khác (bao gồm cả `postgres` hoặc `www-data` nếu có) đọc nội dung:
sudo chown objectstore:objectstore /opt/object-store/config.env
sudo chmod 600 /opt/object-store/config.env
Kết quả mong đợi: File có quyền 600 (rw-------). Chỉ user `objectstore` và root mới đọc được.
Để tăng cường bảo mật, tốt nhất không lưu mật khẩu trong file text rõ ràng. Chúng ta sẽ sử dụng `secret file` cho password và reference nó trong config.
Tạo file chứa mật khẩu riêng biệt và đặt quyền chặt chẽ:
echo -n 'StrongOwnerPass123!' | sudo tee /opt/object-store/secrets/db_password
sudo chown objectstore:objectstore /opt/object-store/secrets/db_password
sudo chmod 400 /opt/object-store/secrets/db_password
Kết quả mong đợi: File `db_password` được tạo với quyền 400 (r--------), chỉ owner đọc được, không ai viết được.
Cập nhật file `config.env` để đọc password từ file secret thay vì hardcode:
sudo nano /opt/object-store/config.env
Sửa dòng `DB_PASSWORD` thành:
DB_PASSWORD=$(cat /opt/object-store/secrets/db_password)
Kết quả mong đợi: File config không còn chứa chuỗi password rõ ràng, mà là lệnh shell để đọc từ file secret.
Tương tự cho Access Key và Secret Key nếu chúng được lưu trong file:
echo -n 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' | sudo tee /opt/object-store/secrets/secret_key
sudo chmod 400 /opt/object-store/secrets/secret_key
sudo chown objectstore:objectstore /opt/object-store/secrets/secret_key
Verify bảo mật file:
ls -la /opt/object-store/config.env
ls -la /opt/object-store/secrets/
Kết quả mong đợi:
- `config.env`: quyền 600, owner objectstore.
- `db_password` và `secret_key`: quyền 400, owner objectstore.
- Nếu bạn cố gắng dùng `cat` với user khác (ví dụ `sudo -u www-data cat ...`), hệ thống sẽ báo lỗi `Permission denied`.
Khởi động lại dịch vụ Object Store để áp dụng biến môi trường mới:
sudo systemctl restart object-store
Kết quả mong đợi: Dịch vụ khởi động thành công, log không có lỗi liên quan đến authentication.
Điều hướng series:
Mục lục: Series: Triển khai Database Object Store với PostgreSQL và Ubuntu 24.04
« Phần 3: Triển khai phần mềm Object Store dựa trên PostgreSQL
Phần 5: Tạo bucket, upload và quản lý object cơ bản »