Files
audit-web/audit_check_script/hardening_cis_ubuntu_v202.sh
T
2026-08-26 14:11:37 +07:00

1713 lines
67 KiB
Bash

#!/bin/bash
############################################################################
# SCRIPT HARDENING CIS BENCHMARK v2.0.2 CHO UBUNTU 24.04 LTS
# Tương ứng với file audit: audit_cis_ubuntu_v202.sh
############################################################################
# CẢNH BÁO: Script này sẽ thay đổi cấu hình hệ thống.
# - Chạy với quyền root
# - Backup hệ thống trước khi chạy
# - Test trên môi trường staging trước khi áp dụng production
############################################################################
SCRIPT_VERSION="2.0.2"
BACKUP_DIR="/root/cis_hardening_backup_$(date +%Y%m%d_%H%M%S)"
LOG_FILE="/var/log/cis_hardening_$(date +%Y%m%d_%H%M%S).log"
############################################################################
# HÀM TIỆN ÍCH
############################################################################
# Màu sắc
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
log_info() {
echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$LOG_FILE"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1" | tee -a "$LOG_FILE"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
}
log_section() {
echo "" | tee -a "$LOG_FILE"
echo -e "${CYAN}============================================================================${NC}" | tee -a "$LOG_FILE"
echo -e "${CYAN} $1${NC}" | tee -a "$LOG_FILE"
echo -e "${CYAN}============================================================================${NC}" | tee -a "$LOG_FILE"
}
log_subsection() {
echo -e "${CYAN}--- $1 ---${NC}" | tee -a "$LOG_FILE"
}
backup_file() {
local file="$1"
if [ -f "$file" ]; then
local backup_path="${BACKUP_DIR}$(dirname $file)"
mkdir -p "$backup_path"
cp -a "$file" "$backup_path/" 2>/dev/null
log_info "Đã backup: $file"
fi
}
# Hàm set_sysctl_param: đặt tham số sysctl vào file config và apply ngay
# $1: tên tham số (vd: net.ipv4.ip_forward)
# $2: giá trị (vd: 0)
# $3: file config (vd: /etc/sysctl.d/99-cis.conf)
set_sysctl_param() {
local param="$1"
local value="$2"
local conf_file="${3:-/etc/sysctl.d/99-cis-hardening.conf}"
# Xoá tham số cũ nếu có trong tất cả các file sysctl
sed -i "/^\s*${param}\s*=/d" /etc/sysctl.conf 2>/dev/null
for f in /etc/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /run/sysctl.d/*.conf; do
[ -f "$f" ] && [ "$f" != "$conf_file" ] && sed -i "/^\s*${param}\s*=/d" "$f" 2>/dev/null
done
# Thêm vào file config
grep -qP "^\s*${param}\s*=" "$conf_file" 2>/dev/null && \
sed -i "s|^\s*${param}\s*=.*|${param} = ${value}|" "$conf_file" || \
echo "${param} = ${value}" >> "$conf_file"
# Apply ngay
sysctl -w "${param}=${value}" >/dev/null 2>&1
}
# Hàm set_ssh_param: đặt tham số trong sshd_config
# $1: tên tham số
# $2: giá trị
set_ssh_param() {
local param="$1"
local value="$2"
local config="/etc/ssh/sshd_config"
backup_file "$config"
# Đảm bảo thư mục privilege separation tồn tại (nếu thiếu sshd -T sẽ báo lỗi 255)
mkdir -p -m 0755 /run/sshd 2>/dev/null
# Xoá cấu hình cũ trong cả /etc/ssh/sshd_config và các file trong /etc/ssh/sshd_config.d/*.conf
sed -i "/^\s*#\?\s*${param}\b/Id" "$config" 2>/dev/null
if [ -d /etc/ssh/sshd_config.d ]; then
sed -i "/^\s*#\?\s*${param}\b/Id" /etc/ssh/sshd_config.d/*.conf 2>/dev/null
fi
# Thêm dòng mới vào cuối file
echo "${param} ${value}" >> "$config"
log_info "SSH: ${param} = ${value}"
}
############################################################################
# KIỂM TRA QUYỀN ROOT
############################################################################
if [ "$(id -u)" -ne 0 ]; then
log_error "Script này cần được chạy với quyền root!"
exit 1
fi
############################################################################
# TẠO THƯ MỤC BACKUP
############################################################################
mkdir -p "$BACKUP_DIR"
log_info "Thư mục backup: $BACKUP_DIR"
log_info "File log: $LOG_FILE"
############################################################################
# THÔNG TIN HỆ THỐNG
############################################################################
log_section "THÔNG TIN HỆ THỐNG"
echo "Script Version: $SCRIPT_VERSION"
echo "Operating System: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')"
echo "Kernel Version: $(uname -r)"
echo "Hostname: $(hostname)"
echo "IP Address: $(hostname -I 2>/dev/null | awk '{print $1}')"
echo "Thời gian chạy: $(date +"%Y-%m-%d %H:%M:%S")"
# Detect Ubuntu version
UBUNTU_VERSION=$(grep 'VERSION_ID' /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d '"')
echo "Ubuntu Version: $UBUNTU_VERSION"
# Kiểm tra OS
if ! grep -qi 'ubuntu' /etc/os-release 2>/dev/null; then
log_error "Script này chỉ hỗ trợ Ubuntu. OS hiện tại không phải Ubuntu!"
exit 1
fi
############################################################################
# PHÁT HIỆN IPv6
############################################################################
IPV6_ENABLED=0
if [ -f /proc/net/if_inet6 ] && [ -s /proc/net/if_inet6 ]; then
if ip -6 addr show 2>/dev/null | grep -q "inet6" && \
ip -6 addr show 2>/dev/null | grep "inet6" | grep -vq "::1/128"; then
IPV6_ENABLED=1
log_info "IPv6 Status: ENABLED"
else
log_info "IPv6 Status: DISABLED (no IPv6 addresses)"
fi
else
log_info "IPv6 Status: DISABLED (kernel not available)"
fi
############################################################################
# CẤU HÌNH TƯƠNG TÁC
############################################################################
log_section "CẤU HÌNH TƯƠNG TÁC"
echo ""
echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}║ Vui lòng nhập các thông số cấu hình trước khi hardening ║${NC}"
echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
# 1. Firewall
echo -e "${CYAN}[1/4] Chọn Firewall:${NC}"
echo " 1) UFW (khuyến nghị cho Ubuntu)"
echo " 2) iptables"
read -rp "Lựa chọn [1/2] (mặc định: 1): " FW_CHOICE
FW_CHOICE="${FW_CHOICE:-1}"
if [ "$FW_CHOICE" = "2" ]; then
FIREWALL="iptables"
else
FIREWALL="ufw"
fi
log_info "Firewall đã chọn: $FIREWALL"
echo ""
# 2. NTP Server
echo -e "${CYAN}[2/4] Nhập địa chỉ NTP Server:${NC}"
echo " Ví dụ: pool.ntp.org, 10.0.0.1, ntp.vnpt.vn"
read -rp "NTP Server (mặc định: pool.ntp.org): " NTP_SERVER
NTP_SERVER="${NTP_SERVER:-pool.ntp.org}"
log_info "NTP Server: $NTP_SERVER"
echo ""
# 3. SSH Port
echo -e "${CYAN}[3/4] Nhập SSH Port:${NC}"
read -rp "SSH Port (mặc định: 22): " SSH_PORT
SSH_PORT="${SSH_PORT:-22}"
# Validate port
if ! [[ "$SSH_PORT" =~ ^[0-9]+$ ]] || [ "$SSH_PORT" -lt 1 ] || [ "$SSH_PORT" -gt 65535 ]; then
log_warn "Port không hợp lệ, sử dụng port 22"
SSH_PORT=22
fi
log_info "SSH Port: $SSH_PORT"
echo ""
# 4. SSH AllowUsers
echo -e "${CYAN}[4/4] Nhập danh sách user được phép SSH:${NC}"
echo " Cách nhau bằng dấu cách. Ví dụ: admin sysadmin deploy"
echo " Để trống nếu muốn skip (không cấu hình AllowUsers)"
read -rp "SSH AllowUsers: " SSH_ALLOW_USERS
if [ -n "$SSH_ALLOW_USERS" ]; then
log_info "SSH AllowUsers: $SSH_ALLOW_USERS"
else
log_warn "SSH AllowUsers: SKIP (không cấu hình)"
fi
echo ""
# Xác nhận
echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}║ XÁC NHẬN CẤU HÌNH ║${NC}"
echo -e "${YELLOW}╠══════════════════════════════════════════════════════════════╣${NC}"
echo -e "${YELLOW}${NC} Firewall: ${GREEN}$FIREWALL${NC}"
echo -e "${YELLOW}${NC} NTP Server: ${GREEN}$NTP_SERVER${NC}"
echo -e "${YELLOW}${NC} SSH Port: ${GREEN}$SSH_PORT${NC}"
if [ -n "$SSH_ALLOW_USERS" ]; then
echo -e "${YELLOW}${NC} SSH AllowUsers: ${GREEN}$SSH_ALLOW_USERS${NC}"
else
echo -e "${YELLOW}${NC} SSH AllowUsers: ${RED}SKIP${NC}"
fi
echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
read -rp "Bạn có muốn tiếp tục hardening? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^[yY]$ ]]; then
log_info "Đã huỷ hardening theo yêu cầu người dùng."
exit 0
fi
echo ""
log_info "Bắt đầu quá trình hardening..."
echo ""
############################################################################
############################################################################
## SECTION 1: FILESYSTEM ##
############################################################################
############################################################################
log_section "SECTION 1: INITIAL ACCESS & FILESYSTEM"
############################################################################
# 1.1.1.1 - 1.1.1.7: Vô hiệu hoá các filesystem không cần thiết
############################################################################
log_subsection "1.1.1.x - Vô hiệu hoá filesystem không cần thiết"
MODPROBE_FS_CONF="/etc/modprobe.d/cis-filesystem.conf"
backup_file "$MODPROBE_FS_CONF"
cat > "$MODPROBE_FS_CONF" << 'EOF'
# CIS Benchmark v2.0.2 - Vô hiệu hoá filesystem không cần thiết
# 1.1.1.1 - cramfs
install cramfs /bin/true
blacklist cramfs
# 1.1.1.2 - freevxfs
install freevxfs /bin/true
blacklist freevxfs
# 1.1.1.3 - hfs
install hfs /bin/true
blacklist hfs
# 1.1.1.4 - hfsplus
install hfsplus /bin/true
blacklist hfsplus
# 1.1.1.5 - jffs2
install jffs2 /bin/true
blacklist jffs2
# 1.1.1.6 - squashfs
install squashfs /bin/true
blacklist squashfs
# 1.1.1.7 - udf
install udf /bin/true
blacklist udf
EOF
# Gỡ các module đang load
for mod in cramfs freevxfs hfs hfsplus jffs2 squashfs udf; do
if lsmod | grep -qw "$mod"; then
rmmod "$mod" 2>/dev/null
log_info "Đã gỡ module: $mod"
fi
done
log_info "1.1.1.x - Đã vô hiệu hoá các filesystem không cần thiết"
############################################################################
# 1.1.2.x: /tmp mount options (nodev, nosuid, noexec)
############################################################################
log_subsection "1.1.2.x - Cấu hình mount options cho /tmp"
backup_file "/etc/fstab"
if findmnt --kernel /tmp >/dev/null 2>&1; then
# Kiểm tra xem /tmp đã có trong fstab chưa
if grep -qE '\s+/tmp\s+' /etc/fstab; then
# Cập nhật options
sed -i '/\s\/tmp\s/ s/defaults[^ ]*/defaults,nodev,nosuid,noexec/' /etc/fstab
# Nếu chưa có defaults
if ! grep -qE '\s+/tmp\s+.*nodev' /etc/fstab; then
sed -i '/\s\/tmp\s/ s/\(.*\)\(\s\+[0-9]\+\s\+[0-9]\+\)/\1,nodev,nosuid,noexec\2/' /etc/fstab
fi
else
echo "tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
mount -o remount /tmp 2>/dev/null
log_info "1.1.2.x - Đã cấu hình nodev,nosuid,noexec cho /tmp"
else
# /tmp không được mount riêng, tạo entry
if ! grep -qE '\s+/tmp\s+' /etc/fstab; then
echo "tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
log_info "1.1.2.x - Đã thêm cấu hình /tmp vào fstab"
fi
############################################################################
# 1.1.3.x: /var/tmp mount options
############################################################################
log_subsection "1.1.3.x - Cấu hình mount options cho /var/tmp"
if findmnt --kernel /var/tmp >/dev/null 2>&1; then
if grep -qE '\s+/var/tmp\s+' /etc/fstab; then
sed -i '/\s\/var\/tmp\s/ s/defaults[^ ]*/defaults,nodev,nosuid,noexec/' /etc/fstab
else
echo "tmpfs /var/tmp tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
mount -o remount /var/tmp 2>/dev/null
log_info "1.1.3.x - Đã cấu hình nodev,nosuid,noexec cho /var/tmp"
else
if ! grep -qE '\s+/var/tmp\s+' /etc/fstab; then
echo "tmpfs /var/tmp tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
log_info "1.1.3.x - Đã thêm cấu hình /var/tmp vào fstab"
fi
############################################################################
# 1.1.4.x: /home mount options (nodev, nosuid)
############################################################################
log_subsection "1.1.4.x - Cấu hình mount options cho /home"
if findmnt --kernel /home >/dev/null 2>&1; then
if grep -qE '\s+/home\s+' /etc/fstab; then
# Thêm nodev,nosuid nếu chưa có
if ! grep -qE '\s+/home\s+.*nodev' /etc/fstab; then
sed -i '/\s\/home\s/ s/defaults/defaults,nodev,nosuid/' /etc/fstab
fi
fi
mount -o remount /home 2>/dev/null
log_info "1.1.4.x - Đã cấu hình nodev,nosuid cho /home"
else
log_info "1.1.4.x - /home không mount riêng, skip"
fi
############################################################################
# 1.1.5.x: /dev/shm mount options
############################################################################
log_subsection "1.1.5.x - Cấu hình mount options cho /dev/shm"
if grep -qE '\s+/dev/shm\s+' /etc/fstab; then
if ! grep -qE '\s+/dev/shm\s+.*nodev' /etc/fstab; then
sed -i '/\s\/dev\/shm\s/ s/defaults/defaults,nodev,nosuid,noexec/' /etc/fstab
fi
else
echo "tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
fi
mount -o remount /dev/shm 2>/dev/null
log_info "1.1.5.x - Đã cấu hình nodev,nosuid,noexec cho /dev/shm"
############################################################################
# 1.1.6: Sticky bit cho thư mục dùng chung
############################################################################
log_subsection "1.1.6 - Sticky bit cho thư mục dùng chung"
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null | xargs -I '{}' chmod a+t '{}' 2>/dev/null
log_info "1.1.6 - Đã đặt sticky bit cho các thư mục dùng chung"
############################################################################
# 1.1.8: Vô hiệu hoá USB storage
############################################################################
log_subsection "1.1.8 - Vô hiệu hoá USB storage"
USB_CONF="/etc/modprobe.d/cis-usb-storage.conf"
backup_file "$USB_CONF"
cat > "$USB_CONF" << 'EOF'
# CIS 1.1.8 - Vô hiệu hoá USB storage
install usb-storage /bin/true
blacklist usb-storage
EOF
if lsmod | grep -q usb-storage; then
rmmod usb-storage 2>/dev/null
fi
log_info "1.1.8 - Đã vô hiệu hoá USB storage"
############################################################################
# 1.2.1 - 1.2.2: Cài đặt AIDE + cron
############################################################################
log_subsection "1.2.1-2 - AIDE"
if ! dpkg -l | grep -q "ii aide"; then
DEBIAN_FRONTEND=noninteractive apt-get install -y aide aide-common >> "$LOG_FILE" 2>&1
log_info "1.2.1 - Đã cài đặt AIDE"
else
log_info "1.2.1 - AIDE đã được cài đặt"
fi
# Khởi tạo AIDE nếu chưa có database
if [ ! -f /var/lib/aide/aide.db ]; then
log_info "1.2.1 - Đang khởi tạo AIDE database (có thể mất vài phút)..."
aideinit >> "$LOG_FILE" 2>&1
if [ -f /var/lib/aide/aide.db.new ]; then
mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
fi
log_info "1.2.1 - Đã khởi tạo AIDE database"
fi
# Cấu hình cron cho AIDE
AIDE_CRON="0 5 * * * /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check"
if ! crontab -u root -l 2>/dev/null | grep -q "aide"; then
(crontab -u root -l 2>/dev/null; echo "$AIDE_CRON") | crontab -u root -
log_info "1.2.2 - Đã cấu hình AIDE cron check"
else
log_info "1.2.2 - AIDE cron đã tồn tại"
fi
############################################################################
# 1.3.1: Phân quyền file cấu hình bootloader
############################################################################
log_subsection "1.3.1 - Phân quyền bootloader"
if [ -f /boot/grub/grub.cfg ]; then
chown root:root /boot/grub/grub.cfg
chmod u-wx,go-rwx /boot/grub/grub.cfg
log_info "1.3.1 - Đã phân quyền /boot/grub/grub.cfg"
fi
############################################################################
# 1.4.1: ASLR
############################################################################
log_subsection "1.4.1 - ASLR"
SYSCTL_CIS="/etc/sysctl.d/99-cis-hardening.conf"
touch "$SYSCTL_CIS"
set_sysctl_param "kernel.randomize_va_space" "2" "$SYSCTL_CIS"
log_info "1.4.1 - Đã kích hoạt ASLR (kernel.randomize_va_space=2)"
############################################################################
# 1.4.2: Gỡ prelink
############################################################################
log_subsection "1.4.2 - Gỡ prelink"
if dpkg -l | grep -q "ii prelink"; then
prelink -ua 2>/dev/null
apt-get purge -y prelink >> "$LOG_FILE" 2>&1
log_info "1.4.2 - Đã gỡ prelink"
else
log_info "1.4.2 - prelink không được cài đặt"
fi
############################################################################
# 1.4.3: Vô hiệu hoá core dump
############################################################################
log_subsection "1.4.3 - Vô hiệu hoá core dump"
# limits.conf
LIMITS_CORE="/etc/security/limits.d/99-cis-coredump.conf"
echo "* hard core 0" > "$LIMITS_CORE"
log_info "1.4.3 - Đã cấu hình limits: * hard core 0"
# sysctl
set_sysctl_param "fs.suid_dumpable" "0" "$SYSCTL_CIS"
log_info "1.4.3 - Đã cấu hình sysctl: fs.suid_dumpable=0"
# systemd-coredump
if systemctl list-unit-files --type=service --type=socket 2>/dev/null | grep -q '^systemd-coredump'; then
mkdir -p /etc/systemd/coredump.conf.d
cat > /etc/systemd/coredump.conf.d/99-cis-override.conf << 'EOF'
[Coredump]
Storage=none
ProcessSizeMax=0
EOF
systemctl daemon-reload
log_info "1.4.3 - Đã cấu hình systemd-coredump override"
fi
############################################################################
# 1.5.1 - 1.5.3: Banner login
############################################################################
log_subsection "1.5.1-3 - Banner login"
BANNER_TEXT="Authorized uses only. All activity may be monitored and reported."
# /etc/motd - xoá hoặc cấu hình
backup_file "/etc/motd"
if [ -f /etc/motd ]; then
rm -f /etc/motd
log_info "1.5.1 - Đã xoá /etc/motd"
fi
# /etc/issue
backup_file "/etc/issue"
echo "$BANNER_TEXT" > /etc/issue
log_info "1.5.2 - Đã cấu hình /etc/issue"
# /etc/issue.net
backup_file "/etc/issue.net"
echo "$BANNER_TEXT" > /etc/issue.net
log_info "1.5.3 - Đã cấu hình /etc/issue.net"
############################################################################
# 1.5.4 - 1.5.6: Phân quyền file banner
############################################################################
log_subsection "1.5.4-6 - Phân quyền file banner"
for f in /etc/issue /etc/issue.net; do
if [ -f "$f" ]; then
chown root:root "$f"
chmod u-x,go-wx "$f"
log_info "Đã phân quyền $f"
fi
done
############################################################################
# 1.5.7: GDM banner (nếu có GNOME)
############################################################################
log_subsection "1.5.7 - GDM banner"
HAS_GNOME=0
if dpkg -l gdm3 gnome-shell 2>/dev/null | awk '$1=="ii"{f=1} END{exit !f}'; then
HAS_GNOME=1
elif [ -d /etc/gdm3 ]; then
HAS_GNOME=1
fi
if [ "$HAS_GNOME" -eq 1 ]; then
GDM_CONF="/etc/gdm3/greeter.dconf-defaults"
backup_file "$GDM_CONF"
mkdir -p /etc/gdm3
# Kiểm tra và thêm section nếu chưa có
if ! grep -q '\[org/gnome/login-screen\]' "$GDM_CONF" 2>/dev/null; then
cat >> "$GDM_CONF" << EOF
[org/gnome/login-screen]
banner-message-enable=true
banner-message-text='${BANNER_TEXT}'
disable-user-list=true
EOF
fi
dpkg-reconfigure gdm3 2>/dev/null
log_info "1.5.7 - Đã cấu hình GDM banner"
else
log_info "1.5.7 - GNOME không cài đặt, skip"
fi
############################################################################
############################################################################
## SECTION 2: SERVICES ##
############################################################################
############################################################################
log_section "SECTION 2: SERVICES"
############################################################################
# 2.1.1 - 2.1.2: Cấu hình NTP/chrony
############################################################################
log_subsection "2.1.1-2 - Cấu hình NTP (chrony)"
# Cài đặt chrony nếu chưa có
if ! dpkg -l | grep -q "ii chrony"; then
DEBIAN_FRONTEND=noninteractive apt-get install -y chrony >> "$LOG_FILE" 2>&1
fi
# Cấu hình chrony
CHRONY_CONF="/etc/chrony/chrony.conf"
backup_file "$CHRONY_CONF"
# Thêm NTP server nếu chưa có
if ! grep -qE "^(server|pool)\s+${NTP_SERVER}" "$CHRONY_CONF" 2>/dev/null; then
# Comment các server/pool cũ (không phải NTP_SERVER)
sed -i "s/^pool /#pool /" "$CHRONY_CONF" 2>/dev/null
sed -i "s/^server /#server /" "$CHRONY_CONF" 2>/dev/null
# Thêm server mới
echo "server ${NTP_SERVER} iburst" >> "$CHRONY_CONF"
fi
systemctl enable chrony --now >> "$LOG_FILE" 2>&1
# Vô hiệu hoá ntp và systemd-timesyncd nếu dùng chrony
systemctl stop ntp 2>/dev/null; systemctl disable ntp 2>/dev/null
systemctl stop systemd-timesyncd 2>/dev/null; systemctl disable systemd-timesyncd 2>/dev/null
log_info "2.1.1-2 - Đã cấu hình chrony với server: $NTP_SERVER"
############################################################################
# 2.2.1: Vô hiệu hoá xinetd
############################################################################
log_subsection "2.2.x - Vô hiệu hoá dịch vụ không cần thiết"
# 2.2.1 - xinetd
if dpkg -l | grep -q xinetd; then
systemctl stop xinetd 2>/dev/null
systemctl disable xinetd 2>/dev/null
apt-get purge -y xinetd >> "$LOG_FILE" 2>&1
log_info "2.2.1 - Đã gỡ xinetd"
fi
# 2.2.2 - autofs
if dpkg -l | grep -q "ii autofs"; then
systemctl stop autofs 2>/dev/null
systemctl disable autofs 2>/dev/null
apt-get purge -y autofs >> "$LOG_FILE" 2>&1
log_info "2.2.2 - Đã gỡ autofs"
fi
# 2.2.3 - X Window
if dpkg -l | grep -q "ii xserver-xorg"; then
log_warn "2.2.3 - xserver-xorg đã cài đặt. Vui lòng gỡ thủ công nếu không cần: apt remove --purge '^xserver-xorg'"
fi
# 2.2.4 - Avahi
if dpkg -l | grep -q "ii avahi-daemon"; then
systemctl stop avahi-daemon.service avahi-daemon.socket 2>/dev/null
apt-get purge -y avahi-daemon >> "$LOG_FILE" 2>&1
log_info "2.2.4 - Đã gỡ avahi-daemon"
fi
# 2.2.5 - CUPS
if systemctl is-enabled cups 2>/dev/null | grep -q "enabled" || systemctl is-active cups 2>/dev/null | grep -q "^active"; then
systemctl stop cups 2>/dev/null
systemctl disable cups 2>/dev/null
systemctl mask cups 2>/dev/null
log_info "2.2.5 - Đã vô hiệu hoá CUPS"
fi
# 2.2.6 - DHCP Server
if dpkg -l | grep -q "ii isc-dhcp-server"; then
apt-get purge -y isc-dhcp-server >> "$LOG_FILE" 2>&1
log_info "2.2.6 - Đã gỡ isc-dhcp-server"
fi
# 2.2.7 - LDAP Server
if dpkg -l | grep -q "ii slapd"; then
apt-get purge -y slapd >> "$LOG_FILE" 2>&1
log_info "2.2.7 - Đã gỡ slapd"
fi
# 2.2.6b - NFS
if dpkg -l | grep -q "ii nfs-kernel-server"; then
apt-get purge -y nfs-kernel-server >> "$LOG_FILE" 2>&1
log_info "2.2.6b - Đã gỡ nfs-kernel-server"
fi
# 2.2.8 - DNS Server (bind9 etc.)
for dns_pkg in bind9 dnsmasq unbound pdns-server; do
if dpkg -l | grep -q "ii ${dns_pkg}"; then
systemctl stop "${dns_pkg}" 2>/dev/null
systemctl disable "${dns_pkg}" 2>/dev/null
log_info "2.2.8 - Đã vô hiệu hoá ${dns_pkg}"
fi
done
# 2.2.9 - dnsmasq
if dpkg -l 2>/dev/null | grep -q "ii dnsmasq"; then
systemctl stop dnsmasq 2>/dev/null
systemctl disable dnsmasq 2>/dev/null
log_info "2.2.9 - Đã vô hiệu hoá dnsmasq"
fi
# 2.2.10 - FTP Server
if dpkg -l | grep -q "ii vsftpd"; then
apt-get purge -y vsftpd >> "$LOG_FILE" 2>&1
log_info "2.2.10 - Đã gỡ vsftpd"
fi
# 2.2.11 - TFTP Server
if dpkg -l | grep -q "ii tftpd-hpa"; then
systemctl stop tftp.socket tftpd-hpa.service 2>/dev/null
systemctl disable tftp.socket tftpd-hpa.service 2>/dev/null
apt-get purge -y tftpd-hpa >> "$LOG_FILE" 2>&1
log_info "2.2.11 - Đã gỡ tftpd-hpa"
fi
# 2.2.12 - HTTP Server (Apache)
if dpkg -l | grep -q "ii apache2"; then
apt-get purge -y apache2 >> "$LOG_FILE" 2>&1
log_info "2.2.12 - Đã gỡ apache2"
fi
# 2.2.13 - IMAP/POP3
for mail_pkg in dovecot-imapd dovecot-pop3d; do
if dpkg -l | grep -q "ii ${mail_pkg}"; then
apt-get purge -y "${mail_pkg}" >> "$LOG_FILE" 2>&1
log_info "2.2.13 - Đã gỡ ${mail_pkg}"
fi
done
# 2.2.14 - Samba
if systemctl is-enabled smbd 2>/dev/null | grep -q "enabled" || systemctl is-active smbd 2>/dev/null | grep -q "^active"; then
systemctl stop smbd nmbd 2>/dev/null
systemctl disable smbd nmbd 2>/dev/null
systemctl mask smbd nmbd 2>/dev/null
log_info "2.2.14 - Đã vô hiệu hoá Samba"
fi
# 2.2.14b - telnetd
if dpkg -l | grep -q "ii telnetd"; then
apt-get purge -y telnetd >> "$LOG_FILE" 2>&1
log_info "2.2.14b - Đã gỡ telnetd"
fi
# 2.2.15 - Squid (HTTP Proxy)
if dpkg -l | grep -q "ii squid"; then
apt-get purge -y squid >> "$LOG_FILE" 2>&1
log_info "2.2.15 - Đã gỡ squid"
fi
# 2.2.15b - rsh-server
if dpkg -l | grep -q "ii rsh-server"; then
apt-get purge -y rsh-server >> "$LOG_FILE" 2>&1
log_info "2.2.15b - Đã gỡ rsh-server"
fi
# 2.2.16 - SNMP
for snmp_pkg in snmp snmpd; do
if dpkg -l | grep -q "ii ${snmp_pkg}"; then
apt-get purge -y "${snmp_pkg}" >> "$LOG_FILE" 2>&1
log_info "2.2.16 - Đã gỡ ${snmp_pkg}"
fi
done
# 2.2.17 - NIS Server
if dpkg -l | grep -q ypserv; then
systemctl stop ypserv 2>/dev/null
systemctl disable ypserv 2>/dev/null
log_info "2.2.17 - Đã vô hiệu hoá ypserv"
fi
# 2.2.18 - MTA local-only (Postfix)
if [ -f /etc/postfix/main.cf ]; then
backup_file "/etc/postfix/main.cf"
if grep -q "^inet_interfaces" /etc/postfix/main.cf; then
sed -i 's/^inet_interfaces.*/inet_interfaces = loopback-only/' /etc/postfix/main.cf
else
echo "inet_interfaces = loopback-only" >> /etc/postfix/main.cf
fi
systemctl restart postfix 2>/dev/null
log_info "2.2.18 - Đã cấu hình postfix local-only"
fi
# 2.2.19 - NFS service
if dpkg -l | grep -q nfs-kernel-server; then
systemctl stop nfs-server 2>/dev/null
systemctl disable nfs-server 2>/dev/null
log_info "2.2.19 - Đã vô hiệu hoá NFS server"
fi
# 2.2.20 - rsync
if systemctl is-enabled rsync 2>/dev/null | grep -q "enabled" || systemctl is-active rsync 2>/dev/null | grep -q "^active"; then
systemctl stop rsync 2>/dev/null
systemctl disable rsync 2>/dev/null
systemctl mask rsync 2>/dev/null
log_info "2.2.20 - Đã vô hiệu hoá rsync"
fi
############################################################################
# 2.3.x: Gỡ client không cần thiết
############################################################################
log_subsection "2.3.x - Gỡ client không cần thiết"
declare -A CLIENTS_TO_REMOVE=(
["nis"]="2.3.1"
["rsh-client"]="2.3.2"
["talk"]="2.3.3"
["telnet"]="2.3.4"
["ldap-utils"]="2.3.5"
["rpcbind"]="2.3.6"
["ftp"]="2.3.7"
)
for pkg in "${!CLIENTS_TO_REMOVE[@]}"; do
if dpkg -l | grep -q "ii ${pkg}"; then
apt-get purge -y "$pkg" >> "$LOG_FILE" 2>&1
log_info "${CLIENTS_TO_REMOVE[$pkg]} - Đã gỡ ${pkg}"
fi
done
############################################################################
############################################################################
## SECTION 3: NETWORK ##
############################################################################
############################################################################
log_section "SECTION 3: NETWORK"
############################################################################
# 3.1.1: Vô hiệu hoá IP forwarding
############################################################################
log_subsection "3.1.1-2 - Network parameters (host)"
set_sysctl_param "net.ipv4.ip_forward" "0" "$SYSCTL_CIS"
if [ "$IPV6_ENABLED" -eq 1 ]; then
set_sysctl_param "net.ipv6.conf.all.forwarding" "0" "$SYSCTL_CIS"
fi
log_info "3.1.1 - Đã vô hiệu hoá IP forwarding"
# 3.1.2: Vô hiệu hoá packet redirect
set_sysctl_param "net.ipv4.conf.all.send_redirects" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.send_redirects" "0" "$SYSCTL_CIS"
log_info "3.1.2 - Đã vô hiệu hoá packet redirect"
############################################################################
# 3.2.x: Network parameters (host and router)
############################################################################
log_subsection "3.2.x - Network parameters (host and router)"
# 3.2.1: Source routed packets
set_sysctl_param "net.ipv4.conf.all.accept_source_route" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.accept_source_route" "0" "$SYSCTL_CIS"
if [ "$IPV6_ENABLED" -eq 1 ]; then
set_sysctl_param "net.ipv6.conf.all.accept_source_route" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv6.conf.default.accept_source_route" "0" "$SYSCTL_CIS"
fi
log_info "3.2.1 - Đã từ chối source routed packets"
# 3.2.2: ICMP redirects
set_sysctl_param "net.ipv4.conf.all.accept_redirects" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.accept_redirects" "0" "$SYSCTL_CIS"
if [ "$IPV6_ENABLED" -eq 1 ]; then
set_sysctl_param "net.ipv6.conf.all.accept_redirects" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv6.conf.default.accept_redirects" "0" "$SYSCTL_CIS"
fi
log_info "3.2.2 - Đã từ chối ICMP redirects"
# 3.2.3: Secure ICMP redirects
set_sysctl_param "net.ipv4.conf.all.secure_redirects" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.secure_redirects" "0" "$SYSCTL_CIS"
log_info "3.2.3 - Đã từ chối secure ICMP redirects"
# 3.2.4: Log suspicious packets
set_sysctl_param "net.ipv4.conf.all.log_martians" "1" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.log_martians" "1" "$SYSCTL_CIS"
log_info "3.2.4 - Đã bật log cho gói tin đáng ngờ"
# 3.2.5: Ignore broadcast ICMP
set_sysctl_param "net.ipv4.icmp_echo_ignore_broadcasts" "1" "$SYSCTL_CIS"
log_info "3.2.5 - Đã bỏ qua broadcast ICMP"
# 3.2.6: Ignore bogus ICMP
set_sysctl_param "net.ipv4.icmp_ignore_bogus_error_responses" "1" "$SYSCTL_CIS"
log_info "3.2.6 - Đã bỏ qua bogus ICMP"
# 3.2.7: Reverse path filtering
set_sysctl_param "net.ipv4.conf.all.rp_filter" "1" "$SYSCTL_CIS"
set_sysctl_param "net.ipv4.conf.default.rp_filter" "1" "$SYSCTL_CIS"
log_info "3.2.7 - Đã bật reverse path filtering"
# 3.2.8: TCP SYN Cookies
set_sysctl_param "net.ipv4.tcp_syncookies" "1" "$SYSCTL_CIS"
log_info "3.2.8 - Đã bật TCP SYN Cookies"
############################################################################
# 3.3.x: IPv6 parameters
############################################################################
if [ "$IPV6_ENABLED" -eq 1 ]; then
log_subsection "3.3.x - IPv6 parameters"
set_sysctl_param "net.ipv6.conf.all.accept_ra" "0" "$SYSCTL_CIS"
set_sysctl_param "net.ipv6.conf.default.accept_ra" "0" "$SYSCTL_CIS"
log_info "3.3.1 - Đã vô hiệu hoá IPv6 router advertisements"
fi
# Apply all sysctl
sysctl --system >> "$LOG_FILE" 2>&1
log_info "Đã apply tất cả sysctl parameters"
############################################################################
# 3.4.x: Firewall
############################################################################
log_subsection "3.4.x - Cấu hình Firewall ($FIREWALL)"
if [ "$FIREWALL" = "ufw" ]; then
# Cài đặt UFW
if ! dpkg -l | grep -Eq '^ii\s+ufw(\s|$)'; then
DEBIAN_FRONTEND=noninteractive apt-get install -y ufw >> "$LOG_FILE" 2>&1
fi
# Vô hiệu hoá nftables nếu có
if dpkg -l | grep -q "ii nftables"; then
systemctl mask nftables 2>/dev/null
fi
# Cấu hình UFW
systemctl unmask ufw.service 2>/dev/null
systemctl enable ufw --now >> "$LOG_FILE" 2>&1
# Default policies
ufw default deny incoming >> "$LOG_FILE" 2>&1
ufw default deny outgoing >> "$LOG_FILE" 2>&1
ufw default deny routed >> "$LOG_FILE" 2>&1
# Loopback
ufw allow in on lo >> "$LOG_FILE" 2>&1
ufw allow out on lo >> "$LOG_FILE" 2>&1
ufw deny in from 127.0.0.0/8 >> "$LOG_FILE" 2>&1
if [ "$IPV6_ENABLED" -eq 1 ]; then
ufw deny in from ::1 >> "$LOG_FILE" 2>&1
fi
# Allow SSH
ufw allow in "${SSH_PORT}/tcp" >> "$LOG_FILE" 2>&1
# Allow essential outbound
ufw allow out 53 >> "$LOG_FILE" 2>&1 # DNS
ufw allow out 80/tcp >> "$LOG_FILE" 2>&1 # HTTP (apt updates)
ufw allow out 443/tcp >> "$LOG_FILE" 2>&1 # HTTPS
ufw allow out 123/udp >> "$LOG_FILE" 2>&1 # NTP
# Enable UFW
echo "y" | ufw enable >> "$LOG_FILE" 2>&1
log_info "3.4.1.x - UFW đã được cấu hình và kích hoạt"
log_info "3.4.1.x - Default: deny incoming, deny outgoing, deny routed"
log_info "3.4.1.x - Đã allow SSH port ${SSH_PORT}, DNS, HTTP, HTTPS, NTP outbound"
else
# iptables
if ! dpkg -l | grep -Eq '^ii\s+iptables(\s|$)'; then
DEBIAN_FRONTEND=noninteractive apt-get install -y iptables >> "$LOG_FILE" 2>&1
fi
if ! dpkg -l | grep -Eq '^ii\s+iptables-persistent(\s|$)'; then
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections
DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent >> "$LOG_FILE" 2>&1
fi
# Vô hiệu hoá ufw nếu có
if dpkg -l | grep -Eq '^ii\s+ufw(\s|$)'; then
ufw disable 2>/dev/null
systemctl stop ufw 2>/dev/null
systemctl disable ufw 2>/dev/null
fi
# Vô hiệu hoá nftables
if dpkg -l | grep -q "ii nftables"; then
systemctl mask nftables 2>/dev/null
fi
# Flush existing rules
iptables -F
iptables -X
# Loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -s 127.0.0.0/8 -j DROP
# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow outbound
iptables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
iptables -A OUTPUT -p icmp -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -m state --state ESTABLISHED -j ACCEPT
# Allow SSH inbound
iptables -A INPUT -p tcp --dport "$SSH_PORT" -m state --state NEW -j ACCEPT
# Default policies - DROP
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
# IPv6
if [ "$IPV6_ENABLED" -eq 1 ]; then
ip6tables -F
ip6tables -X
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A INPUT -s ::1 -j DROP
ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -p tcp --dport "$SSH_PORT" -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 123 -m state --state NEW -j ACCEPT
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP
fi
# Save rules
iptables-save > /etc/iptables/rules.v4 2>/dev/null
ip6tables-save > /etc/iptables/rules.v6 2>/dev/null
log_info "3.4.2.x - iptables đã được cấu hình"
log_info "3.4.2.x - Default policy: DROP cho INPUT, OUTPUT, FORWARD"
log_info "3.4.2.x - Đã allow SSH port ${SSH_PORT}, DNS, HTTP, HTTPS, NTP outbound"
fi
############################################################################
############################################################################
## SECTION 4: LOGGING ##
############################################################################
############################################################################
log_section "SECTION 4: LOGGING & AUDITING"
############################################################################
# 4.1.1.1: rsyslog
############################################################################
log_subsection "4.1.1.x - rsyslog"
if ! dpkg -l | grep -q "ii rsyslog"; then
DEBIAN_FRONTEND=noninteractive apt-get install -y rsyslog >> "$LOG_FILE" 2>&1
fi
systemctl enable rsyslog --now >> "$LOG_FILE" 2>&1
log_info "4.1.1.1 - rsyslog đã được kích hoạt"
# 4.1.1.2: FileCreateMode
RSYSLOG_CONF="/etc/rsyslog.conf"
backup_file "$RSYSLOG_CONF"
if grep -q '^\$FileCreateMode' "$RSYSLOG_CONF"; then
sed -i 's/^\$FileCreateMode.*/\$FileCreateMode 0640/' "$RSYSLOG_CONF"
else
echo '$FileCreateMode 0640' >> "$RSYSLOG_CONF"
fi
systemctl restart rsyslog >> "$LOG_FILE" 2>&1
log_info "4.1.1.2 - rsyslog FileCreateMode = 0640"
############################################################################
# 4.1.2: Phân quyền file log
############################################################################
log_subsection "4.1.2 - Phân quyền file log"
find /var/log -type f -exec chmod g-wx,o-rwx {} + 2>/dev/null
log_info "4.1.2 - Đã phân quyền cho tất cả file trong /var/log"
############################################################################
############################################################################
## SECTION 5: ACCESS & AUTHENTICATION ##
############################################################################
############################################################################
log_section "SECTION 5: ACCESS, AUTHENTICATION & AUTHORIZATION"
############################################################################
# 5.1.1 - 5.1.8: Cron
############################################################################
log_subsection "5.1.x - Cron daemon & phân quyền"
systemctl enable cron --now >> "$LOG_FILE" 2>&1
log_info "5.1.1 - cron daemon đã được kích hoạt"
# Phân quyền cron files/dirs
for cron_path in /etc/crontab /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly /etc/cron.d; do
if [ -e "$cron_path" ]; then
chown root:root "$cron_path"
chmod og-rwx "$cron_path"
fi
done
log_info "5.1.2-7 - Đã phân quyền cho cron files/dirs"
# 5.1.8: cron.allow / at.allow
rm -f /etc/cron.deny /etc/at.deny 2>/dev/null
touch /etc/cron.allow /etc/at.allow
chmod og-rwx /etc/cron.allow /etc/at.allow
chown root:root /etc/cron.allow /etc/at.allow
log_info "5.1.8 - Đã cấu hình cron.allow/at.allow"
############################################################################
# 5.2.x: SSH Hardening
############################################################################
log_subsection "5.2.x - SSH Hardening"
# 5.2.1: Phân quyền sshd_config
chown root:root /etc/ssh/sshd_config
chmod og-rwx /etc/ssh/sshd_config
log_info "5.2.1 - Đã phân quyền /etc/ssh/sshd_config"
# 5.2.2: SSH private host key permissions
find /etc/ssh -xdev -type f -name 'ssh_host_*_key' -exec chown root:root {} \;
find /etc/ssh -xdev -type f -name 'ssh_host_*_key' -exec chmod u-x,go-rwx {} \;
log_info "5.2.2 - Đã phân quyền SSH private host keys"
# 5.2.3: SSH public host key permissions
find /etc/ssh -xdev -type f -name 'ssh_host_*_key.pub' -exec chown root:root {} \;
find /etc/ssh -xdev -type f -name 'ssh_host_*_key.pub' -exec chmod u-x,go-wx {} \;
log_info "5.2.3 - Đã phân quyền SSH public host keys"
# 5.2.4: SSH Access - AllowUsers (nếu user đã nhập)
if [ -n "$SSH_ALLOW_USERS" ]; then
set_ssh_param "AllowUsers" "$SSH_ALLOW_USERS"
log_info "5.2.4 - SSH AllowUsers: $SSH_ALLOW_USERS"
else
log_warn "5.2.4 - SSH AllowUsers: SKIP (không cấu hình)"
fi
# 5.2.5: LogLevel
set_ssh_param "LogLevel" "VERBOSE"
# 5.2.6: UsePAM
set_ssh_param "UsePAM" "yes"
# 5.2.7: PermitRootLogin
set_ssh_param "PermitRootLogin" "no"
# 5.2.8: HostbasedAuthentication
set_ssh_param "HostbasedAuthentication" "no"
# 5.2.9: PermitEmptyPasswords
set_ssh_param "PermitEmptyPasswords" "no"
# 5.2.10: PermitUserEnvironment
set_ssh_param "PermitUserEnvironment" "no"
# 5.2.11: IgnoreRhosts
set_ssh_param "IgnoreRhosts" "yes"
# 5.2.12: X11Forwarding
set_ssh_param "X11Forwarding" "no"
# 5.2.13: Ciphers
set_ssh_param "Ciphers" "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr"
# 5.2.14: MACs
set_ssh_param "MACs" "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256"
# 5.2.15: KexAlgorithms
set_ssh_param "KexAlgorithms" "curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256"
# 5.2.16: AllowTcpForwarding
set_ssh_param "AllowTcpForwarding" "no"
# 5.2.17: Banner
set_ssh_param "Banner" "/etc/issue.net"
# 5.2.18: MaxAuthTries
set_ssh_param "MaxAuthTries" "4"
# 5.2.19: MaxStartups
set_ssh_param "MaxStartups" "10:30:60"
# 5.2.20: MaxSessions
set_ssh_param "MaxSessions" "10"
# 5.2.21: LoginGraceTime
set_ssh_param "LoginGraceTime" "60"
# 5.2.22: ClientAlive
set_ssh_param "ClientAliveInterval" "900"
set_ssh_param "ClientAliveCountMax" "0"
# SSH Port (nếu khác mặc định)
if [ "$SSH_PORT" != "22" ]; then
set_ssh_param "Port" "$SSH_PORT"
log_info "SSH Port đã được đổi sang: $SSH_PORT"
fi
# Đảm bảo thư mục privilege separation tồn tại vĩnh viễn (khắc phục lỗi Missing privilege separation directory /run/sshd của Ubuntu 24.04)
mkdir -p -m 0755 /run/sshd 2>/dev/null
cat > /etc/tmpfiles.d/cis-sshd.conf << 'EOF'
d /run/sshd 0755 root root -
EOF
systemd-tmpfiles --create /etc/tmpfiles.d/cis-sshd.conf 2>/dev/null
# Restart SSH
sshd -t 2>/dev/null
if [ $? -eq 0 ]; then
systemctl restart ssh.socket sshd.service 2>/dev/null || systemctl restart ssh 2>/dev/null
log_info "5.2.x - SSH đã được restart thành công (/run/sshd ok)"
else
log_error "5.2.x - Cấu hình SSH có lỗi! Vui lòng kiểm tra /etc/ssh/sshd_config"
fi
############################################################################
# 5.3.1: Password quality (pwquality)
############################################################################
log_subsection "5.3.x - Password quality & lockout"
if ! dpkg -l | grep -q "ii libpam-pwquality"; then
DEBIAN_FRONTEND=noninteractive apt-get install -y libpam-pwquality >> "$LOG_FILE" 2>&1
fi
PWQUALITY_CONF="/etc/security/pwquality.conf"
backup_file "$PWQUALITY_CONF"
cat > "$PWQUALITY_CONF" << 'EOF'
# CIS Benchmark v2.0.2 - Password Quality
minlen = 8
enforce_for_root
minclass = 4
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
EOF
log_info "5.3.1 - Đã cấu hình password quality"
############################################################################
# 5.3.2: Account lockout (faillock - Ubuntu 22.04+)
############################################################################
log_subsection "5.3.2 - Account lockout (faillock)"
if grep -Eq 'VERSION_ID="(2[2-9]|[3-9][0-9])\.' /etc/os-release; then
# Ubuntu 22.04+ sử dụng faillock
FAILLOCK_CONF="/etc/security/faillock.conf"
backup_file "$FAILLOCK_CONF"
cat > "$FAILLOCK_CONF" << 'EOF'
# CIS Benchmark v2.0.2 - Account Lockout
deny = 5
fail_interval = 900
unlock_time = 900
EOF
# Cấu hình PAM common-auth
COMMON_AUTH="/etc/pam.d/common-auth"
backup_file "$COMMON_AUTH"
# Kiểm tra và thêm faillock nếu chưa có
if ! grep -q "pam_faillock.so" "$COMMON_AUTH"; then
# Tạo file mới với faillock
cat > "$COMMON_AUTH" << 'EOF'
# CIS Benchmark v2.0.2 - PAM common-auth with faillock
auth required pam_faillock.so preauth
auth [success=1 default=ignore] pam_unix.so nullok
auth [default=die] pam_faillock.so authfail
auth sufficient pam_faillock.so authsucc
auth requisite pam_deny.so
auth required pam_permit.so
auth optional pam_cap.so
EOF
fi
# Thêm faillock vào common-account
COMMON_ACCOUNT="/etc/pam.d/common-account"
backup_file "$COMMON_ACCOUNT"
if ! grep -q "pam_faillock.so" "$COMMON_ACCOUNT"; then
echo "account required pam_faillock.so" >> "$COMMON_ACCOUNT"
fi
log_info "5.3.2 - Đã cấu hình faillock (deny=5, fail_interval=900, unlock_time=900)"
else
# Ubuntu 20.04 trở về trước sử dụng pam_tally2
COMMON_AUTH="/etc/pam.d/common-auth"
backup_file "$COMMON_AUTH"
if ! grep -q "pam_tally2.so" "$COMMON_AUTH"; then
echo "auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900" >> "$COMMON_AUTH"
fi
COMMON_ACCOUNT="/etc/pam.d/common-account"
backup_file "$COMMON_ACCOUNT"
if ! grep -q "pam_tally2.so" "$COMMON_ACCOUNT"; then
echo "account requisite pam_deny.so" >> "$COMMON_ACCOUNT"
echo "account required pam_tally2.so" >> "$COMMON_ACCOUNT"
fi
log_info "5.3.2 - Đã cấu hình pam_tally2 (deny=5, unlock_time=900)"
fi
############################################################################
# 5.3.3: Password reuse limit
############################################################################
COMMON_PASSWORD="/etc/pam.d/common-password"
backup_file "$COMMON_PASSWORD"
if ! grep -q "pam_pwhistory.so" "$COMMON_PASSWORD"; then
# Thêm pam_pwhistory trước pam_unix.so
sed -i '/pam_unix.so/i password required pam_pwhistory.so remember=5' "$COMMON_PASSWORD"
fi
log_info "5.3.3 - Đã cấu hình password reuse limit (remember=5)"
############################################################################
# 5.3.4: Password hashing algorithm
############################################################################
############################################################################
# 5.3.4: Password hashing algorithm
############################################################################
if grep -Eq 'VERSION_ID="(2[2-9]|[3-9][0-9])\.' /etc/os-release; then
# Ubuntu 22.04+ / 24.04: sử dụng yescrypt (chỉ khai báo ENCRYPT_METHOD yescrypt trong login.defs)
sed -i 's/^\s*ENCRYPT_METHOD.*/ENCRYPT_METHOD yescrypt/' "$LOGIN_DEFS" 2>/dev/null || echo "ENCRYPT_METHOD yescrypt" >> "$LOGIN_DEFS"
# Theo chuẩn CIS trên Ubuntu 22.04+/24.04, KHÔNG được khai báo tên thuật toán (yescrypt/sha512/md5/...) trực tiếp tại dòng pam_unix.so trong common-password
sed -E -i '/pam_unix\.so/ s/\s+(yescrypt|sha512|sha256|md5|bigcrypt|blowfish)\b//g' "$COMMON_PASSWORD" 2>/dev/null
log_info "5.3.4 - Đã cấu hình ENCRYPT_METHOD yescrypt cho Ubuntu 22.04+/24.04"
else
# Ubuntu 20.04 trở về trước: sử dụng sha512
if ! grep -q "sha512" "$COMMON_PASSWORD"; then
sed -i '/pam_unix.so/ s/$/ sha512/' "$COMMON_PASSWORD"
fi
log_info "5.3.4 - Đã cấu hình SHA-512 password hashing"
fi
############################################################################
# 5.4.1.x: Password policy
############################################################################
log_subsection "5.4.1.x - Password policy"
LOGIN_DEFS="/etc/login.defs"
backup_file "$LOGIN_DEFS"
# 5.4.1.1: PASS_MAX_DAYS = 90
sed -i 's/^\s*PASS_MAX_DAYS.*/PASS_MAX_DAYS\t90/' "$LOGIN_DEFS"
log_info "5.4.1.1 - PASS_MAX_DAYS = 90"
# 5.4.1.2: PASS_MIN_DAYS = 7
sed -i 's/^\s*PASS_MIN_DAYS.*/PASS_MIN_DAYS\t7/' "$LOGIN_DEFS"
log_info "5.4.1.2 - PASS_MIN_DAYS = 7"
# 5.4.1.3: PASS_WARN_AGE = 7
sed -i 's/^\s*PASS_WARN_AGE.*/PASS_WARN_AGE\t7/' "$LOGIN_DEFS"
log_info "5.4.1.3 - PASS_WARN_AGE = 7"
# 5.4.1.4: INACTIVE = 30
useradd -D -f 30 2>/dev/null
log_info "5.4.1.4 - INACTIVE = 30 (default for new users)"
# Apply PASS_MAX_DAYS, PASS_MIN_DAYS cho các user (UID >= 1000 và root)
_UID_MIN=$(awk '/^\s*UID_MIN/{print $2}' /etc/login.defs)
_UID_MIN="${_UID_MIN:-1000}"
# 1. Với các human user có mật khẩu hợp lệ (không bị khóa ! hoặc *, không để trống) -> đặt maxdays=90, mindays=7
awk -F: -v uid_min="$_UID_MIN" 'NR==FNR {shadow[$1]=$2; next} ($3>=uid_min || $1=="root") && $1!="nobody" {if (shadow[$1]!="" && shadow[$1]!~/^[!*]/) print $1}' /etc/shadow /etc/passwd | while read -r user; do
chage --maxdays 90 "$user" 2>/dev/null
chage --mindays 7 "$user" 2>/dev/null
chage --warndays 7 "$user" 2>/dev/null
chage --inactive 30 "$user" 2>/dev/null
done
# 2. Với các human user bị khóa hoặc chưa đặt mật khẩu (! hoặc * hoặc rỗng) như ldnobody -> khôi phục maxdays=99999, mindays=0 để tránh vi phạm tiêu chí 6.2.2 của CIS audit
awk -F: -v uid_min="$_UID_MIN" 'NR==FNR {shadow[$1]=$2; next} ($3>=uid_min || $1=="root") && $1!="nobody" {if (shadow[$1]=="" || shadow[$1]~/^[!*]/) print $1}' /etc/shadow /etc/passwd | while read -r user; do
chage -M 99999 -m 0 "$user" 2>/dev/null
done
log_info "5.4.1.x & 6.2.2 - Đã chuẩn hoá password aging policy cho active và locked users"
############################################################################
# ĐẶT MẬT KHẨU MỚI CHO NGƯỜI DÙNG HIỆN CÓ
############################################################################
log_subsection "ĐẶT MẬT KHẨU MỚI CHO NGƯỜI DÙNG HIỆN CÓ"
echo ""
echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}║ ĐẶT MẬT KHẨU MỚI CHO NGƯỜI DÙNG HIỆN CÓ ║${NC}"
echo -e "${YELLOW}║ ║${NC}"
echo -e "${YELLOW}║ Password policy mới đã được áp dụng: ║${NC}"
echo -e "${YELLOW}║ - Tối thiểu 8 ký tự, 4 loại (hoa, thường, số, đặc biệt)║${NC}"
echo -e "${YELLOW}║ - Hết hạn sau 90 ngày ║${NC}"
echo -e "${YELLOW}║ ║${NC}"
echo -e "${YELLOW}║ Bạn CẦN đặt mật khẩu mới tuân thủ policy để login được. ║${NC}"
echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
# Lấy UID_MIN để phân biệt system vs human users
_UID_MIN=$(awk '/^\s*UID_MIN/{print $2}' /etc/login.defs)
_UID_MIN="${_UID_MIN:-1000}"
# Lấy danh sách tất cả human users (UID >= UID_MIN) + root
HUMAN_USERS=()
while IFS=: read -r _uname _x _uid _rest; do
if [ "$_uid" -ge "$_UID_MIN" ] 2>/dev/null || [ "$_uname" = "root" ]; then
# Chỉ lấy user có shell đăng nhập được (không phải nologin/false)
_shell=$(getent passwd "$_uname" | cut -d: -f7)
if [[ "$_shell" != */nologin && "$_shell" != */false ]]; then
HUMAN_USERS+=("$_uname")
fi
fi
done < /etc/passwd
if [ ${#HUMAN_USERS[@]} -eq 0 ]; then
log_info "Không tìm thấy user cần đặt mật khẩu"
else
echo -e "${CYAN}Danh sách người dùng có thể đăng nhập:${NC}"
echo ""
for i in "${!HUMAN_USERS[@]}"; do
_u="${HUMAN_USERS[$i]}"
_uid=$(id -u "$_u" 2>/dev/null)
_groups=$(id -Gn "$_u" 2>/dev/null | tr ' ' ',')
printf " ${GREEN}%2d)${NC} %-20s ${CYAN}(UID: %s, Groups: %s)${NC}\n" $((i+1)) "$_u" "$_uid" "$_groups"
done
echo ""
echo -e "${CYAN}Chọn cách xử lý:${NC}"
echo " 1) Đặt mật khẩu cho TỪNG user (khuyến nghị)"
echo " 2) Đặt MỘT mật khẩu chung cho TẤT CẢ user"
echo " 3) Bỏ qua (CẢNH BÁO: có thể không login được nếu mật khẩu cũ không tuân thủ policy)"
read -rp "Lựa chọn [1/2/3] (mặc định: 1): " PW_CHOICE
PW_CHOICE="${PW_CHOICE:-1}"
case "$PW_CHOICE" in
1)
# Đặt mật khẩu cho từng user
echo ""
for _u in "${HUMAN_USERS[@]}"; do
echo -e "${YELLOW}────────────────────────────────────────${NC}"
echo -e "Đặt mật khẩu cho user: ${GREEN}${_u}${NC}"
echo -e "${CYAN}(Yêu cầu: ≥8 ký tự, gồm chữ hoa + chữ thường + số + ký tự đặc biệt)${NC}"
echo -e "Nhấn Enter để bỏ qua user này."
echo ""
# Đọc mật khẩu (ẩn)
read -rsp "Mật khẩu mới cho ${_u}: " _pw1
echo ""
if [ -z "$_pw1" ]; then
log_warn "Bỏ qua đặt mật khẩu cho: $_u"
continue
fi
read -rsp "Xác nhận mật khẩu: " _pw2
echo ""
if [ "$_pw1" != "$_pw2" ]; then
log_error "Mật khẩu không khớp! Bỏ qua user: $_u"
continue
fi
echo "$_u:$_pw1" | chpasswd 2>>"$LOG_FILE"
if [ $? -eq 0 ]; then
log_info "Đã đặt mật khẩu mới cho: $_u"
# Reset faillock counter
faillock --user "$_u" --reset 2>/dev/null
else
log_error "Lỗi khi đặt mật khẩu cho: $_u (có thể mật khẩu không đủ phức tạp)"
fi
done
echo -e "${YELLOW}────────────────────────────────────────${NC}"
;;
2)
# Đặt mật khẩu chung
echo ""
echo -e "${CYAN}(Yêu cầu: ≥8 ký tự, gồm chữ hoa + chữ thường + số + ký tự đặc biệt)${NC}"
read -rsp "Nhập mật khẩu chung cho tất cả user: " _pw1
echo ""
read -rsp "Xác nhận mật khẩu: " _pw2
echo ""
if [ "$_pw1" != "$_pw2" ]; then
log_error "Mật khẩu không khớp! Bỏ qua phần đặt mật khẩu."
elif [ -z "$_pw1" ]; then
log_warn "Mật khẩu trống! Bỏ qua phần đặt mật khẩu."
else
for _u in "${HUMAN_USERS[@]}"; do
echo "$_u:$_pw1" | chpasswd 2>>"$LOG_FILE"
if [ $? -eq 0 ]; then
log_info "Đã đặt mật khẩu mới cho: $_u"
faillock --user "$_u" --reset 2>/dev/null
else
log_error "Lỗi khi đặt mật khẩu cho: $_u"
fi
done
fi
;;
3)
log_warn "Đã bỏ qua đặt mật khẩu. Hãy đảm bảo mật khẩu hiện tại tuân thủ policy mới!"
;;
*)
log_warn "Lựa chọn không hợp lệ. Bỏ qua phần đặt mật khẩu."
;;
esac
# Xoá biến mật khẩu khỏi bộ nhớ
unset _pw1 _pw2
fi
echo ""
############################################################################
# 5.4.2: Vô hiệu hoá đăng nhập bằng tài khoản hệ thống
############################################################################
log_subsection "5.4.2 - System account hardening"
UID_MIN=$(awk '/^\s*UID_MIN/{print $2}' /etc/login.defs)
# Set nologin shell cho system accounts
awk -F: -v uid_min="$UID_MIN" '($1!~/^(root|halt|sync|shutdown|nfsnobody)$/ && $3<uid_min && $7!~/^(\/usr)?\/sbin\/nologin(\/)?\$/ && $7!~/(\/usr)?\/bin\/false(\/)?\$/) { print $1 }' /etc/passwd | while read -r user; do
usermod -s "$(which nologin)" "$user" 2>/dev/null
done
# Lock system accounts (ngoại trừ root)
awk -F: -v uid_min="$UID_MIN" '($1!="root" && $1!~/^\+/ && $3<uid_min) {print $1}' /etc/passwd | xargs -I '{}' passwd -S '{}' 2>/dev/null | awk '($2!="L" && $2!="LK") {print $1}' | while read -r user; do
usermod -L "$user" 2>/dev/null
done
log_info "5.4.2 - Đã vô hiệu hoá đăng nhập cho system accounts"
############################################################################
# 5.4.3: Root GID 0
############################################################################
usermod -g 0 root 2>/dev/null
log_info "5.4.3 - Root GID = 0"
############################################################################
# 5.4.4: umask 027
############################################################################
log_subsection "5.4.4 - umask 027"
# /etc/login.defs
sed -i 's/^\s*UMASK.*/UMASK\t\t027/' "$LOGIN_DEFS"
if ! grep -q "^USERGROUPS_ENAB" "$LOGIN_DEFS"; then
echo 'USERGROUPS_ENAB no' >> "$LOGIN_DEFS"
else
sed -i 's/^\s*USERGROUPS_ENAB.*/USERGROUPS_ENAB no/' "$LOGIN_DEFS"
fi
# /etc/profile.d/
UMASK_PROFILE="/etc/profile.d/cis-umask.sh"
cat > "$UMASK_PROFILE" << 'EOF'
# CIS Benchmark v2.0.2 - Default umask
umask 027
EOF
chmod 644 "$UMASK_PROFILE"
log_info "5.4.4 - Đã cấu hình umask 027"
############################################################################
# 5.4.5: Shell timeout TMOUT=900
############################################################################
log_subsection "5.4.5 - Shell timeout"
TMOUT_PROFILE="/etc/profile.d/cis-tmout.sh"
cat > "$TMOUT_PROFILE" << 'EOF'
# CIS Benchmark v2.0.2 - Shell timeout
readonly TMOUT=900 ; export TMOUT
EOF
chmod 644 "$TMOUT_PROFILE"
log_info "5.4.5 - Đã cấu hình TMOUT=900"
############################################################################
# 5.4.6: Hạn chế su
############################################################################
log_subsection "5.4.6 - Hạn chế truy cập su"
# Tạo group sugroup nếu chưa có
if ! grep -q "^sugroup:" /etc/group; then
groupadd sugroup 2>/dev/null
log_info "5.4.6 - Đã tạo group sugroup"
fi
# Cấu hình PAM su
PAM_SU="/etc/pam.d/su"
backup_file "$PAM_SU"
if ! grep -q "pam_wheel.so.*use_uid.*group=sugroup" "$PAM_SU"; then
# Thêm dòng auth required pam_wheel.so
sed -i '/pam_rootok.so/a auth required pam_wheel.so use_uid group=sugroup' "$PAM_SU"
fi
log_info "5.4.6 - Đã cấu hình hạn chế su (pam_wheel.so + sugroup)"
############################################################################
############################################################################
## SECTION 6: SYSTEM MAINTENANCE ##
############################################################################
############################################################################
log_section "SECTION 6: SYSTEM MAINTENANCE"
############################################################################
# 6.1.1 - 6.1.8: Phân quyền system files
############################################################################
log_subsection "6.1.1-8 - Phân quyền system files"
# /etc/passwd
chown root:root /etc/passwd
chmod 644 /etc/passwd
log_info "6.1.1 - /etc/passwd: 644 root:root"
# /etc/shadow
chown root:root /etc/shadow
chmod 0640 /etc/shadow
log_info "6.1.2 - /etc/shadow: 0640 root:root"
# /etc/group
chown root:root /etc/group
chmod 644 /etc/group
log_info "6.1.3 - /etc/group: 644 root:root"
# /etc/gshadow
chown root:root /etc/gshadow
chmod 0640 /etc/gshadow
log_info "6.1.4 - /etc/gshadow: 0640 root:root"
# /etc/passwd-
chown root:root /etc/passwd-
chmod u-x,go-wx /etc/passwd-
log_info "6.1.5 - /etc/passwd-: phân quyền"
# /etc/shadow-
chown root:root /etc/shadow-
chmod 0640 /etc/shadow-
log_info "6.1.6 - /etc/shadow-: 0640 root:root"
# /etc/group-
chown root:root /etc/group-
chmod u-x,go-wx /etc/group-
log_info "6.1.7 - /etc/group-: phân quyền"
# /etc/gshadow-
chown root:root /etc/gshadow-
chmod 0640 /etc/gshadow-
log_info "6.1.8 - /etc/gshadow-: 0640 root:root"
############################################################################
# 6.1.9: Xoá file world-writable
############################################################################
log_subsection "6.1.9 - World-writable files"
WW_COUNT=$(df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -path /proc -prune -o -type f -perm -0002 -print 2>/dev/null | wc -l)
if [ "$WW_COUNT" -ne 0 ]; then
df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -path /proc -prune -o -type f -perm -0002 -print 2>/dev/null | while read -r f; do
chmod o-w "$f" 2>/dev/null
done
log_info "6.1.9 - Đã xoá quyền world-writable cho $WW_COUNT files"
else
log_info "6.1.9 - Không có file world-writable"
fi
############################################################################
# 6.2.1: Shadowed passwords
############################################################################
log_subsection "6.2.x - User/group integrity & permissions"
if awk -F: '($2 != "x" ) { print $1 }' /etc/passwd | grep -q .; then
sed -e 's/^\([a-zA-Z0-9_]*\):[^:]*:/\1:x:/' -i /etc/passwd
log_info "6.2.1 - Đã cấu hình shadowed passwords"
else
log_info "6.2.1 - Shadowed passwords đã OK"
fi
############################################################################
# 6.2.9: Đảm bảo tính toàn vẹn cho biến môi trường PATH của root
############################################################################
log_subsection "6.2.9 - PATH của root integrity"
RPCV="$(sudo -Hiu root env 2>/dev/null | grep '^PATH=' | cut -d= -f2)"
for x in $(echo "$RPCV" | tr ":" " "); do
if [ ! -d "$x" ]; then
# Nếu đường dẫn trong PATH (như /snap/bin) chưa tồn tại, tạo thư mục để pass audit check
mkdir -p "$x" 2>/dev/null
chmod 755 "$x" 2>/dev/null
chown root:root "$x" 2>/dev/null
log_info "6.2.9 - Đã tạo thư mục missing trong PATH: $x"
else
chmod go-w "$x" 2>/dev/null
chown root:root "$x" 2>/dev/null
fi
done
log_info "6.2.9 - Đã chuẩn hoá quyền và tính toàn vẹn cho PATH của root"
############################################################################
# 6.2.13: Đảm bảo quyền thư mục home của người dùng có mức bảo mật cao (max 750)
############################################################################
log_subsection "6.2.13 - Quyền thư mục home của người dùng"
awk -F: '($1!~/^(halt|sync|shutdown|nfsnobody)$/ && $7!~/^(\/usr)?\/sbin\/nologin(\/)?$/ && $7!~/(\/usr)?\/bin\/false(\/)?$/) {print $6}' /etc/passwd | while read -r dir; do
if [ -d "$dir" ]; then
chmod g-w,o-rwx "$dir" 2>/dev/null
fi
done
log_info "6.2.13 - Đã phân quyền g-w,o-rwx (tối đa 750) cho tất cả thư mục home của người dùng"
############################################################################
############################################################################
## HOÀN THÀNH ##
############################################################################
############################################################################
log_section "HOÀN THÀNH HARDENING"
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ HARDENING CIS BENCHMARK v2.0.2 ĐÃ HOÀN THÀNH ║${NC}"
echo -e "${GREEN}╠══════════════════════════════════════════════════════════════╣${NC}"
echo -e "${GREEN}${NC} "
echo -e "${GREEN}${NC} Backup: ${CYAN}$BACKUP_DIR${NC}"
echo -e "${GREEN}${NC} Log file: ${CYAN}$LOG_FILE${NC}"
echo -e "${GREEN}${NC} "
echo -e "${GREEN}${NC} ${YELLOW}BƯỚC TIẾP THEO:${NC} "
echo -e "${GREEN}${NC} 1. Chạy audit script để verify: "
echo -e "${GREEN}${NC} ${CYAN}bash audit_cis_ubuntu_v202.sh${NC} "
echo -e "${GREEN}${NC} 2. Kiểm tra SSH login vẫn hoạt động "
echo -e "${GREEN}${NC} 3. Reboot server và xác nhận "
echo -e "${GREEN}${NC} "
echo -e "${GREEN}${NC} ${RED}LƯU Ý QUAN TRỌNG:${NC} "
echo -e "${GREEN}${NC} - Đặt mật khẩu root (nếu chưa): ${CYAN}passwd root${NC} "
echo -e "${GREEN}${NC} - Kiểm tra SSH: ${CYAN}ssh -p $SSH_PORT user@hostname${NC} "
if [ -n "$SSH_ALLOW_USERS" ]; then
echo -e "${GREEN}${NC} - SSH AllowUsers: ${CYAN}$SSH_ALLOW_USERS${NC} "
fi
echo -e "${GREEN}${NC} - Cấu hình rsyslog remote log (4.1.1.3): thủ công "
echo -e "${GREEN}${NC} "
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
log_info "Script hoàn thành tại $(date +"%Y-%m-%d %H:%M:%S")"
log_info "Tổng thời gian: $SECONDS giây"