042f66499a
- Add missing lucide-react icons (Users, Target, MessageCircle, Layers, CreditCard) - Fix admin/page.test.tsx ESLint errors (add displayName) - Fix api/contact/route.test.ts ESLint errors (remove any types, use import) - Add RESEND_API_KEY environment variable for API tests - All 122 test suites now passing - Test pass rate: 99.8% (1499/1502 passed, 3 skipped)
29 KiB
29 KiB
Jenkins生产环境安全加固 - 执行检查清单
作者: 张翔
日期: 2026-04-07
版本: 1.0
执行环境: 生产服务器
预计时间: 3小时
📋 执行前准备
环境信息确认
# 记录服务器信息
SERVER_IP=$(curl -s ifconfig.me)
SERVER_HOSTNAME=$(hostname)
CURRENT_TIME=$(date '+%Y-%m-%d %H:%M:%S')
echo "========================================"
echo " Jenkins安全加固执行清单"
echo "========================================"
echo "服务器IP: $SERVER_IP"
echo "主机名: $SERVER_HOSTNAME"
echo "执行时间: $CURRENT_TIME"
echo "执行人: $(whoami)"
echo "========================================"
- 确认服务器IP地址
- 确认当前时间
- 确认执行人权限(需要root或sudo权限)
- 确认SSH连接稳定
备份当前配置
# 创建备份目录
BACKUP_DIR="/tmp/jenkins-security-backup-$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 备份Jenkins配置
if [ -d "/var/lib/jenkins" ]; then
cp -r /var/lib/jenkins "$BACKUP_DIR/jenkins-home"
echo "✓ Jenkins主目录已备份"
fi
# 备份Jenkins配置文件
if [ -f "/etc/default/jenkins" ]; then
cp /etc/default/jenkins "$BACKUP_DIR/jenkins-default.bak"
echo "✓ Jenkins配置文件已备份"
elif [ -f "/etc/sysconfig/jenkins" ]; then
cp /etc/sysconfig/jenkins "$BACKUP_DIR/jenkins-sysconfig.bak"
echo "✓ Jenkins配置文件已备份"
fi
# 备份Nginx配置
if [ -d "/etc/nginx/conf.d" ]; then
cp -r /etc/nginx/conf.d "$BACKUP_DIR/nginx-conf"
echo "✓ Nginx配置已备份"
fi
# 备份防火墙规则
if command -v ufw &> /dev/null; then
ufw status numbered > "$BACKUP_DIR/ufw-rules.bak"
echo "✓ UFW防火墙规则已备份"
elif command -v firewall-cmd &> /dev/null; then
firewall-cmd --list-all > "$BACKUP_DIR/firewalld-rules.bak"
echo "✓ Firewalld防火墙规则已备份"
fi
echo "备份目录: $BACKUP_DIR"
echo "备份完成时间: $(date '+%Y-%m-%d %H:%M:%S')"
- Jenkins主目录已备份
- Jenkins配置文件已备份
- Nginx配置已备份
- 防火墙规则已备份
- 记录备份目录路径
🚨 阶段1:快速响应(15分钟)
1.1 检查是否已被攻击
echo "=== 检查Jenkins安全状态 ==="
# 检查最近的失败登录
echo "1. 检查最近的失败登录:"
sudo journalctl -u jenkins --since "1 hour ago" | grep -i "failed\|error" | tail -20
# 检查可疑进程
echo -e "\n2. 检查可疑进程:"
ps aux | grep -E "jenkins|java" | grep -v grep
# 检查异常文件修改
echo -e "\n3. 检查最近24小时内修改的文件:"
sudo find /var/lib/jenkins -type f -mtime -1 -ls 2>/dev/null | head -20
# 检查网络连接
echo -e "\n4. 检查Jenkins网络连接:"
sudo netstat -tunap | grep 8080
# 检查磁盘空间
echo -e "\n5. 检查磁盘空间:"
df -h | grep -E "Filesystem|/$|/var"
- 未发现异常登录
- 未发现可疑进程
- 未发现异常文件修改
- 网络连接正常
- 磁盘空间充足
1.2 临时阻止外部访问
echo "=== 临时阻止外部访问8080端口 ==="
# 方法1:使用UFW
if command -v ufw &> /dev/null; then
sudo ufw deny 8080/tcp comment 'Jenkins Direct Access - Emergency Block'
sudo ufw --force reload
echo "✓ UFW已阻止8080端口"
# 方法2:使用Firewalld
elif command -v firewall-cmd &> /dev/null; then
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload
echo "✓ Firewalld已阻止8080端口"
# 方法3:使用iptables
else
sudo iptables -I INPUT -p tcp --dport 8080 -j DROP
echo "✓ iptables已阻止8080端口"
fi
# 验证
echo -e "\n验证防火墙规则:"
if command -v ufw &> /dev/null; then
sudo ufw status | grep 8080
elif command -v firewall-cmd &> /dev/null; then
sudo firewall-cmd --list-ports | grep 8080 || echo "8080端口已被阻止"
fi
- 防火墙已阻止8080端口
- 验证防火墙规则生效
1.3 测试外部访问
echo "=== 测试外部访问是否被阻止 ==="
# 从本地测试
echo "1. 本地测试:"
curl -I -m 5 http://localhost:8080 2>&1 || echo "✓ 本地访问失败(预期)"
# 从外部测试(如果有其他服务器)
# curl -I -m 5 http://YOUR_SERVER_IP:8080 2>&1 || echo "✓ 外部访问被阻止(预期)"
echo -e "\n✓ 快速响应阶段完成"
- 外部访问已被阻止
🔧 阶段2:网络层加固(30分钟)
2.1 修改Jenkins监听地址
echo "=== 修改Jenkins监听地址 ==="
# 检测配置文件位置
if [ -f "/etc/default/jenkins" ]; then
JENKINS_CONFIG="/etc/default/jenkins"
CONFIG_TYPE="debian"
elif [ -f "/etc/sysconfig/jenkins" ]; then
JENKINS_CONFIG="/etc/sysconfig/jenkins"
CONFIG_TYPE="rhel"
else
echo "❌ 未找到Jenkins配置文件"
exit 1
fi
echo "配置文件: $JENKINS_CONFIG"
# 备份配置文件
sudo cp "$JENKINS_CONFIG" "$BACKUP_DIR/jenkins-config-before.bak"
# 查看当前配置
echo -e "\n当前Jenkins配置:"
grep -E "JENKINS_ARGS|JENKINS_LISTEN_ADDRESS|httpPort" "$JENKINS_CONFIG" || echo "未找到相关配置"
# 修改配置
if [ "$CONFIG_TYPE" = "debian" ]; then
# Debian/Ubuntu方式
if grep -q "JENKINS_ARGS" "$JENKINS_CONFIG"; then
# 如果已有JENKINS_ARGS,添加监听地址
if grep -q "httpListenAddress" "$JENKINS_CONFIG"; then
sudo sed -i 's/httpListenAddress=[^ "]*/httpListenAddress=127.0.0.1/' "$JENKINS_CONFIG"
else
sudo sed -i '/JENKINS_ARGS=/ s/"$/ --httpListenAddress=127.0.0.1"/' "$JENKINS_CONFIG"
fi
else
# 如果没有JENKINS_ARGS,添加新行
echo 'JENKINS_ARGS="--httpListenAddress=127.0.0.1"' | sudo tee -a "$JENKINS_CONFIG"
fi
else
# RHEL/CentOS方式
if grep -q "JENKINS_LISTEN_ADDRESS" "$JENKINS_CONFIG"; then
sudo sed -i 's/^JENKINS_LISTEN_ADDRESS=.*/JENKINS_LISTEN_ADDRESS="127.0.0.1"/' "$JENKINS_CONFIG"
else
echo 'JENKINS_LISTEN_ADDRESS="127.0.0.1"' | sudo tee -a "$JENKINS_CONFIG"
fi
fi
# 验证修改
echo -e "\n修改后的配置:"
grep -E "JENKINS_ARGS|JENKINS_LISTEN_ADDRESS|httpListenAddress" "$JENKINS_CONFIG"
echo -e "\n✓ Jenkins配置已修改"
- Jenkins配置文件已备份
- Jenkins监听地址已修改为127.0.0.1
- 配置修改已验证
2.2 重启Jenkins服务
echo "=== 重启Jenkins服务 ==="
# 检查Jenkins状态
echo "当前Jenkins状态:"
sudo systemctl status jenkins --no-pager
# 重启Jenkins
echo -e "\n重启Jenkins..."
sudo systemctl restart jenkins
# 等待服务启动
echo "等待Jenkins启动..."
sleep 10
# 检查服务状态
echo -e "\n检查Jenkins状态:"
sudo systemctl status jenkins --no-pager
# 检查监听地址
echo -e "\n检查监听地址:"
sudo netstat -tlnp | grep 8080
# 应该显示: tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN <pid>/java
- Jenkins服务已重启
- Jenkins服务状态正常
- 监听地址为127.0.0.1:8080
2.3 配置防火墙规则
echo "=== 配置防火墙规则 ==="
# UFW配置
if command -v ufw &> /dev/null; then
echo "使用UFW配置防火墙..."
# 启用UFW
sudo ufw --force enable
# 设置默认策略
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 允许必要端口
sudo ufw allow 22/tcp comment 'SSH Access'
sudo ufw allow 80/tcp comment 'HTTP Access'
sudo ufw allow 443/tcp comment 'HTTPS Access'
# 确保阻止8080端口
sudo ufw deny 8080/tcp comment 'Jenkins Direct Access Blocked'
# 重载防火墙
sudo ufw --force reload
# 显示状态
sudo ufw status numbered
# Firewalld配置
elif command -v firewall-cmd &> /dev/null; then
echo "使用Firewalld配置防火墙..."
# 启动并启用
sudo systemctl start firewalld
sudo systemctl enable firewalld
# 允许必要服务
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# 确保移除8080端口
sudo firewall-cmd --permanent --remove-port=8080/tcp
# 重载防火墙
sudo firewall-cmd --reload
# 显示状态
sudo firewall-cmd --list-all
fi
echo -e "\n✓ 防火墙规则已配置"
- 防火墙已启用
- SSH端口已开放
- HTTP/HTTPS端口已开放
- 8080端口已阻止
- 防火墙规则已验证
2.4 验证网络隔离
echo "=== 验证网络隔离 ==="
# 检查Jenkins监听地址
echo "1. 检查Jenkins监听地址:"
sudo netstat -tlnp | grep 8080
# 预期: 127.0.0.1:8080
# 尝试从外部IP访问(应该失败)
echo -e "\n2. 尝试从外部IP访问:"
curl -I -m 5 --interface $(ip route | grep default | awk '{print $5}' | head -1) http://localhost:8080 2>&1 || echo "✓ 外部访问被阻止(预期)"
# 检查防火墙规则
echo -e "\n3. 检查防火墙规则:"
if command -v ufw &> /dev/null; then
sudo ufw status | grep 8080
elif command -v firewall-cmd &> /dev/null; then
sudo firewall-cmd --list-ports | grep 8080 || echo "8080端口未开放(预期)"
fi
echo -e "\n✓ 网络隔离验证完成"
- Jenkins仅监听127.0.0.1
- 外部访问被阻止
- 防火墙规则正确
🔐 阶段3:应用层防护(45分钟)
3.1 生成HTTP Basic Auth密码
echo "=== 生成HTTP Basic Auth密码 ==="
# 设置管理员用户名
ADMIN_USER="admin"
# 提示输入密码
echo "请设置Jenkins访问密码:"
read -s JENKINS_PASSWORD
echo ""
echo "请再次确认密码:"
read -s JENKINS_PASSWORD_CONFIRM
echo ""
# 验证密码
if [ "$JENKINS_PASSWORD" != "$JENKINS_PASSWORD_CONFIRM" ]; then
echo "❌ 两次密码输入不一致"
exit 1
fi
if [ -z "$JENKINS_PASSWORD" ]; then
echo "❌ 密码不能为空"
exit 1
fi
# 创建密码文件
HTPASSWD_FILE="/etc/nginx/conf.d/.jenkins-htpasswd"
# 使用htpasswd或openssl生成密码
if command -v htpasswd &> /dev/null; then
sudo htpasswd -bc "$HTPASSWD_FILE" "$ADMIN_USER" "$JENKINS_PASSWORD"
else
# 使用openssl生成
SALT=$(openssl rand -base64 3)
HASH=$(openssl passwd -apr1 -salt "$SALT" "$JENKINS_PASSWORD")
echo "$ADMIN_USER:$HASH" | sudo tee "$HTPASSWD_FILE"
fi
# 设置权限
sudo chmod 600 "$HTPASSWD_FILE"
sudo chown www-data:www-data "$HTPASSWD_FILE" 2>/dev/null || sudo chown nginx:nginx "$HTPASSWD_FILE"
echo "✓ HTTP Basic Auth密码文件已生成: $HTPASSWD_FILE"
# 记录密码(仅用于本次执行)
echo "管理员用户: $ADMIN_USER" | sudo tee "$BACKUP_DIR/admin-credentials.txt"
echo "密码文件: $HTPASSWD_FILE" | sudo tee -a "$BACKUP_DIR/admin-credentials.txt"
- 管理员密码已设置
- HTTP Basic Auth密码文件已生成
- 密码文件权限已设置
3.2 获取域名和SSL证书信息
echo "=== 获取域名和SSL证书信息 ==="
# 提示输入域名
echo "请输入Jenkins访问域名(例如: jenkins.example.com):"
read DOMAIN
if [ -z "$DOMAIN" ]; then
echo "❌ 域名不能为空"
exit 1
fi
# 检查SSL证书
echo -e "\n检查SSL证书..."
if [ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
SSL_CERT="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
SSL_KEY="/etc/letsencrypt/live/$DOMAIN/privkey.pem"
echo "✓ 找到Let's Encrypt证书"
elif [ -f "/etc/nginx/ssl/$DOMAIN.crt" ]; then
SSL_CERT="/etc/nginx/ssl/$DOMAIN.crt"
SSL_KEY="/etc/nginx/ssl/$DOMAIN.key"
echo "✓ 找到自签名证书"
else
echo "⚠️ 未找到SSL证书,将使用HTTP配置"
SSL_CERT=""
SSL_KEY=""
fi
# 显示证书信息
if [ -n "$SSL_CERT" ]; then
echo -e "\n证书信息:"
sudo openssl x509 -in "$SSL_CERT" -noout -subject -dates
fi
echo "域名: $DOMAIN" | sudo tee -a "$BACKUP_DIR/deployment-info.txt"
- 域名已确认
- SSL证书状态已检查
3.3 配置Nginx反向代理
echo "=== 配置Nginx反向代理 ==="
NGINX_CONF_FILE="/etc/nginx/conf.d/jenkins-security.conf"
# 创建Nginx配置
sudo tee "$NGINX_CONF_FILE" > /dev/null << 'NGINX_CONF_EOF'
# Jenkins安全反向代理配置
# 作者: 张翔
# 日期: 2026-04-07
# 说明: 多层安全防护 - 认证、频率限制、审计日志
# 上游Jenkins服务
upstream jenkins_backend {
server 127.0.0.1:8080;
keepalive 32;
}
# 频率限制区域
limit_req_zone $binary_remote_addr zone=jenkins_limit:10m rate=10r/m;
limit_conn_zone $binary_remote_addr zone=jenkins_conn:10m;
# 日志格式(包含安全审计信息)
log_format jenkins_security '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'request_time=$request_time '
'upstream_response_time=$upstream_response_time '
'ssl_protocol=$ssl_protocol '
'ssl_cipher=$ssl_cipher';
# HTTP重定向到HTTPS(如果有SSL证书)
server {
listen 80;
server_name DOMAIN_PLACEHOLDER;
# Let's Encrypt验证路径
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS主配置(如果有SSL证书)
server {
listen 443 ssl http2;
server_name DOMAIN_PLACEHOLDER;
# SSL配置
ssl_certificate SSL_CERT_PLACEHOLDER;
ssl_certificate_key SSL_KEY_PLACEHOLDER;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 安全响应头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 访问日志
access_log /var/log/nginx/jenkins-access.log jenkins_security;
error_log /var/log/nginx/jenkins-error.log warn;
# 频率限制
limit_req zone=jenkins_limit burst=20 nodelay;
limit_conn jenkins_conn 10;
# 客户端请求限制
client_max_body_size 100m;
client_body_timeout 60s;
client_header_timeout 60s;
# Webhook端点(IP白名单)
location ~ ^/generic-webhook-trigger(/.*)?$ {
# IP白名单(需要配置)
# allow GITEA_SERVER_IP;
# deny all;
# 代理到Jenkins
proxy_pass http://jenkins_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# Jenkins主界面(需要认证)
location /jenkins/ {
# HTTP Basic Auth
auth_basic "Jenkins Production Access";
auth_basic_user_file HTPASSWD_FILE_PLACEHOLDER;
# 代理到Jenkins
proxy_pass http://jenkins_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# WebSocket支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 默认拒绝其他路径
location / {
return 404;
}
}
NGINX_CONF_EOF
# 替换占位符
sudo sed -i "s|DOMAIN_PLACEHOLDER|$DOMAIN|g" "$NGINX_CONF_FILE"
sudo sed -i "s|HTPASSWD_FILE_PLACEHOLDER|$HTPASSWD_FILE|g" "$NGINX_CONF_FILE"
if [ -n "$SSL_CERT" ]; then
sudo sed -i "s|SSL_CERT_PLACEHOLDER|$SSL_CERT|g" "$NGINX_CONF_FILE"
sudo sed -i "s|SSL_KEY_PLACEHOLDER|$SSL_KEY|g" "$NGINX_CONF_FILE"
else
# 如果没有SSL证书,注释掉HTTPS配置,使用HTTP
echo "⚠️ 未配置SSL证书,将使用HTTP配置"
# 这里需要调整配置,暂时跳过
fi
echo "✓ Nginx配置文件已创建: $NGINX_CONF_FILE"
- Nginx配置文件已创建
- 域名已配置
- HTTP Basic Auth已配置
- SSL证书已配置(如有)
3.4 测试Nginx配置
echo "=== 测试Nginx配置 ==="
# 测试配置语法
sudo nginx -t
if [ $? -eq 0 ]; then
echo "✓ Nginx配置语法正确"
else
echo "❌ Nginx配置存在错误,请检查"
exit 1
fi
# 创建日志目录
sudo mkdir -p /var/log/nginx
sudo touch /var/log/nginx/jenkins-access.log
sudo touch /var/log/nginx/jenkins-error.log
# 重启Nginx
echo -e "\n重启Nginx..."
sudo systemctl restart nginx
# 检查Nginx状态
sudo systemctl status nginx --no-pager
echo -e "\n✓ Nginx配置完成"
- Nginx配置测试通过
- Nginx服务已重启
- Nginx状态正常
🔑 阶段4:认证授权层(30分钟)
4.1 配置Jenkins安全设置
echo "=== 配置Jenkins安全设置 ==="
JENKINS_CONFIG_XML="/var/lib/jenkins/config.xml"
if [ -f "$JENKINS_CONFIG_XML" ]; then
# 备份配置文件
sudo cp "$JENKINS_CONFIG_XML" "$BACKUP_DIR/config.xml.bak"
# 检查当前安全配置
echo "当前Jenkins安全配置:"
grep -A 5 "<useSecurity>" "$JENKINS_CONFIG_XML" || echo "未找到安全配置"
# 注意: Jenkins安全配置通常通过Web UI配置
# 这里仅做检查,实际配置建议通过Web UI完成
echo -e "\n⚠️ 请通过Web UI配置Jenkins安全设置:"
echo "1. 访问: https://$DOMAIN/jenkins/configureSecurity"
echo "2. 启用安全: 勾选'启用安全'"
echo "3. 授权策略: 选择'安全矩阵'"
echo "4. 取消匿名用户的所有权限"
echo "5. 保存配置"
echo -e "\n✓ Jenkins配置文件已备份"
else
echo "⚠️ 未找到Jenkins配置文件"
fi
- Jenkins配置已备份
- 已了解Web UI配置步骤
4.2 配置Webhook Token
echo "=== 配置Webhook Token ==="
# 生成新的Webhook密钥
WEBHOOK_SECRET=$(openssl rand -hex 32)
echo "新的Webhook密钥: $WEBHOOK_SECRET"
# 保存密钥
echo "WEBHOOK_SECRET=$WEBHOOK_SECRET" | sudo tee "$BACKUP_DIR/webhook-secret.txt"
# 检查Jenkinsfile中的硬编码token
echo -e "\n检查Jenkinsfile中的硬编码token..."
if [ -f "Jenkinsfile" ]; then
if grep -q "token.*=.*['\"].*['\"]" Jenkinsfile; then
echo "⚠️ 发现硬编码token,需要替换为环境变量:"
grep -n "token.*=.*['\"].*['\"]" Jenkinsfile
echo -e "\n建议修改为:"
echo "token = env.WEBHOOK_TOKEN"
echo ""
echo "并在Jenkins中配置环境变量 WEBHOOK_TOKEN"
else
echo "✓ 未发现硬编码token"
fi
fi
# 配置Jenkins环境变量
echo -e "\n配置Jenkins环境变量..."
echo "请在Jenkins Web UI中配置:"
echo "1. 访问: https://$DOMAIN/jenkins/configure"
echo "2. 找到'全局属性' -> '环境变量'"
echo "3. 添加键值对:"
echo " 键: WEBHOOK_TOKEN"
echo " 值: $WEBHOOK_SECRET"
echo "4. 保存配置"
echo -e "\n✓ Webhook密钥已生成"
- Webhook密钥已生成
- Jenkinsfile已检查
- 已了解环境变量配置步骤
4.3 配置IP白名单
echo "=== 配置IP白名单 ==="
# 获取Gitea服务器IP
echo "请输入Gitea服务器IP地址(用于Webhook白名单):"
read GITEA_IP
if [ -n "$GITEA_IP" ]; then
# 更新Nginx配置
NGINX_CONF_FILE="/etc/nginx/conf.d/jenkins-security.conf"
# 添加IP白名单规则
sudo sed -i "s|# allow GITEA_SERVER_IP;|allow $GITEA_IP;|g" "$NGINX_CONF_FILE"
sudo sed -i "s|# deny all;|deny all;|g" "$NGINX_CONF_FILE"
echo "✓ IP白名单已配置: $GITEA_IP"
# 测试Nginx配置
sudo nginx -t && sudo systemctl reload nginx
else
echo "⚠️ 未配置IP白名单,Webhook端点将允许所有IP访问"
fi
# 记录配置
echo "Gitea IP: $GITEA_IP" | sudo tee -a "$BACKUP_DIR/deployment-info.txt"
- Gitea服务器IP已配置
- Nginx IP白名单已更新
- Nginx配置已重载
📊 阶段5:审计监控层(20分钟)
5.1 配置日志轮转
echo "=== 配置日志轮转 ==="
LOGROTATE_CONF="/etc/logrotate.d/jenkins-security"
sudo tee "$LOGROTATE_CONF" > /dev/null << 'EOF'
/var/log/nginx/jenkins-*.log {
daily
rotate 90
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
EOF
echo "✓ 日志轮转配置已创建: $LOGROTATE_CONF"
# 测试配置
sudo logrotate -d "$LOGROTATE_CONF"
- 日志轮转配置已创建
- 日志轮转配置已测试
5.2 创建监控脚本
echo "=== 创建监控脚本 ==="
MONITOR_SCRIPT="/usr/local/bin/monitor-jenkins-security.sh"
sudo tee "$MONITOR_SCRIPT" > /dev/null << 'EOF'
#!/bin/bash
# Jenkins安全监控脚本
# 作者: 张翔
# 用途: 监控Jenkins安全状态
LOG_FILE="/var/log/nginx/jenkins-access.log"
ALERT_THRESHOLD=10
# 检查失败的认证尝试
echo "=== 检查失败的认证尝试 ==="
FAILED_AUTH=$(grep " 401 " "$LOG_FILE" | tail -n 100 | awk '{print $1}' | sort | uniq -c | awk -v threshold=$ALERT_THRESHOLD '$1 > threshold {print $1, $2}')
if [ -n "$FAILED_AUTH" ]; then
echo "⚠️ 检测到多次认证失败的IP:"
echo "$FAILED_AUTH"
else
echo "✓ 未发现异常认证失败"
fi
# 检查异常请求
echo -e "\n=== 检查异常请求 ==="
ABNORMAL_REQUESTS=$(grep -E "POST|DELETE|PUT" "$LOG_FILE" | tail -n 100 | grep -v " 200 \| 201 " | awk '{print $1, $7, $9}')
if [ -n "$ABNORMAL_REQUESTS" ]; then
echo "⚠️ 检测到异常请求:"
echo "$ABNORMAL_REQUESTS"
else
echo "✓ 未发现异常请求"
fi
# 检查Jenkins服务状态
echo -e "\n=== 检查Jenkins服务状态 ==="
if systemctl is-active --quiet jenkins; then
echo "✓ Jenkins服务运行正常"
else
echo "❌ Jenkins服务未运行"
fi
# 检查Nginx服务状态
echo -e "\n=== 检查Nginx服务状态 ==="
if systemctl is-active --quiet nginx; then
echo "✓ Nginx服务运行正常"
else
echo "❌ Nginx服务未运行"
fi
# 检查磁盘空间
echo -e "\n=== 检查磁盘空间 ==="
DISK_USAGE=$(df -h /var | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 80 ]; then
echo "⚠️ 磁盘使用率: ${DISK_USAGE}%"
else
echo "✓ 磁盘使用率: ${DISK_USAGE}%"
fi
EOF
sudo chmod +x "$MONITOR_SCRIPT"
echo "✓ 监控脚本已创建: $MONITOR_SCRIPT"
# 运行一次监控
sudo "$MONITOR_SCRIPT"
- 监控脚本已创建
- 监控脚本已测试
5.3 配置定时任务
echo "=== 配置定时任务 ==="
# 添加到crontab
(crontab -l 2>/dev/null; echo "# Jenkins安全监控 - 每小时执行一次"; echo "0 * * * * $MONITOR_SCRIPT >> /var/log/jenkins-security-monitor.log 2>&1") | crontab -
# 显示当前crontab
echo "当前定时任务:"
crontab -l
echo -e "\n✓ 定时任务已配置"
- 定时任务已配置
- 定时任务已验证
✅ 阶段6:验证与测试(30分钟)
6.1 运行安全验证脚本
echo "=== 运行安全验证脚本 ==="
# 如果已有验证脚本
if [ -f "/usr/local/bin/verify-jenkins-security.sh" ]; then
sudo /usr/local/bin/verify-jenkins-security.sh
else
echo "⚠️ 验证脚本不存在,执行手动验证"
fi
- 安全验证脚本已运行
- 所有检查项通过
6.2 手动验证清单
网络层验证
echo "=== 网络层验证 ==="
# 1. 检查Jenkins监听地址
echo "1. 检查Jenkins监听地址:"
sudo netstat -tlnp | grep 8080
# 预期: 127.0.0.1:8080
# 2. 尝试外部访问
echo -e "\n2. 尝试外部访问8080端口:"
curl -I -m 5 http://localhost:8080 2>&1 || echo "✓ 外部访问被阻止"
# 3. 检查防火墙
echo -e "\n3. 检查防火墙规则:"
if command -v ufw &> /dev/null; then
sudo ufw status | grep 8080
elif command -v firewall-cmd &> /dev/null; then
sudo firewall-cmd --list-ports | grep 8080 || echo "✓ 8080端口未开放"
fi
- Jenkins仅监听127.0.0.1
- 外部访问被阻止
- 防火墙规则正确
应用层验证
echo "=== 应用层验证 ==="
# 1. 测试Nginx配置
echo "1. 测试Nginx配置:"
sudo nginx -t
# 2. 测试匿名访问
echo -e "\n2. 测试匿名访问(应返回401):"
curl -I -k https://$DOMAIN/jenkins/ 2>&1 | grep "HTTP"
# 3. 测试认证访问
echo -e "\n3. 测试认证访问(应返回200):"
curl -I -k -u "$ADMIN_USER:$JENKINS_PASSWORD" https://$DOMAIN/jenkins/ 2>&1 | grep "HTTP"
# 4. 测试错误密码
echo -e "\n4. 测试错误密码(应返回401):"
curl -I -k -u "admin:wrongpassword" https://$DOMAIN/jenkins/ 2>&1 | grep "HTTP"
- Nginx配置正确
- 匿名访问返回401
- 认证访问返回200
- 错误密码返回401
认证层验证
echo "=== 认证层验证 ==="
# 1. 测试Webhook签名验证
echo "1. 测试Webhook签名验证:"
PAYLOAD='{"ref": "refs/heads/release/test"}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
# 无签名请求(应失败)
echo "无签名请求:"
curl -X POST -k "https://$DOMAIN/generic-webhook-trigger/invoke" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" 2>&1
# 有签名请求(应成功)
echo -e "\n有签名请求:"
curl -X POST -k "https://$DOMAIN/generic-webhook-trigger/invoke" \
-H "Content-Type: application/json" \
-H "X-Gitea-Signature: sha256=$SIGNATURE" \
-d "$PAYLOAD" 2>&1
# 2. 测试IP白名单
echo -e "\n2. 测试IP白名单:"
echo "请从非白名单IP测试Webhook访问,应被拒绝"
- Webhook签名验证生效
- IP白名单生效
审计层验证
echo "=== 审计层验证 ==="
# 1. 检查访问日志
echo "1. 检查访问日志:"
tail -20 /var/log/nginx/jenkins-access.log
# 2. 检查日志轮转配置
echo -e "\n2. 检查日志轮转配置:"
cat /etc/logrotate.d/jenkins-security
# 3. 检查监控脚本
echo -e "\n3. 检查监控脚本:"
ls -lh /usr/local/bin/monitor-jenkins-security.sh
- 访问日志正常记录
- 日志轮转配置正确
- 监控脚本存在
6.3 CI/CD验证
echo "=== CI/CD验证 ==="
# 1. 手动触发Jenkins构建
echo "1. 手动触发Jenkins构建:"
echo "请访问: https://$DOMAIN/jenkins/"
echo "使用用户名: $ADMIN_USER 和设置的密码登录"
echo "手动触发一个构建任务"
# 2. 测试Webhook触发
echo -e "\n2. 测试Webhook触发:"
echo "请在Gitea中推送代码到release分支,验证Webhook是否触发构建"
# 3. 检查构建日志
echo -e "\n3. 检查构建日志:"
echo "请检查Jenkins构建日志,确认构建成功"
- 手动触发构建成功
- Webhook触发构建成功
- 构建产物正常部署
📝 执行总结
完成情况
echo "========================================"
echo " Jenkins安全加固执行总结"
echo "========================================"
echo ""
echo "执行时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "服务器: $SERVER_HOSTNAME ($SERVER_IP)"
echo "域名: $DOMAIN"
echo ""
echo "备份目录: $BACKUP_DIR"
echo ""
echo "重要信息:"
echo "- 管理员用户: $ADMIN_USER"
echo "- Jenkins访问地址: https://$DOMAIN/jenkins/"
echo "- Webhook密钥: 已保存在 $BACKUP_DIR/webhook-secret.txt"
echo ""
echo "后续步骤:"
echo "1. 通过Web UI配置Jenkins安全设置"
echo "2. 在Jenkins中配置环境变量 WEBHOOK_TOKEN"
echo "3. 更新Jenkinsfile中的token配置"
echo "4. 配置SSL证书(如未配置)"
echo "5. 设置定期安全审计"
echo ""
echo "监控命令:"
echo "- 查看访问日志: tail -f /var/log/nginx/jenkins-access.log"
echo "- 运行监控脚本: sudo /usr/local/bin/monitor-jenkins-security.sh"
echo "- 检查服务状态: sudo systemctl status jenkins nginx"
echo ""
echo "========================================"
验收确认
- 所有阶段已完成
- 所有验证项通过
- CI/CD流水线正常
- 文档已更新
- 团队已通知
🚨 应急回滚
如果出现问题,执行以下回滚操作:
echo "=== 执行回滚 ==="
# 1. 恢复Jenkins配置
sudo cp "$BACKUP_DIR/jenkins-default.bak" /etc/default/jenkins
# 2. 恢复Nginx配置
sudo cp -r "$BACKUP_DIR/nginx-conf"/* /etc/nginx/conf.d/
# 3. 重启服务
sudo systemctl restart jenkins
sudo systemctl restart nginx
# 4. 开放8080端口(仅应急)
sudo ufw allow 8080/tcp
echo "✓ 回滚完成"
执行状态: ⏳ 待执行
最后更新: 2026-04-07