# Jenkins生产环境安全加固 - 执行检查清单 **作者:** 张翔 **日期:** 2026-04-07 **版本:** 1.0 **执行环境:** 生产服务器 **预计时间:** 3小时 --- ## 📋 执行前准备 ### 环境信息确认 ```bash # 记录服务器信息 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连接稳定 ### 备份当前配置 ```bash # 创建备份目录 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 检查是否已被攻击 ```bash 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 临时阻止外部访问 ```bash 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 测试外部访问 ```bash 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监听地址 ```bash 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服务 ```bash 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 /java ``` - [ ] Jenkins服务已重启 - [ ] Jenkins服务状态正常 - [ ] 监听地址为127.0.0.1:8080 ### 2.3 配置防火墙规则 ```bash 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 验证网络隔离 ```bash 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密码 ```bash 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证书信息 ```bash 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反向代理 ```bash 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配置 ```bash 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安全设置 ```bash 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 "" "$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 ```bash 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白名单 ```bash 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 配置日志轮转 ```bash 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 创建监控脚本 ```bash 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 配置定时任务 ```bash 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 运行安全验证脚本 ```bash echo "=== 运行安全验证脚本 ===" # 如果已有验证脚本 if [ -f "/usr/local/bin/verify-jenkins-security.sh" ]; then sudo /usr/local/bin/verify-jenkins-security.sh else echo "⚠️ 验证脚本不存在,执行手动验证" fi ``` - [ ] 安全验证脚本已运行 - [ ] 所有检查项通过 ### 6.2 手动验证清单 #### 网络层验证 ```bash 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 - [ ] 外部访问被阻止 - [ ] 防火墙规则正确 #### 应用层验证 ```bash 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 #### 认证层验证 ```bash 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白名单生效 #### 审计层验证 ```bash 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验证 ```bash 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触发构建成功 - [ ] 构建产物正常部署 --- ## 📝 执行总结 ### 完成情况 ```bash 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流水线正常 - [ ] 文档已更新 - [ ] 团队已通知 --- ## 🚨 应急回滚 如果出现问题,执行以下回滚操作: ```bash 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