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

29 KiB
Raw Blame History

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