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)
This commit is contained in:
张翔
2026-04-09 17:33:21 +08:00
parent a86231fb9a
commit 042f66499a
17 changed files with 5376 additions and 13 deletions
+77
View File
@@ -0,0 +1,77 @@
# Jenkins安全配置环境变量示例
# 作者:张翔
# 日期:2026-04-07
# 说明:复制此文件为 .env.jenkins.production 并填入实际值
# ============================================
# Jenkins访问控制
# ============================================
# Jenkins管理员用户名
JENKINS_ADMIN_USER=admin
# Jenkins管理员密码(请使用强密码)
# 生成方法:openssl rand -base64 32
JENKINS_ADMIN_PASSWORD=CHANGE_ME_STRONG_PASSWORD_HERE
# ============================================
# Webhook安全配置
# ============================================
# Webhook Token(用于Generic Webhook Trigger
# 生成方法:openssl rand -hex 32
JENKINS_WEBHOOK_TOKEN=CHANGE_ME_RANDOM_TOKEN_HERE
# Webhook签名密钥(用于验证Gitea请求)
# 生成方法:openssl rand -hex 32
WEBHOOK_SECRET=CHANGE_ME_WEBHOOK_SECRET_HERE
# ============================================
# 网络安全配置
# ============================================
# 允许访问Webhook的IP地址(逗号分隔)
# 示例:192.168.1.100,10.0.0.50
ALLOWED_IPS=127.0.0.1
# Jenkins域名
DOMAIN=your-domain.com
# ============================================
# SSL/TLS配置
# ============================================
# SSL证书路径
SSL_CERT_PATH=/etc/letsencrypt/live/your-domain.com/fullchain.pem
SSL_KEY_PATH=/etc/letsencrypt/live/your-domain.com/privkey.pem
# ============================================
# 审计和监控
# ============================================
# 安全日志保留天数
SECURITY_LOG_RETENTION_DAYS=90
# 访问日志路径
JENKINS_ACCESS_LOG=/var/log/nginx/jenkins-access.log
JENKINS_ERROR_LOG=/var/log/nginx/jenkins-error.log
# ============================================
# 频率限制
# ============================================
# 每分钟最大请求数
RATE_LIMIT_REQUESTS=10
# 并发连接数限制
CONNECTION_LIMIT=10
# ============================================
# 备份配置
# ============================================
# 备份目录
BACKUP_DIR=/backup/jenkins
# 备份保留天数
BACKUP_RETENTION_DAYS=30
+371
View File
@@ -0,0 +1,371 @@
# Jenkins安全加固快速部署指南
**作者:** 张翔
**日期:** 2026-04-07
**紧急程度:** 🔴 立即执行
---
## ⚡ 5分钟快速响应
### 情况紧急?立即执行以下命令
```bash
# 1. 阻止外部访问8080端口
sudo ufw deny 8080/tcp && sudo ufw --force reload
# 2. 修改Jenkins监听地址
sudo sed -i 's|httpPort=8080|httpPort=8080 --httpListenAddress=127.0.0.1|' /etc/default/jenkins
sudo systemctl restart jenkins
# 3. 验证
sudo netstat -tlnp | grep 8080
# 应显示:127.0.0.1:8080
```
---
## 📋 完整部署流程(30分钟)
### 前置准备
```bash
# 1. 克隆或进入项目目录
cd /path/to/novalon-website
# 2. 检查当前状态
sudo netstat -tlnp | grep 8080
curl -I http://localhost:8080
```
### 步骤1:配置环境变量
```bash
# 1. 复制环境变量模板
cp scripts/security/.env.jenkins.example scripts/security/.env.jenkins.production
# 2. 编辑配置文件
vim scripts/security/.env.jenkins.production
# 3. 生成随机密钥
# Webhook Token
openssl rand -hex 32
# 将输出复制到 JENKINS_WEBHOOK_TOKEN
# Webhook Secret
openssl rand -hex 32
# 将输出复制到 WEBHOOK_SECRET
# 管理员密码
openssl rand -base64 32
# 将输出复制到 JENKINS_ADMIN_PASSWORD
```
### 步骤2:配置Jenkins Credentials
```bash
# 方法1:通过Jenkins UI
# 访问:https://your-domain.com/jenkins/credentials/store/system/domain/_/
# 添加Secret text
# ID: jenkins-webhook-token
# Secret: [步骤1生成的token]
# 方法2:通过Jenkins CLI
java -jar jenkins-cli.jar -s http://localhost:8080/ create-credentials-by-xml system::system::jenkins << EOF
<com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>
<scope>GLOBAL</scope>
<id>jenkins-webhook-token</id>
<description>Jenkins Webhook Token</description>
<username></username>
<password>${JENKINS_WEBHOOK_TOKEN}</password>
</com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>
EOF
```
### 步骤3:运行安全加固脚本
```bash
# 1. 设置权限
chmod +x scripts/security/jenkins-security-hardening.sh
# 2. 加载环境变量
export $(cat scripts/security/.env.jenkins.production | xargs)
# 3. 运行脚本
sudo -E ./scripts/security/jenkins-security-hardening.sh
# 按照提示输入:
# - 管理员密码
# - 是否立即重启服务
```
### 步骤4:配置SSL证书(如未配置)
```bash
# 使用Let's Encrypt
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
# 或使用已有证书
sudo mkdir -p /etc/letsencrypt/live/your-domain.com
sudo cp your-cert.pem /etc/letsencrypt/live/your-domain.com/fullchain.pem
sudo cp your-key.pem /etc/letsencrypt/live/your-domain.com/privkey.pem
```
### 步骤5:配置Gitea Webhook
```bash
# 1. 进入Gitea仓库设置
# Settings -> Webhooks -> Add Webhook
# 2. 配置Webhook
# 目标URL: https://your-domain.com/generic-webhook-trigger/invoke
# HTTP方法: POST
# 触发条件: Push events
# 启用签名验证: 是
# 签名密钥: [步骤1生成的WEBHOOK_SECRET]
# 3. 测试Webhook
# 点击"Test Delivery"按钮
```
### 步骤6:验证安全配置
```bash
# 1. 运行自动验证
sudo /usr/local/bin/verify-jenkins-security.sh
# 2. 手动测试
# 测试1:直接访问8080端口(应失败)
curl -I http://YOUR_SERVER_IP:8080
# 测试2:匿名访问(应返回401
curl -I https://your-domain.com/jenkins/
# 测试3:认证访问(应成功)
curl -I -u admin:YOUR_PASSWORD https://your-domain.com/jenkins/
# 测试4Webhook签名验证
PAYLOAD='{"ref": "refs/heads/release/test"}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
curl -X POST https://your-domain.com/generic-webhook-trigger/invoke \
-H "Content-Type: application/json" \
-H "X-Gitea-Signature: sha256=$SIGNATURE" \
-d "$PAYLOAD"
```
---
## 📁 文件清单
```
scripts/security/
├── jenkins-security-hardening.sh # 主加固脚本
├── .env.jenkins.example # 环境变量模板
└── README.md # 本文档
docs/security/
└── JENKINS_SECURITY_HARDENING_GUIDE.md # 详细安全指南
Jenkinsfile # 已更新(移除硬编码token)
```
---
## 🔍 验证检查清单
执行以下命令确认所有配置正确:
```bash
# ✅ Jenkins仅监听127.0.0.1
sudo netstat -tlnp | grep 8080
# 预期:127.0.0.1:8080
# ✅ 防火墙已阻止8080
sudo ufw status | grep 8080
# 预期:8080/tcp DENY
# ✅ Nginx配置正确
sudo nginx -t
# 预期:test is successful
# ✅ HTTP Basic Auth已配置
ls -la /etc/nginx/conf.d/.jenkins-htpasswd
# 预期:文件存在且权限为600
# ✅ Jenkinsfile无硬编码token
grep -r "token.*=.*['\"].*['\"]" Jenkinsfile
# 预期:无输出
# ✅ SSL证书有效
openssl s_client -connect your-domain.com:443 -servername your-domain.com 2>/dev/null | openssl x509 -noout -dates
# 预期:显示证书有效期
# ✅ 服务运行正常
sudo systemctl status jenkins nginx
# 预期:active (running)
```
---
## 🚨 常见问题
### Q1: 脚本执行失败
**问题:** `permission denied`
**解决:**
```bash
chmod +x scripts/security/jenkins-security-hardening.sh
sudo ./scripts/security/jenkins-security-hardening.sh
```
### Q2: Jenkins无法启动
**问题:** 修改监听地址后Jenkins无法启动
**解决:**
```bash
# 检查配置文件
cat /etc/default/jenkins | grep JENKINS_ARGS
# 恢复备份
sudo cp /tmp/jenkins-security-backup-*/jenkins-default.bak /etc/default/jenkins
sudo systemctl restart jenkins
```
### Q3: Nginx配置错误
**问题:** `nginx: [emerg] unknown directive`
**解决:**
```bash
# 检查Nginx版本
nginx -v
# 确保版本 >= 1.18
sudo apt update && sudo apt upgrade nginx
# 验证配置
sudo nginx -t
```
### Q4: Webhook触发失败
**问题:** Webhook返回403
**解决:**
```bash
# 检查IP白名单
grep "allow" /etc/nginx/conf.d/jenkins-security.conf
# 检查签名验证
# 确保Gitea配置的签名密钥与WEBHOOK_SECRET一致
# 查看Nginx错误日志
tail -f /var/log/nginx/jenkins-error.log
```
### Q5: 认证失败
**问题:** HTTP Basic Auth无法登录
**解决:**
```bash
# 重新生成密码文件
sudo htpasswd -c /etc/nginx/conf.d/.jenkins-htpasswd admin
# 重启Nginx
sudo systemctl restart nginx
```
---
## 📊 安全监控
### 设置定时监控
```bash
# 添加到crontab
crontab -e
```
```cron
# 每小时检查异常访问
0 * * * * /usr/local/bin/monitor-jenkins-security.sh >> /var/log/jenkins-security-monitor.log 2>&1
# 每天备份配置
0 2 * * * tar -czf /backup/jenkins-config-$(date +\%Y\%m\%d).tar.gz /var/lib/jenkins
# 每周发送安全报告
0 9 * * 1 /usr/local/bin/jenkins-security-report.sh | mail -s "Jenkins Security Report" admin@your-domain.com
```
### 查看实时日志
```bash
# 监控访问日志
tail -f /var/log/nginx/jenkins-access.log
# 监控错误日志
tail -f /var/log/nginx/jenkins-error.log
# 监控Jenkins日志
sudo journalctl -u jenkins -f
```
---
## 🔄 回滚方案
如果出现问题,可以快速回滚:
```bash
# 1. 恢复Jenkins配置
sudo cp /tmp/jenkins-security-backup-*/jenkins-default.bak /etc/default/jenkins
# 2. 恢复Nginx配置
sudo rm /etc/nginx/conf.d/jenkins-security.conf
sudo cp -r /tmp/jenkins-security-backup-*/nginx-conf/* /etc/nginx/conf.d/
# 3. 重启服务
sudo systemctl restart jenkins nginx
# 4. 恢复防火墙规则
sudo ufw allow 8080/tcp
sudo ufw --force reload
```
---
## 📞 获取帮助
**文档:**
- [完整安全指南](./JENKINS_SECURITY_HARDENING_GUIDE.md)
- [Jenkins官方安全文档](https://www.jenkins.io/doc/book/security/)
**应急联系:**
- 安全负责人:张翔
- 技术支持:devops@your-domain.com
---
## ✅ 部署后确认
完成所有步骤后,确认以下事项:
- [ ] Jenkins仅监听127.0.0.1:8080
- [ ] 防火墙已阻止外部访问8080
- [ ] Nginx反向代理正常工作
- [ ] HTTP Basic Auth认证生效
- [ ] Webhook签名验证通过
- [ ] SSL证书有效
- [ ] 所有日志正常记录
- [ ] 监控脚本运行正常
- [ ] 备份策略已配置
- [ ] 团队成员已通知
---
**最后更新:** 2026-04-07
**文档版本:** 1.0
@@ -0,0 +1,544 @@
#!/bin/bash
# Jenkins生产环境安全加固脚本
# 作者:张翔
# 日期:2026-04-07
# 版本:1.0
# 用途:系统性解决Jenkins暴露在公网8080端口的安全风险
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 配置参数
JENKINS_HOME="${JENKINS_HOME:-/var/lib/jenkins}"
NGINX_CONF_DIR="${NGINX_CONF_DIR:-/etc/nginx/conf.d}"
BACKUP_DIR="${BACKUP_DIR:-/tmp/jenkins-security-backup-$(date +%Y%m%d_%H%M%S)}"
DOMAIN="${DOMAIN:-your-domain.com}"
# 安全参数
ADMIN_USER="${JENKINS_ADMIN_USER:-admin}"
WEBHOOK_SECRET="${WEBHOOK_SECRET:-$(openssl rand -hex 32)}"
ALLOWED_IPS="${ALLOWED_IPS:-}"
echo "======================================================================"
echo " Jenkins生产环境安全加固脚本"
echo " 作者:张翔 | 日期:2026-04-07 | 版本:1.0"
echo "======================================================================"
echo ""
# 前置检查
log_step "执行前置检查..."
if [ "$EUID" -ne 0 ]; then
log_error "请使用root权限运行此脚本"
exit 1
fi
if ! command -v nginx &> /dev/null; then
log_error "Nginx未安装,请先安装Nginx"
exit 1
fi
if ! command -v openssl &> /dev/null; then
log_error "OpenSSL未安装"
exit 1
fi
log_info "前置检查通过"
# 创建备份目录
log_step "创建备份目录..."
mkdir -p "$BACKUP_DIR"
log_info "备份目录:$BACKUP_DIR"
# 备份现有配置
log_step "备份现有配置..."
if [ -d "$JENKINS_HOME" ]; then
cp -r "$JENKINS_HOME" "$BACKUP_DIR/jenkins-home" 2>/dev/null || true
fi
if [ -d "$NGINX_CONF_DIR" ]; then
cp -r "$NGINX_CONF_DIR" "$BACKUP_DIR/nginx-conf" 2>/dev/null || true
fi
log_info "配置已备份"
# 步骤1:修改Jenkins监听地址
log_step "步骤1/7:修改Jenkins监听地址为127.0.0.1..."
if [ -f "/etc/default/jenkins" ]; then
JENKINS_DEFAULT="/etc/default/jenkins"
elif [ -f "/etc/sysconfig/jenkins" ]; then
JENKINS_DEFAULT="/etc/sysconfig/jenkins"
else
log_warn "未找到Jenkins配置文件,跳过此步骤"
JENKINS_DEFAULT=""
fi
if [ -n "$JENKINS_DEFAULT" ]; then
cp "$JENKINS_DEFAULT" "$BACKUP_DIR/jenkins-default.bak"
if grep -q "JENKINS_ARGS" "$JENKINS_DEFAULT"; then
if grep -q "httpListenAddress" "$JENKINS_DEFAULT"; then
sed -i 's/httpListenAddress=[^ ]*/httpListenAddress=127.0.0.1/' "$JENKINS_DEFAULT"
else
sed -i '/JENKINS_ARGS=/ s/"$/ --httpListenAddress=127.0.0.1"/' "$JENKINS_DEFAULT"
fi
else
echo 'JENKINS_ARGS="--httpListenAddress=127.0.0.1"' >> "$JENKINS_DEFAULT"
fi
log_info "Jenkins配置已更新,仅监听127.0.0.1"
fi
# 步骤2:生成HTTP Basic Auth密码
log_step "步骤2/7:生成HTTP Basic Auth密码..."
read -sp "请输入Jenkins访问密码: " JENKINS_PASSWORD
echo ""
read -sp "请再次确认密码: " JENKINS_PASSWORD_CONFIRM
echo ""
if [ "$JENKINS_PASSWORD" != "$JENKINS_PASSWORD_CONFIRM" ]; then
log_error "两次密码输入不一致"
exit 1
fi
if [ -z "$JENKINS_PASSWORD" ]; then
log_error "密码不能为空"
exit 1
fi
HTPASSWD_FILE="$NGINX_CONF_DIR/.jenkins-htpasswd"
htpasswd -bc "$HTPASSWD_FILE" "$ADMIN_USER" "$JENKINS_PASSWORD" 2>/dev/null || \
openssl passwd -apr1 "$JENKINS_PASSWORD" | sed "s|^|$ADMIN_USER:|" > "$HTPASSWD_FILE"
chmod 600 "$HTPASSWD_FILE"
log_info "HTTP Basic Auth密码文件已生成:$HTPASSWD_FILE"
# 步骤3:创建Nginx安全配置
log_step "步骤3/7:创建Nginx反向代理安全配置..."
NGINX_JENKINS_CONF="$NGINX_CONF_DIR/jenkins-security.conf"
cat > "$NGINX_JENKINS_CONF" << 'NGINX_CONF_EOF'
# Jenkins安全反向代理配置
# 作者:张翔
# 日期:2026-04-07
# 说明:多层安全防护 - 认证、频率限制、IP白名单、审计日志
# 上游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
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主配置
server {
listen 443 ssl http2;
server_name DOMAIN_PLACEHOLDER;
# SSL配置
ssl_certificate /etc/letsencrypt/live/DOMAIN_PLACEHOLDER/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_PLACEHOLDER/privkey.pem;
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白名单(仅允许Gitea服务器)
# ALLOWED_IPS_PLACEHOLDER
# 验证Webhook签名
# if ($http_x_gitea_signature = "") {
# return 403;
# }
# 代理到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
# 替换占位符
sed -i "s|DOMAIN_PLACEHOLDER|$DOMAIN|g" "$NGINX_JENKINS_CONF"
sed -i "s|HTPASSWD_FILE_PLACEHOLDER|$HTPASSWD_FILE|g" "$NGINX_JENKINS_CONF"
# 添加IP白名单
if [ -n "$ALLOWED_IPS" ]; then
IP_ALLOW_RULE="allow $ALLOWED_IPS; deny all;"
sed -i "s|# ALLOWED_IPS_PLACEHOLDER|$IP_ALLOW_RULE|g" "$NGINX_JENKINS_CONF"
fi
log_info "Nginx安全配置已创建:$NGINX_JENKINS_CONF"
# 步骤4:配置防火墙规则
log_step "步骤4/7:配置防火墙规则..."
if command -v ufw &> /dev/null; then
ufw --force enable
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
ufw deny 8080/tcp comment 'Jenkins Direct Access Blocked'
ufw --force reload
log_info "UFW防火墙规则已配置"
elif command -v firewall-cmd &> /dev/null; then
systemctl start firewalld
systemctl enable firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --remove-port=8080/tcp
firewall-cmd --reload
log_info "Firewalld防火墙规则已配置"
else
log_warn "未检测到防火墙,请手动配置iptables规则"
fi
# 步骤5:创建Webhook签名验证脚本
log_step "步骤5/7:创建Webhook签名验证脚本..."
WEBHOOK_VERIFY_SCRIPT="/usr/local/bin/verify-jenkins-webhook.sh"
cat > "$WEBHOOK_VERIFY_SCRIPT" << 'WEBHOOK_EOF'
#!/bin/bash
# Webhook签名验证脚本
# 用途:验证来自Gitea的Webhook请求签名
set -euo pipefail
WEBHOOK_SECRET="${WEBHOOK_SECRET:-}"
PAYLOAD_FILE="${1:-/dev/stdin}"
if [ -z "$WEBHOOK_SECRET" ]; then
echo "ERROR: WEBHOOK_SECRET not set" >&2
exit 1
fi
# 读取请求体
PAYLOAD=$(cat "$PAYLOAD_FILE")
# 计算HMAC签名
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')
echo "sha256=$SIGNATURE"
WEBHOOK_EOF
chmod +x "$WEBHOOK_VERIFY_SCRIPT"
log_info "Webhook验证脚本已创建:$WEBHOOK_VERIFY_SCRIPT"
# 步骤6:配置Jenkins安全设置
log_step "步骤6/7:配置Jenkins安全设置..."
JENKINS_CONFIG_XML="$JENKINS_HOME/config.xml"
if [ -f "$JENKINS_CONFIG_XML" ]; then
cp "$JENKINS_CONFIG_XML" "$BACKUP_DIR/config.xml.bak"
# 禁用匿名访问
if grep -q "<useSecurity>true</useSecurity>" "$JENKINS_CONFIG_XML"; then
log_info "Jenkins安全已启用"
else
sed -i 's|<useSecurity>.*</useSecurity>|<useSecurity>true</useSecurity>|' "$JENKINS_CONFIG_XML" 2>/dev/null || true
fi
log_info "Jenkins安全配置已更新"
fi
# 步骤7:创建安全验证脚本
log_step "步骤7/7:创建安全验证脚本..."
VERIFY_SCRIPT="/usr/local/bin/verify-jenkins-security.sh"
cat > "$VERIFY_SCRIPT" << 'VERIFY_EOF'
#!/bin/bash
# Jenkins安全验证脚本
# 作者:张翔
# 用途:验证Jenkins安全加固是否成功
set -euo pipefail
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo "=========================================="
echo " Jenkins安全验证"
echo "=========================================="
echo ""
PASS=0
FAIL=0
check_pass() {
echo -e "${GREEN}[✓]${NC} $1"
((PASS++))
}
check_fail() {
echo -e "${RED}[✗]${NC} $1"
((FAIL++))
}
check_warn() {
echo -e "${YELLOW}[!]${NC} $1"
}
# 检查1Jenkins是否仅监听127.0.0.1
echo "检查1Jenkins监听地址"
if netstat -tlnp 2>/dev/null | grep -q ":8080.*127.0.0.1"; then
check_pass "Jenkins仅监听127.0.0.1:8080"
elif netstat -tlnp 2>/dev/null | grep -q ":8080.*0.0.0.0"; then
check_fail "Jenkins监听0.0.0.0:8080(风险!)"
else
check_warn "Jenkins未运行或监听地址未知"
fi
# 检查2:直接访问8080端口是否被拒绝
echo ""
echo "检查2:直接访问8080端口"
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 2 http://localhost:8080 2>/dev/null | grep -q "000"; then
check_pass "直接访问8080端口被拒绝"
else
check_fail "可以直接访问8080端口(风险!)"
fi
# 检查3Nginx配置是否正确
echo ""
echo "检查3Nginx配置"
if nginx -t 2>/dev/null; then
check_pass "Nginx配置语法正确"
else
check_fail "Nginx配置存在错误"
fi
# 检查4HTTPS是否启用
echo ""
echo "检查4HTTPS配置"
if [ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then
check_pass "SSL证书已配置"
else
check_warn "SSL证书未找到,请手动配置"
fi
# 检查5:防火墙规则
echo ""
echo "检查5:防火墙规则"
if command -v ufw &> /dev/null; then
if ufw status | grep -q "8080.*DENY"; then
check_pass "防火墙已阻止8080端口"
else
check_fail "防火墙未阻止8080端口"
fi
elif command -v firewall-cmd &> /dev/null; then
if ! firewall-cmd --list-ports | grep -q "8080"; then
check_pass "防火墙已阻止8080端口"
else
check_fail "防火墙未阻止8080端口"
fi
else
check_warn "未检测到防火墙"
fi
# 检查6HTTP Basic Auth
echo ""
echo "检查6HTTP Basic Auth"
if [ -f "/etc/nginx/conf.d/.jenkins-htpasswd" ]; then
check_pass "HTTP Basic Auth密码文件存在"
else
check_fail "HTTP Basic Auth密码文件不存在"
fi
# 检查7Jenkinsfile中是否还有硬编码token
echo ""
echo "检查7:敏感信息检查"
if [ -f "Jenkinsfile" ]; then
if grep -q "token.*=.*['\"].*['\"]" Jenkinsfile 2>/dev/null; then
check_fail "Jenkinsfile中存在硬编码token"
else
check_pass "Jenkinsfile中未发现硬编码token"
fi
else
check_warn "未找到Jenkinsfile"
fi
# 汇总
echo ""
echo "=========================================="
echo " 验证结果:通过 $PASS 项,失败 $FAIL 项"
echo "=========================================="
if [ $FAIL -eq 0 ]; then
echo -e "${GREEN}安全加固验证通过!${NC}"
exit 0
else
echo -e "${RED}安全加固存在风险,请检查失败项!${NC}"
exit 1
fi
VERIFY_EOF
chmod +x "$VERIFY_SCRIPT"
log_info "安全验证脚本已创建:$VERIFY_SCRIPT"
# 重启服务
log_step "重启服务..."
echo ""
read -p "是否立即重启Jenkins和Nginx服务?(y/N): " RESTART_CHOICE
if [[ "$RESTART_CHOICE" =~ ^[Yy]$ ]]; then
if command -v systemctl &> /dev/null; then
systemctl restart jenkins
systemctl restart nginx
log_info "服务已重启"
else
service jenkins restart
service nginx restart
log_info "服务已重启"
fi
else
log_warn "请手动重启服务:systemctl restart jenkins nginx"
fi
# 输出安全信息
echo ""
echo "======================================================================"
echo " 安全加固完成"
echo "======================================================================"
echo ""
echo "📋 重要信息:"
echo " - Jenkins访问地址: https://$DOMAIN/jenkins/"
echo " - 管理员用户: $ADMIN_USER"
echo " - Webhook密钥: $WEBHOOK_SECRET"
echo ""
echo "📁 备份位置: $BACKUP_DIR"
echo ""
echo "✅ 后续步骤:"
echo " 1. 运行安全验证: $VERIFY_SCRIPT"
echo " 2. 更新Jenkinsfile中的webhook token为环境变量"
echo " 3. 配置SSL证书(如未配置)"
echo " 4. 设置定期安全审计"
echo ""
echo "⚠️ 安全提醒:"
echo " - 请妥善保管管理员密码和Webhook密钥"
echo " - 定期更新密码(建议每90天)"
echo " - 监控访问日志:/var/log/nginx/jenkins-access.log"
echo ""
echo "📞 如遇问题,请检查:"
echo " - Jenkins日志: journalctl -u jenkins -f"
echo " - Nginx日志: tail -f /var/log/nginx/jenkins-error.log"
echo "======================================================================"