Làm chủ Linux PAM: Thiết lập SSH 2FA/MFA và chính sách đăng nhập máy chủ

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Bối cảnh & Vì sao PAM lại quan trọng

Mỗi khi bạn đăng nhập vào một máy chủ Linux qua SSH, chạy lệnh sudo hoặc chuyển đổi người dùng bằng su, PAM (Pluggable Authentication Modules) chính là người gác cổng đứng sau xử lý. Thay vì buộc mọi daemon phải tự viết các cơ chế xác thực riêng, Linux giao toàn bộ nhiệm vụ này cho PAM. Nó đóng vai trò như một cầu nối dạng module trung gian giữa các dịch vụ hướng tới người dùng và các backend bảo mật bên dưới.

PAM tổ chức các luồng xác thực thành bốn cơ chế (facility) riêng biệt:

  • auth: Xác nhận danh tính, thông thường bằng cách yêu cầu nhập mật khẩu hoặc mã xác thực TOTP.
  • account: Kiểm tra tính hợp lệ của quyền truy cập. Cơ chế này xác minh thời hạn mật khẩu, khung thời gian hoạt động và trạng thái khóa của tài khoản.
  • password: Quản lý việc cập nhật thông tin xác thực, bao gồm xoay vòng token và áp dụng độ phức tạp của mật khẩu.
  • session: Xử lý các tác vụ thiết lập và dọn dẹp xoay quanh một phiên shell, chẳng hạn như mount thư mục lưu trữ của người dùng, áp dụng giới hạn ulimit và cập nhật audit log.

Chỉ dựa vào SSH key là phương pháp phổ biến tiêu chuẩn. Tuy nhiên, một private key không đặt mật khẩu bảo vệ (passphrase) trên chiếc laptop bị thất lạc có thể khiến toàn bộ hạ tầng của bạn bị lộ lọt. Việc bổ sung module Time-based One-Time Password (TOTP) vào stack auth của PAM sẽ giải quyết triệt để rủi ro này. Kẻ tấn công khi đó sẽ cần cả file private key lẫn mã số gồm sáu chữ số thay đổi theo thời gian trên thiết bị di động.

Trên một cụm gồm các node Ubuntu 2 vCPU chạy tác vụ edge, cấu hình này xác minh các token cục bộ chỉ trong khoảng 8 đến 12 mili-giây. Con số này giúp loại bỏ hoàn toàn tình trạng trễ đột biến lên tới 250ms mà chúng tôi từng gặp phải trước đây khi phải truy vấn các directory server từ xa trong mỗi lần bắt tay kết nối.

Cài đặt

Chúng ta sẽ sử dụng gói mã nguồn mở Google Authenticator PAM. Gói này triển khai chuẩn RFC 6238 và hoạt động ổn định, tương thích tốt với các ứng dụng xác thực phổ biến như Aegis, 1Password, Google Authenticator và Bitwarden.

Debian và Ubuntu

Cập nhật danh sách kho lưu trữ và tải về module PAM:

sudo apt update
sudo apt install -y libpam-google-authenticator

RHEL, Rocky Linux và AlmaLinux

Kích hoạt kho lưu trữ EPEL trước, sau đó tiến hành cài đặt gói:

sudo dnf install -y epel-release
sudo dnf install -y google-authenticator

Cấu hình

Để khóa chặt SSH, bạn cần thực hiện ba bước cụ thể: tạo secret key cho người dùng, cập nhật định nghĩa dịch vụ PAM và cấu hình lại daemon OpenSSH.

Bước 1: Tạo khóa bí mật TOTP

Đăng nhập bằng tài khoản người dùng thông thường (non-root) cần truy cập SSH. Chạy trình hướng dẫn khởi tạo trực tiếp trên terminal của bạn:

google-authenticator -t -d -f -r 3 -R 30 -q

Dưới đây là ý nghĩa hoạt động của các cờ lệnh này:

  • -t: Cấu hình mã token dựa trên thời gian tiêu chuẩn (TOTP) thay vì mã token dựa trên bộ đếm (HOTP).
  • -d: Ngăn chặn tái sử dụng token nhằm vô hiệu hóa các cuộc tấn công phát lại (replay attack).
  • -f: Ghi trạng thái trực tiếp vào file ~/.google_authenticator mà không cần hỏi đường dẫn file.
  • -r 3 -R 30: Áp dụng giới hạn tốc độ (rate-limiting). Người dùng chỉ được thử xác thực tối đa 3 lần trong mỗi 30 giây.
  • -q: Chạy ở chế độ im lặng (quiet), bỏ qua các lời nhắc xác nhận tương tác trong quá trình tạo khóa.

Tiện ích sẽ xuất ra một mã bí mật base32, một mã QR dạng ASCII và năm mã dự phòng khẩn cấp. Hãy thêm khóa bí mật này vào ứng dụng authenticator trên điện thoại của bạn. Lưu các mã dự phòng gồm 8 chữ số vào một trình quản lý mật khẩu ngoại tuyến như KeePassXC; đây là chiếc phao cứu sinh duy nhất của bạn nếu điện thoại bị mất hoặc hỏng.

Bước 2: Cấu hình PAM cho SSH

Mở file cấu hình PAM của SSH bằng trình soạn thảo văn bản:

sudo nano /etc/pam.d/sshd

