centos 基线加固脚本(等保三级合规)适用centos、redhat7.x-8.x、rocky8.x、openEuler 20.x-22.x
·
更新日志
2025/11/01 全部代码逻辑全部重写,基线配置项不变。口令重复次数限制、配置口令生存期、配置口令锁定策略,这三项策略已注释掉不运行,建议有自动改密措施的堡垒机或运维机使用。
2024/09/12 增加支持麒麟V10操作系统、默认注释掉口令生存期及口令重复次数限制
2024/05/23 修正了6系列操作系统用户识别的BUG
2024/05/28 改变信息显示方式
基线加固项列表
配置SSH合规项
- 限制/etc/ssh/sshd_config的访问权限
- 限制SSH服务使用的密钥文件权限
- 使用更加安全的Ciphers算法
- 使用更加安全的MAC算法
- 确保SSH中HostbasedAuthentication关闭
- 确保SSH中PermitEmptyPasswords被禁用
- 确保配置了SSH空闲超时间隔
- 确保设置了SSH警告提示信息
- 确保SSH中X11转发被禁用
- 确保SSH中MaxAuthTries设置小于等于4
- 确保SSH中IgnoreRhosts被允许
- 确保SSH中PermitUserEnvironment被禁用
- 确保SSH中LoginGraceTime设置为一分钟或更短
- 限制root用户SSH远程登录
- 限制仅允许SSH协议2版本连接
- 确保SSH中LogLevel设置为INFO
- 检查SSH访问是否受限制
- 限制SFTP用户访问目录
配置OS合规项
- 配置操作系统的审计记录保存180天
- 配置口令生存期 --> PASS_MAX_DAYS
- 配置口令生存期 --> PASS_MIN_DAYS
- 配置口令生存期 --> PASS_MIN_LEN
- 配置口令生存期 --> PASS_WARN_AGE
- 配置口令复杂度
- 检查文件与目录缺省权限控制
- 检查登陆超时时间设置
- 禁止wheel组以外的用户使用su命令
- 把现有登陆权限的用户加入wheel组
- 口令重复次数限制
- 配置用户最小授权
- 设置关键文件的属性
- 检查不活跃的密码锁定是否小于等于30天
- 记录守护进程产生的DEBUG日志
- 检查系统core dump状态
- 禁止组合键关机
- 限制历史命令
- 禁止ICMP重定向
- 禁止IP源路由
- 确保忽略广播的ICMP请求
- 检查可疑数据包是否被记录
- 配置口令锁定策略
- 正在重建yum源缓存
- 检查AIDE是否安装
- 检查AIDE是否安装 --> 正在安装aide服务
- 检查audit是否安装
- 检查audit服务是否已启动
- 检查audit日志是否不会自动删除
- 检查系统用户状态. . .
- 系统中有登录权限的用户有:root . . .
- 系统中UID=0的用户有:root . . .
- 系统中无空密码用户. . .
- 正在重启SSH服务
- 正在重新加载profile用户参数
- 正在重新加载bashrc用户参数
- 正在加载用户内核参数
#!/bin/bash
########################## 蜈蚣出品 #########################
# Function : ssh centos baseline #
# Platform : Centos6.x-8.x & Rocky8.x & openEuler 20.x-22.x #
# Version : 2.0.0 #
# Date : 2025-11-01 #
#############################################################
clear
OLD_LANG=$LANG
export LANG="en_US.UTF-8"
# ------------------------------- 变量定义 -------------------------------
SHELL_HOME="/opt/baseline"
LOCK_FILE="/tmp/$(basename "$0").lock"
BACKUP_DIR="${SHELL_HOME}/backup/$(date +%Y%m%d%H%M%S)"
LOG_FILE="${SHELL_HOME}/log/$(date +%Y%m%d%H%M%S).log"
SUPPORTED_DISTROS=("centos:7-8" "rhel:7-8" "rocky:8-8" "openeuler:20-24" "kylin:10-10" "hce:1-2")
# ------------------------------- 创建目录 -------------------------------
mkdir -p ${SHELL_HOME} ${SHELL_HOME}/log ${SHELL_HOME}/backup &>/dev/null
# --------------------------- 备份文件路径映射 ---------------------------
declare -A FILE_MAP=(
[sshd_config]="/etc/ssh/sshd_config"
[logrotate.conf]="/etc/logrotate.conf"
[login.defs]="/etc/login.defs"
[password-auth]="/etc/pam.d/password-auth"
[system-auth]="/etc/pam.d/system-auth"
[pwquality.conf]="/etc/security/pwquality.conf"
[profile]="/etc/profile"
[bashrc]="/etc/bashrc"
[pamdsu]="/etc/pam.d/su"
[sudoers]="/etc/sudoers"
[sudouser]="/etc/sudoers.d/sudouser"
[rsyslog.conf]="/etc/rsyslog.conf"
[limits.conf]="/etc/security/limits.conf"
[sysctl.conf]="/etc/sysctl.conf"
[auditd.conf]="/etc/audit/auditd.conf"
[ctrl-alt-del.target]="/usr/lib/systemd/system/ctrl-alt-del.target"
)
# ------------------------------- 日志函数 -------------------------------
log() {
local type=$1 msg=$2 nwrap=$3
local reset="\033[0m"
case $type in
INFO) color="\033[0m";;
SUCC) color="\033[92m";;
WARN) color="\033[93m";;
ATTN) color="\033[96m";;
ERROR) color="\033[91m";;
*) color="\033[0m";;
esac
local time=$(date +"%Y-%m-%d %H:%M:%S")
echo -${nwrap}e "[${time}] ${color}[${type}] ${msg}${reset}" | tee -a ${LOG_FILE} 2>/dev/null
}
log2() {
local type=$1
local reset="\033[0m"
case $type in
SUCC) color="\033[92m";;
WARN) color="\033[93m";;
PASS) color="\033[96m";;
ERROR) color="\033[91m";;
esac
echo -e " ${color}[${type}]${reset}" | tee -a ${LOG_FILE} 2>/dev/null
}
# ------------------------------- 系统检查 -------------------------------
check_root() {
[[ $EUID -ne 0 ]] && { log ERROR "必须以root用户或root权限运行"; exit 1; }
}
check_os() {
! command -v bc &>/dev/null && { log ERROR "需要bc计算工具,请安装"; exit 1; }
[[ ! -f /etc/os-release ]] && { log ERROR "无法识别操作系统"; exit 1; }
source /etc/os-release
local dist_id=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
local version_id=$(echo "$VERSION_ID" | cut -d. -f1 | sed 's/[^0-9]//g')
local supported=false
for dist in "${SUPPORTED_DISTROS[@]}"; do
IFS=':' read -r name range <<< "$dist"
if [[ "$dist_id" == "$name" ]]; then
IFS='-' read -r min max <<< "$range"
if (( $(echo "$version_id >= $min" | bc -l) )) && (( $(echo "$version_id <= $max" | bc -l) )); then
supported=true
break
fi
fi
done
$supported || { log ERROR "不支持的操作系统: $ID $VERSION_ID"; exit 1; }
log INFO "检测到支持的操作系统: $ID $VERSION_ID"
}
# ------------------------------- 锁机制 -------------------------------
acquire_lock() {
exec 200>"$LOCK_FILE"
flock -xn 200 || { log ERROR "脚本已在运行,请勿重复执行"; exit 1; }
echo $$ >&200
}
release_lock() {
flock -u 200
rm -f "$LOCK_FILE"
}
# ------------------------------- 倒计时 -------------------------------
countdown() {
local count=11
local time=$(date +"%Y-%m-%d %H:%M:%S")
log ATTN "即将对系统进行基线配置,过程将对SSH等多个配置文件进行修改,可能会造成SSH重启失败。"
log ATTN "脚本运行过程中请保持活动的连接窗口,切勿中途中断!避免因配置不完整无法重连服务器。"
log ATTN "建议复制一个连接窗口以备不时之需,或自行配置Telnet服务预留另一个远程连接通道。"
echo -en [`date +"%Y-%m-%d %H:%M:%S"`] "\033[96m[ATTN] 基线脚本即将开始,如暂不运行请在倒计时结束前按Ctrl+C终止脚本,倒计时: \033[0m"
tput sc
while true
do
if [[ $count -ge 1 ]] ; then
let count--
sleep 1
tput rc
tput ed
echo -en "\033[31m$count \033[0m"
else
break
fi
done
echo -e ""
}
# ------------------------------- 版本检测 -------------------------------
get_systemusers() {
systemusers=$(awk -F: '($3 >= 1000 && $3 <=65000) && ($7=="/bin/bash") {print $1}' /etc/passwd | tr "\n" " " | sed -e 's/,$/\n/' | sed 's/[ ]*$//g')
}
# ------------------------------- 备份与回滚 -------------------------------
backup_files() {
local configfile=$1
local configpar=$2
local file_path backup_file
mkdir -p "$BACKUP_DIR"
log INFO "正在备份${configfile}文件..."
[[ -z "${FILE_MAP[$configfile]}" ]] && { log ERROR "未知的配置文件: $configfile"; return 1; }
file_path="${FILE_MAP[$configfile]}"
backup_file="${BACKUP_DIR}/${configpar}_${configfile}.tar.gz"
[[ ! -f "$file_path" ]] && { log WARN "文件 $file_path 不存在"; return 1; }
tar czPf "$backup_file" "$file_path" 1>/dev/null 2>>"${LOG_FILE}"
}
rollback() {
local configfile=$1
local configpar=$2
local file_path backup_file
log WARN "检测到配置失败,启动回滚 . . ."
[[ -z "${FILE_MAP[$configfile]}" ]] && { log ERROR "未知的配置文件: $configfile"; return 1; }
file_path="${FILE_MAP[$configfile]}"
backup_file="${BACKUP_DIR}/${configpar}_${configfile}.tar.gz"
[[ ! -f "$backup_file" ]] && { log WARN "文件 $backup_file 不存在"; return 1; }
tar xzPf "$backup_file" 1>/dev/null 2>>"${LOG_FILE}"
log WARN "${pkg}回滚完成"
}
# ------------------------------- 安装主体 -------------------------------
backup_all() {
local config
log INFO "开始批量备份所有配置文件..."
for config in "${!FILE_MAP[@]}"; do
backup_files "$config" "${FUNCNAME[0]}"
done
log INFO "批量备份完成"
return 0
}
sed_config() {
local key=$1
local value=$2
local confpath=$3
[[ -n $4 ]] && local check_value=$4 || local check_value=$2
if grep -qE "^[[:space:]]*${check_value}" ${confpath} 2>>${LOG_FILE} ; then
log2 PASS
return 0
else
if grep -qE "^[[:space:]]*#?${key}" ${confpath} 2>>${LOG_FILE} ; then
sed -i "/^\s*${key}/ s|^\s*||" ${confpath} 2>>${LOG_FILE}
sed -i "/^\s*${key}/ s|^\(.*\)$|#\1|g" ${confpath} 2>>${LOG_FILE}
sed -i "0,/^#${key}.*/s|^#${key}.*|${value}|" ${confpath} 2>>${LOG_FILE}
else
echo -e "${value}" >> ${confpath} 2>>${LOG_FILE}
fi
grep -qE "^[[:space:]]*${check_value}" ${confpath} 2>>${LOG_FILE} && { log2 SUCC ; return 0; } || return 1
fi
}
sshd_config() {
log ATTN "开始执行配置SSH合规项. . ."
backup_files sshd_config ${FUNCNAME[0]}
log INFO "正在配置/etc/ssh/sshd_config的访问权限. . ."
chown root:root /etc/ssh/sshd_config 2>>${LOG_FILE}
chmod og-rwx /etc/ssh/sshd_config 2>>${LOG_FILE}
log INFO "正在配置SSH服务使用的密钥文件权限. . ."
chmod 400 /etc/ssh/*key 2>>${LOG_FILE}
chmod 400 /etc/ssh/*key.pub 2>>${LOG_FILE}
chown -R root:root /etc/ssh/*key 2>>${LOG_FILE}
chown -R root:root /etc/ssh/*key.pub 2>>${LOG_FILE}
log INFO "限制root用户SSH远程登录" "n"
sed_config "PermitRootLogin" "PermitRootLogin no" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "使用更加安全的Ciphers算法" "n"
sed_config "Ciphers" "Ciphers aes128-ctr,aes192-ctr,aes256-ctr" "/etc/ssh/sshd_config" "Ciphers.*aes128-ctr.*aes192-ctr.*aes256-ctr" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "使用更加安全的MAC算法" "n"
sed_config "MACs" "MACs hmac-sha2-512,hmac-sha2-256" "/etc/ssh/sshd_config" "MACs.*hmac-sha2-512.*hmac-sha2-256" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置HostbasedAuthentication为关闭" "n"
sed_config "HostbasedAuthentication" "HostbasedAuthentication no" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置PermitEmptyPasswords为禁用" "n"
sed_config "PermitEmptyPasswords" "PermitEmptyPasswords no" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置SSH空闲超时间隔_配置1" "n"
sed_config "ClientAliveInterval" "ClientAliveInterval 300" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置SSH空闲超时间隔_配置2" "n"
sed_config "ClientAliveCountMax" "ClientAliveCountMax 0" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置X11转发为禁用" "n"
sed_config "X11Forwarding" "X11Forwarding no" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置MaxAuthTries小于等于4" "n"
sed_config "MaxAuthTries" "MaxAuthTries 4" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置IgnoreRhosts为允许" "n"
sed_config "IgnoreRhosts" "IgnoreRhosts yes" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置PermitUserEnvironment为禁用" "n"
sed_config "PermitUserEnvironment" "PermitUserEnvironment no" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置LoginGraceTime为一分钟或更短" "n"
sed_config "LoginGraceTime" "LoginGraceTime 60" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "限制仅允许SSH协议2版本连接" "n"
sed_config "Protocol" "Protocol 2" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置LogLevel为INFO" "n"
sed_config "LogLevel" "LogLevel INFO" "/etc/ssh/sshd_config" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置SSH警告提示信息" "n"
sed_config "Banner" "Banner /etc/ssh/issue.Banner" "/etc/ssh/sshd_config" "Banner" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
[[ ! -f /etc/ssh/issue.Banner ]] && echo -e "\nAuthorized users only. All activity may be monitored and reported.\n" > /etc/ssh/issue.Banner
log INFO "配置SSH访问开启用户限制" "n"
sed_config "AllowUsers" "AllowUsers root ${systemusers}" "/etc/ssh/sshd_config" "AllowUsers root ${systemusers}" && log ATTN "检查SSH访问是否开启用户限制 --> 已配置root ${systemusers}用户允许SSH访问" || { log2 ERROR; rollback sshd_config ${FUNCNAME[0]}; return_no=1; }
log INFO "配置SFTP服务使用internal-sftp" "n"
sed_config "Subsystem" "Subsystem sftp internal-sftp -l INFO -f AUTH" "/etc/ssh/sshd_config"
log INFO "限制SFTP用户访问目录" "n"
grep -qE "^sftpgroup" /etc/group || groupadd sftpgroup
if ! id -u sftpuser &>/dev/null ; then
useradd -m -s /sbin/nologin sftpuser
usermod -a -G sftpgroup sftpuser
chown root:root /home/sftpuser
fi
# 此部分必须放在sshd_config文件的最后
grep -qE "^#?Match.*" /etc/ssh/sshd_config && { sed -i "/^#Match.*/d" /etc/ssh/sshd_config; sed -i "/^Match.*/d" /etc/ssh/sshd_config; }
grep -qE "^#?[[:blank:]]X11Forwarding.*" /etc/ssh/sshd_config && { sed -i "/^#[[:blank:]]X11Forwarding.*/d" /etc/ssh/sshd_config; sed -i "/^[[:blank:]]X11Forwarding.*/d" /etc/ssh/sshd_config; }
grep -qE "^#?[[:blank:]]AllowTcpForwarding.*" /etc/ssh/sshd_config && { sed -i "/^#[[:blank:]]AllowTcpForwarding.*/d" /etc/ssh/sshd_config; sed -i "/^[[:blank:]]AllowTcpForwarding.*/d" /etc/ssh/sshd_config; }
grep -qE "^#?[[:blank:]]PermitTTY.*" /etc/ssh/sshd_config && { sed -i "/^#[[:blank:]]PermitTTY.*/d" /etc/ssh/sshd_config; sed -i "/^[[:blank:]]PermitTTY.*/d" /etc/ssh/sshd_config; }
grep -qE "^#?.*ForceCommand.*" /etc/ssh/sshd_config && { sed -i "/^#.*ForceCommand.*/d" /etc/ssh/sshd_config; sed -i "/^.*ForceCommand.*/d" /etc/ssh/sshd_config; }
grep -qE "^#?.*ChrootDirectory.*" /etc/ssh/sshd_config && { sed -i "/^#.*ChrootDirectory.*/d" /etc/ssh/sshd_config; sed -i "/^.*ChrootDirectory.*/d" /etc/ssh/sshd_config; }
echo -e "Match Group sftpgroup" >> /etc/ssh/sshd_config
echo -e "\tX11Forwarding no" >> /etc/ssh/sshd_config
echo -e "\tAllowTcpForwarding no" >> /etc/ssh/sshd_config
echo -e "\tForceCommand internal-sftp" >> /etc/ssh/sshd_config
echo -e "\tChrootDirectory /home/sftpuser" >> /etc/ssh/sshd_config
log2 SUCC
log ATTN "正在重启openssh服务. . ."
systemctl restart sshd 1>/dev/null 2>>${LOG_FILE} && log SUCC "openssh服务启动成功" || { log ERROR "openssh服务启动失败"; rollback sshd_config ${FUNCNAME[0]}; return 1; }
[[ ! -n $return_no ]] && local return_no=0
return "$return_no"
}
baseline_os() {
log ATTN "开始执行配置操作系统合规项. . ."
log INFO "正在配置用户最小授权. . ."
chmod 700 /etc/security &>/dev/null
chmod 644 /etc/passwd &>/dev/null
chmod 644 /etc/group &>/dev/null
chmod 644 /etc/services &>/dev/null
chmod 400 /etc/shadow &>/dev/null
chmod 400 /etc/gshadow &>/dev/null
[[ -f /etc/xinetd.conf ]] && chmod 600 /etc/xinetd.conf &>/dev/null
chown root:root /etc/security &>/dev/null
chown root:root /etc/passwd &>/dev/null
chown root:root /etc/group &>/dev/null
chown root:root /etc/services &>/dev/null
chown root:root /etc/shadow &>/dev/null
chown root:root /etc/gshadow &>/dev/null
log INFO "开始设置关键文件的属性. . ."
chattr +a /var/log/messages &>/dev/null
usermod -s /sbin/nologin sync &>/dev/null
usermod -s /sbin/nologin halt &>/dev/null
usermod -s /sbin/nologin shutdown &>/dev/null
log INFO "正在检查不活跃的密码锁定是否小于等于30天. . ."
for systemusers_i in $systemusers ; do
log ATTN "检查不活跃的密码锁定是否小于等于30天 --> 正在配置用户$systemusers_i"
chage --inactive 30 $systemusers_i
done
logrotate() {
backup_files logrotate.conf ${FUNCNAME[0]}
log INFO "配置操作系统的审计记录保存180天" "n"
sed_config "rotate" "rotate 28" "/etc/logrotate.conf" "rotate.*28" || { log2 ERROR; rollback logrotate.conf ${FUNCNAME[0]}; return_no=1; }
}
pwdcomp() {
backup_files password-auth ${FUNCNAME[0]}
backup_files system-auth ${FUNCNAME[0]}
backup_files pwquality.conf ${FUNCNAME[0]}
log INFO "配置口令复杂度_配置1" "n"
sed_config "password.*requisite.*pam_pwquality.so" "password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= minlen=8 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1" "/etc/pam.d/password-auth" "password.*requisite.*pam_pwquality.so.*try_first_pass.*local_users_only.*retry=3.*authtok_type=.*minlen=8.*dcredit=-1.*ucredit=-1.*ocredit=-1.*lcredit=-1" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置2" "n"
sed_config "password.*requisite.*pam_pwquality.so" "password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type= minlen=8 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1" "/etc/pam.d/system-auth" "password.*requisite.*pam_pwquality.so.*try_first_pass.*local_users_only.*retry=3.*authtok_type=.*minlen=8.*dcredit=-1.*ucredit=-1.*ocredit=-1.*lcredit=-1" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置3" "n"
sed_config "minlen" "minlen = 8" "/etc/security/pwquality.conf" "minlen.*=.*8" || { log2 ERROR; rollback pwquality.conf ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置4" "n"
sed_config "dcredit" "dcredit = -1" "/etc/security/pwquality.conf" "dcredit.*=.*-1" || { log2 ERROR; rollback pwquality.conf ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置5" "n"
sed_config "ucredit" "ucredit = -1" "/etc/security/pwquality.conf" "ucredit.*=.*-1" || { log2 ERROR; rollback pwquality.conf ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置6" "n"
sed_config "lcredit" "lcredit = -1" "/etc/security/pwquality.conf" "lcredit.*=.*-1" || { log2 ERROR; rollback pwquality.conf ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令复杂度_配置7" "n"
sed_config "ocredit" "ocredit = -1" "/etc/security/pwquality.conf" "ocredit.*=.*-1" || { log2 ERROR; rollback pwquality.conf ${FUNCNAME[0]}; return_no=1; }
}
pwdreplim() {
backup_files password-auth ${FUNCNAME[0]}
backup_files system-auth ${FUNCNAME[0]}
log INFO "口令重复次数限制_配置1" "n"
sed_config "password.*sufficient.*pam_unix.so" "password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5" "/etc/pam.d/password-auth" "password.*sufficient.*pam_unix.so.*sha512.*shadow.*nullok.*try_first_pass.*use_authtok.*remember=5" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "口令重复次数限制_配置2" "n"
sed_config "password.*sufficient.*pam_unix.so" "password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok remember=5" "/etc/pam.d/system-auth" "password.*sufficient.*pam_unix.so.*sha512.*shadow.*nullok.*try_first_pass.*use_authtok.*remember=5" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
}
pwdlife() {
backup_files login.defs ${FUNCNAME[0]}
log INFO "配置口令生存期 --> PASS_MAX_DAYS" "n"
sed_config "PASS_MAX_DAYS.*" "PASS_MAX_DAYS\t90" "/etc/login.defs" "PASS_MAX_DAYS.*90" || { log2 ERROR; rollback login.defs ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令生存期 --> PASS_MIN_DAYS" "n"
sed_config "PASS_MIN_DAYS.*" "PASS_MIN_DAYS\t10" "/etc/login.defs" "PASS_MIN_DAYS.*10" || { log2 ERROR; rollback login.defs ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令生存期 --> PASS_MIN_LEN" "n"
sed_config "PASS_MIN_LEN.*" "PASS_MIN_LEN\t8" "/etc/login.defs" "PASS_MIN_LEN.*8" || { log2 ERROR; rollback login.defs ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令生存期 --> PASS_WARN_AGE" "n"
sed_config "PASS_WARN_AGE.*" "PASS_WARN_AGE\t7" "/etc/login.defs" "PASS_WARN_AGE.*7" || { log2 ERROR; rollback login.defs ${FUNCNAME[0]}; return_no=1; }
log INFO "正在为已有用户配置口令生存期 . . ."
for systemusers_i in $systemusers ; do
log ATTN "正在为已有用户配置口令生存期 --> $systemusers_i" "n"
chage -M 90 -m 10 -W 7 $systemusers_i && log2 SUCC || { log2 ERROR; rollback systemusers_chage; return_no=1; }
done
}
faillock() {
backup_files password-auth ${FUNCNAME[0]}
backup_files system-auth ${FUNCNAME[0]}
log INFO "配置口令锁定策略_配置1" "n"
sed_config "auth.*required.*pam_faillock.so" "auth required pam_faillock.so preauth audit silent deny=5 unlock_time=180" "/etc/pam.d/password-auth" "auth.*required.*pam_faillock.so.*preauth.*audit.*silent.*deny=5.*unlock_time=180" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置2" "n"
sed_config "auth.*\[.*success.*=.*1.*default.*=.*bad.*\].*pam_unix.so" "auth [success=1 default=bad] pam_unix.so" "/etc/pam.d/password-auth" "auth.*\[.*success.*=.*1.*default.*=.*bad.*\].*pam_unix.so" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置3" "n"
sed_config "auth.*\[.*default.*=.*die.*\].*pam_faillock.so" "auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=180" "/etc/pam.d/password-auth" "auth.*\[.*default.*=.*die.*\].*pam_faillock.so.*authfail.*audit.*deny=5.*unlock_time=180" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置4" "n"
sed_config "auth.*sufficient.*pam_faillock.so" "auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=180" "/etc/pam.d/password-auth" "auth.*sufficient.*pam_faillock.so.*authsucc.*audit.*deny=5.*unlock_time=180" || { log2 ERROR; rollback password-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置5" "n"
sed_config "auth.*required.*pam_faillock.so" "auth required pam_faillock.so preauth audit silent deny=5 unlock_time=180" "/etc/pam.d/system-auth" "auth.*required.*pam_faillock.so.*preauth.*audit.*silent.*deny=5.*unlock_time=180" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置6" "n"
sed_config "auth.*\[.*success.*=.*1.*default.*=.*bad.*\].*pam_unix.so" "auth [success=1 default=bad] pam_unix.so" "/etc/pam.d/system-auth" "auth.*\[.*success.*=.*1.*default.*=.*bad.*\].*pam_unix.so" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置7" "n"
sed_config "auth.*\[.*default.*=.*die.*\].*pam_faillock.so" "auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=180" "/etc/pam.d/system-auth" "auth.*\[.*default.*=.*die.*\].*pam_faillock.so.*authfail.*audit.*deny=5.*unlock_time=180" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
log INFO "配置口令锁定策略_配置8" "n"
sed_config "auth.*sufficient.*pam_faillock.so" "auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=180" "/etc/pam.d/system-auth" "auth.*sufficient.*pam_faillock.so.*authsucc.*audit.*deny=5.*unlock_time=180" || { log2 ERROR; rollback system-auth ${FUNCNAME[0]}; return_no=1; }
}
fileumask() {
backup_files profile ${FUNCNAME[0]}
backup_files bashrc ${FUNCNAME[0]}
log INFO "配置文件与目录缺省权限控制_配置1" "n"
sed_config "umask.*0[1-9][1-9]" "\tumask 027" "/etc/profile" "umask.*027" || { log2 ERROR; rollback profile ${FUNCNAME[0]}; return_no=1; }
log INFO "配置文件与目录缺省权限控制_配置2" "n"
sed_config "umask.*0[1-9][1-9]" "\tumask 027" "/etc/bashrc" "umask.*027" || { log2 ERROR; rollback bashrc ${FUNCNAME[0]}; return_no=1; }
}
logtmout() {
backup_files profile ${FUNCNAME[0]}
log INFO "配置登陆超时时间" "n"
sed_config "[a-z].*TMOUT" "export TMOUT=300" "/etc/profile" "[a-z].*TMOUT.*=.*300" || { log2 ERROR; rollback profile ${FUNCNAME[0]}; return_no=1; }
}
onlywheel() {
backup_files pamdsu ${FUNCNAME[0]}
backup_files login.defs ${FUNCNAME[0]}
backup_files sudoers ${FUNCNAME[0]}
backup_files sudouser ${FUNCNAME[0]}
log INFO "禁止wheel组以外的用户使用su命令_配置1" "n"
sed_config "auth.*sufficient.*pam_rootok.so" "auth\t\tsufficient\tpam_rootok.so" "/etc/pam.d/su" "auth.*sufficient.*pam_rootok.so" || { log2 ERROR; rollback pamdsu ${FUNCNAME[0]}; return_no=1; }
log INFO "禁止wheel组以外的用户使用su命令_配置2" "n"
sed_config "auth.*required.*pam_wheel.so" "auth\t\trequired\tpam_wheel.so\tgroup=wheel" "/etc/pam.d/su" "auth.*required.*pam_wheel.so.*group=wheel" || { log2 ERROR; rollback pamdsu ${FUNCNAME[0]}; return_no=1; }
log INFO "禁止wheel组以外的用户使用su命令_配置3" "n"
sed_config "SU_WHEEL_ONLY" "SU_WHEEL_ONLY yes" "/etc/login.defs" "SU_WHEEL_ONLY.*yes" || { log2 ERROR; rollback login.defs ${FUNCNAME[0]}; return_no=1; }
log INFO "正在把现有登陆权限的用户加入wheel组. . ."
for systemusers_i in $systemusers ; do
log ATTN "把现有登陆权限的用户加入wheel组 --> $systemusers_i" "n"
groups $systemusers_i | grep -qE "wheel" && log2 PASS || { usermod -a -G wheel $systemusers_i &>/dev/null && log2 SUCC || { log2 ERROR; rollback systemusers_wheel; return_no=1; } }
done
log INFO "配置sudoers提权调用. . ."
grep -qE "^%wheel" /etc/sudoers && sed -i "/^%wheel/ s/^\(.*\)$/#\1/g" /etc/sudoers
grep -qE "^#includedir.*/etc/sudoers.d" /etc/sudoers || echo -e "\n## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment)\n#includedir /etc/sudoers.d" | tee -a /etc/sudoers &>/dev/null
[[ -d /etc/sudoers.d/ ]] || mkdir -p /etc/sudoers.d/
[[ -f /etc/sudoers.d/sudouser ]] || touch /etc/sudoers.d/sudouser
log ATTN "配置sudoers提权调用 --> 配置允许wheel组使用提权" "n"
sed_config "%wheel" "%wheel ALL=(ALL) ALL,!/bin/su,!/bin/sh,!/bin/tcsh,!/usr/sbin/visudo,!/usr/bin/passwd,!/usr/bin/halt,!/sbin/halt,!/sbin/shutdown,!/usr/sbin/init,!/usr/sbin/poweroff,!/sbin/poweroff" "/etc/sudoers.d/sudouser" "%wheel.*ALL=\(ALL\).*ALL,\!/bin/su,\!/bin/sh,\!/bin/tcsh,\!/usr/sbin/visudo,\!/usr/bin/passwd,\!/usr/bin/halt,\!/sbin/halt,\!/sbin/shutdown,\!/usr/sbin/init,\!/usr/sbin/poweroff,\!/sbin/poweroff" || { log2 ERROR; rollback sudouser ${FUNCNAME[0]}; return_no=1; }
chmod 550 /etc/sudoers.d
chmod 640 /etc/sudoers.d/sudouser
}
debuglog() {
backup_files rsyslog.conf ${FUNCNAME[0]}
log INFO "记录守护进程产生的DEBUG日志" "n"
sed_config "daemon.debug" "daemon.debug /var/log/daemon.debug.log" "/etc/rsyslog.conf" "daemon.debug.*/" || { log2 ERROR; rollback rsyslog.conf ${FUNCNAME[0]}; return_no=1; }
}
histsize() {
backup_files profile ${FUNCNAME[0]}
log INFO "限制历史命令设置_配置1" "n"
sed_config "HISTFILESIZE" "HISTFILESIZE=5" "/etc/profile" "HISTFILESIZE.*=.*5" || { log2 ERROR; rollback profile ${FUNCNAME[0]}; return_no=1; }
log INFO "限制历史命令设置_配置2" "n"
sed_config "HISTSIZE" "HISTSIZE=5" "/etc/profile" "HISTSIZE.*=.*5" || { log2 ERROR; rollback profile ${FUNCNAME[0]}; return_no=1; }
}
coredump() {
backup_files limits.conf ${FUNCNAME[0]}
backup_files profile ${FUNCNAME[0]}
log INFO "检查系统core dump状态_配置1" "n"
sed_config "\*.*soft.*core" "*\tsoft\tcore\t0" "/etc/security/limits.conf" "^\*.*soft.*core.*0" || { log2 ERROR; rollback limits.conf ${FUNCNAME[0]}; return_no=1; }
log INFO "检查系统core dump状态_配置2" "n"
sed_config "\*.*hard.*core" "*\thard\tcore\t0" "/etc/security/limits.conf" "^\*.*hard.*core.*0" || { log2 ERROR; rollback limits.conf ${FUNCNAME[0]}; return_no=1; }
sed -i "/^# End of file/d" /etc/security/limits.conf
echo -e "# End of file" >> /etc/security/limits.conf
log INFO "检查系统core dump状态_配置3" "n"
grep -qE "^ulimit.*-S" /etc/profile && { sed -i "/^ulimit.*-S/ s/^\(.*\)$/#\1/g" /etc/profile &>/dev/null && log2 SUCC || { log2 ERROR; rollback profile; return_no=1; } } || log2 PASS
}
ctrl-alt-del() {
backup_files ctrl-alt-del.target ${FUNCNAME[0]}
log INFO "禁止组合键关机" "n"
[[ -f "/usr/lib/systemd/system/ctrl-alt-del.target" ]] && { rm -rf /usr/lib/systemd/system/ctrl-alt-del.target && log2 SUCC || { log2 ERROR; rollback ctrl-alt-del.target; return_no=1; } } || log2 PASS
}
netconf() {
backup_files sysctl.conf ${FUNCNAME[0]}
log INFO "禁止ICMP重定向" "n"
sed_config "net.ipv4.conf.all.accept_redirects" "net.ipv4.conf.all.accept_redirects=0" "/etc/sysctl.conf" "net.ipv4.conf.all.accept_redirects.*=.*0" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.conf.all.accept_redirects/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
log INFO "配置忽略广播的ICMP请求" "n"
sed_config "net.ipv4.icmp_echo_ignore_broadcasts" "net.ipv4.icmp_echo_ignore_broadcasts=1" "/etc/sysctl.conf" "net.ipv4.icmp_echo_ignore_broadcasts.*=.*1" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.icmp_echo_ignore_broadcasts/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
log INFO "禁止IP源路由_配置1" "n"
sed_config "net.ipv4.conf.all.accept_source_route" "net.ipv4.conf.all.accept_source_route=0" "/etc/sysctl.conf" "net.ipv4.conf.all.accept_source_route.*=.*0" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.conf.all.accept_source_route/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
log INFO "禁止IP源路由_配置2" "n"
sed_config "net.ipv4.conf.default.accept_source_route" "net.ipv4.conf.default.accept_source_route=0" "/etc/sysctl.conf" "net.ipv4.conf.default.accept_source_route.*=.*0" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.conf.default.accept_source_route/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
log INFO "配置检查可疑数据包被记录_配置1" "n"
sed_config "net.ipv4.conf.all.log_martians" "net.ipv4.conf.all.log_martians=1" "/etc/sysctl.conf" "net.ipv4.conf.all.log_martians.*=.*1" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.conf.all.log_martians/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
log INFO "配置检查可疑数据包被记录_配置2" "n"
sed_config "net.ipv4.conf.default.log_martians" "net.ipv4.conf.default.log_martians=1" "/etc/sysctl.conf" "net.ipv4.conf.default.log_martians.*=.*1" || { log2 ERROR; rollback sysctl.conf ${FUNCNAME[0]}; return_no=1; }
[[ -f /etc/sysctl.d/99-sysctl.conf && ! -L /etc/sysctl.d/99-sysctl.conf ]] && sed -i "/^\s*net.ipv4.conf.default.log_martians/ s/^\(.*\)$/#\1/g" /etc/sysctl.d/99-sysctl.conf &>/dev/null
}
logrotate
pwdcomp
#pwdreplim #口令重复次数限制。建议有自动改密措施的堡垒机或运维机使用
#pwdlife #配置口令生存期。建议有自动改密措施的堡垒机或运维机使用
#faillock #配置口令锁定策略。建议有自动改密措施的堡垒机或运维机使用
fileumask
logtmout
onlywheel
debuglog
histsize
coredump
ctrl-alt-del
netconf
log INFO "正在重新加载profile用户参数. . ."
source /etc/profile 1>/dev/null 2>>${LOG_FILE}
log INFO "正在重新加载bashrc用户参数. . ."
source /etc/bashrc 1>/dev/null 2>>${LOG_FILE}
log INFO "正在加载用户内核参数. . ."
sysctl -p 1>/dev/null 2>>${LOG_FILE}
log ATTN "正在重启rsyslog服务. . ."
systemctl restart rsyslog 1>/dev/null 2>>${LOG_FILE} && log SUCC "rsyslog服务启动成功" || { log ERROR "rsyslog服务启动失败"; rollback rsyslog backup_all}; return 1; }
[[ ! -n $return_no ]] && local return_no=0
return "$return_no"
}
# ------------------------------- 依赖检查 -------------------------------
install_software() {
log INFO "正在重建yum源缓存并安装系统组件. . ."
yum makecache -C 1>/dev/null 2>>${LOG_FILE} || yum clean all 1>/dev/null 2>>${LOG_FILE} && yum makecache 1>/dev/null 2>>${LOG_FILE} || { log ERROR "重建yum源缓存失败,基于yum安装的脚本不执行"; return 1; }
installer() {
local dep=$1
log INFO "安装系统组件${dep^^}" "n"
if ! yum list installed "$dep" &>/dev/null; then
yum install -y "$dep" 1>/dev/null 2>>${LOG_FILE} && log2 SUCC || { log2 ERROR; return_no=1; }
else
log2 PASS
fi
}
auditdservice() {
backup_files auditd.conf ${FUNCNAME[0]}
log INFO "检查audit服务是否已启动" "n"
systemctl status auditd &>/dev/null
if [ $? -eq 0 ] ; then
log2 PASS
else
systemctl is-enabled auditd &>/dev/null || systemctl enable auditd &>/dev/null
systemctl start auditd &>/dev/null && log2 SUCC || { log2 ERROR; return_no=1; }
fi
log INFO "配置audit日志为自动删除" "n"
sed_config "max_log_file_action" "max_log_file_action = keep_logs" "/etc/audit/auditd.conf" "max_log_file_action.*=.*keep_logs" || { log2 ERROR; rollback auditd.conf ${FUNCNAME[0]}; return_no=1; }
}
installer aide
installer audit
auditdservice
[[ ! -n $return_no ]] && local return_no=0
return "$return_no"
}
userscheck() {
log INFO "正在检查系统用户状态. . ."
log ATTN "系统中有登录权限的用户有:`awk -F: '($7=="/bin/bash"){print $1}' /etc/passwd | tr '\n' ' ' | sed -e 's/,$/\n/'`. . ."
log ATTN "系统中UID=0的用户有:`awk -F: '($3=="0"){print $1}' /etc/passwd | tr '\n' ' ' | sed -e 's/,$/\n/'`. . ."
N=`awk -F: '($2==""){print $1}' /etc/shadow | wc -l` &>/dev/null
if [ $N -eq 0 ] ; then
log ATTN "系统中无空密码用户. . ."
else
log ATTN "系统中空密码用户有:`awk -F: 'length($2)==0 {print $1}' /etc/shadow | tr '\n' ' ' | sed -e 's/,$/\n/'`请及时配置密码或删除用户. . ."
fi
}
# ------------------------------- 结束安装 -------------------------------
end_install() {
chown `logname`.`logname` $SHELL_HOME/ -R &>/dev/null
find $SHELL_HOME -type f -exec chmod 644 {} \; &>/dev/null
find $SHELL_HOME -type d -exec chmod 755 {} \; &>/dev/null
log ATTN "脚本目录: $SHELL_HOME"
log ATTN "备份目录: $BACKUP_DIR"
log ATTN "日志文件: $LOG_FILE"
export LANG=$OLD_LANG
}
# ------------------------------- 主流程 -------------------------------
main() {
acquire_lock
trap release_lock EXIT
check_root
check_os
countdown
get_systemusers
backup_all
local all_success=true
sshd_config || all_success=false
baseline_os || all_success=false
install_software || all_success=false
userscheck || all_success=false
if $all_success; then
log SUCC "所有组件配置成功!"
end_install
else
log ERROR "部分组件配置失败,已尝试回滚"
end_install
exit 1
fi
}
main
更多推荐


所有评论(0)