Files
novalon-website/docs/plans/CHECKLIST_JENKINS_SECURITY.md
T
张翔 042f66499a fix: complete test suite fixes - achieve 99.8% pass rate
- 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)
2026-04-09 17:33:21 +08:00

1120 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <pid>/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 "<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
```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