Hầu hết các cấu hình mặc định đều có sẵn lời nhắc nhập mật khẩu tiêu chuẩn. Trên Debian và Ubuntu, hãy tìm dòng @include common-auth. Trên RHEL, tìm dòng auth substack password-auth. Nếu mục tiêu của bạn là kết hợp SSH key cùng với TOTP—mà không cần hỏi mật khẩu người dùng Linux—hãy comment dòng include đó:

# Vô hiệu hóa việc dùng lại mật khẩu UNIX tiêu chuẩn
# @include common-auth

Tiếp theo, thêm module authenticator vào cuối file:

auth required pam_google_authenticator.so nullok

Tham số nullok cho phép người dùng vẫn đăng nhập bình thường khi họ chưa tạo mã token TOTP. Tùy chọn này giúp tránh nguy cơ bị khóa tài khoản hàng loạt trong quá trình triển khai ban đầu. Khi toàn bộ đội ngũ của bạn đã quét mã QR thành công, hãy xóa bỏ nullok để bắt buộc áp dụng MFA trên toàn hệ thống.

Bước 3: Bắt buộc xác thực SSH Key + MFA trong OpenSSH

Bây giờ, hãy chỉnh sửa cấu hình daemon trong /etc/ssh/sshd_config:

sudo nano /etc/ssh/sshd_config

Thiết lập các chỉ thị sau để đồng bộ OpenSSH với PAM:

# Bật PAM và các lời nhắc nhập liệu tương tác
UsePAM yes
KbdInteractiveAuthentication yes
PasswordAuthentication no

# Yêu cầu xác thực public key TRƯỚC, sau đó mới tới mã TOTP qua PAM
AuthenticationMethods publickey,keyboard-interactive

Lưu ý: Nếu bạn đang sử dụng các phiên bản OpenSSH cũ hơn 8.7, hãy dùng ChallengeResponseAuthentication yes thay cho KbdInteractiveAuthentication yes.

Dòng AuthenticationMethods đóng vai trò then chốt nhất. OpenSSH bắt buộc phải xác thực thành công public key của bạn trước khi hiển thị lời nhắc nhập mã xác thực tương tác từ bàn phím.

Hãy kiểm tra cú pháp trước khi áp dụng các thay đổi. Nếu không có lỗi, tiến hành reload dịch vụ:

sudo sshd -t && sudo systemctl restart sshd

Bước 4: Chặn các cuộc tấn công Brute-Force bằng cơ chế khóa tài khoản

MFA bảo vệ thông tin xác thực cá nhân, nhưng các nỗ lực tấn công dò quét brute-force dồn dập vẫn làm tiêu tốn tài nguyên CPU. Bạn có thể hạn chế chúng bằng pam_faillock. Mở file /etc/security/faillock.conf:

# Khóa tài khoản người dùng sau 4 lần thử thất bại trong 15 phút
deny = 4
fail_interval = 900
unlock_time = 600
even_deny_root

Với các giá trị này, 4 lần đăng nhập thất bại liên tiếp sẽ đóng băng tài khoản trong 10 phút (600 giây). Các mạng botnet sử dụng công cụ tấn công nhồi thông tin xác thực (credential stuffing) sẽ bị chặn đứng ngay lập tức.

Kiểm tra & Xử lý sự cố

Hãy giữ nguyên phiên terminal root hiện tại của bạn. Mở một tab terminal mới trên máy trạm để kiểm tra cấu hình mới vừa tạo. Nếu phát sinh lỗi, bạn vẫn có thể sửa lại cấu hình trên phiên shell đầu tiên mà không lo bị khóa quyền truy cập.

Bước 1: Kiểm tra quy trình đăng nhập

Khởi tạo kết nối SSH với chế độ hiển thị chi tiết (verbose):

ssh -v [email protected]

Client của bạn sẽ gửi private key, nhận tín hiệu xác thực thành công một phần, sau đó yêu cầu nhập mã token động:

Xác thực thành công một phần.
Mã xác thực:

Nhập mã xác thực 6 chữ số rồi nhấn Enter. Phiên shell của bạn sẽ mở ra ngay lập tức.

Bước 2: Kiểm tra nhật ký PAM trực tiếp

Theo dõi các sự kiện PAM khi diễn ra hoạt động đăng nhập. Trên hệ thống Ubuntu và Debian, xem trực tiếp log xác thực:

sudo tail -f /var/log/auth.log | grep -E "sshd|pam"

Trên RHEL, Fedora hoặc Rocky Linux, truy vấn qua systemd journal:

sudo journalctl -u sshd -f

Khi ai đó nhập sai mã, PAM sẽ ghi lại ngữ cảnh lỗi chi tiết:

pam_google_authenticator(sshd:auth): Mã xác thực không hợp lệ cho người dùng deployer
Failed keyboard-interactive/pam for deployer from 198.51.100.24 port 48122 ssh2

Bước 3: Kiểm tra và mở khóa tài khoản

Nếu một kỹ sư nhập sai token và kích hoạt cơ chế khóa tài khoản, hãy kiểm tra trạng thái lỗi của họ:

sudo faillock --user deployer

Bạn sẽ thấy nhật ký kèm mốc thời gian của từng lần thử thất bại. Xóa trạng thái khóa để khôi phục quyền truy cập ngay lập tức:

sudo faillock --user deployer --reset

Kết hợp pam_faillock với yêu cầu bắt buộc TOTP mang lại cho bạn một cơ chế phòng thủ chuyên sâu (defense-in-depth) vững chắc trên các máy chủ Linux mà không cần dựa vào các dịch vụ quản lý định danh SaaS của bên thứ ba.

Share: