第十部分:安全加固

33. 访问控制

33.1 基于IP的访问控制

33.1.1 防火墙白名单

仅允许特定IP连接:

#!/bin/bash
# setup-ip-whitelist.sh

# 允许的IP列表
ALLOWED_IPS=(
    "203.0.113.10"     # 办公室
    "198.51.100.0/24"  # 分支机构网段
    "192.0.2.50"       # 家庭网络
)

echo "=== 配置IP白名单 ==="

# 1. 设置默认策略(拒绝所有)
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP

# 2. 允许已建立的连接
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# 3. 允许本地回环
sudo iptables -A INPUT -i lo -j ACCEPT

# 4. 添加白名单IP
echo "添加允许的IP..."
for ip in "${ALLOWED_IPS[@]}"; do
    echo "  允许: $ip"
    sudo iptables -A INPUT -p udp --dport 51820 -s $ip -j ACCEPT
done

# 5. 记录被拒绝的连接
sudo iptables -A INPUT -p udp --dport 51820 -j LOG --log-prefix "WG-BLOCKED: "
sudo iptables -A INPUT -p udp --dport 51820 -j DROP

# 6. 保存规则
sudo netfilter-persistent save

echo ""
echo "✓ IP白名单配置完成"
echo ""
echo "当前规则:"
sudo iptables -L INPUT -n -v --line-numbers | grep 51820

33.1.2 地理位置限制

使用GeoIP限制连接:

#!/bin/bash
# setup-geoip-blocking.sh

echo "=== 配置地理位置限制 ==="

# 1. 安装GeoIP模块
echo "[1] 安装GeoIP..."
sudo apt install -y xtables-addons-common libtext-csv-xs-perl

# 2. 下载GeoIP数据库
echo ""
echo "[2] 下载GeoIP数据库..."
sudo mkdir -p /usr/share/xt_geoip
cd /usr/share/xt_geoip

# 下载数据
sudo wget https://download.db-ip.com/free/dbip-country-lite-$(date +%Y-%m).csv.gz
sudo gunzip dbip-country-lite-*.csv.gz

# 转换数据
sudo /usr/lib/xtables-addons/xt_geoip_build -D . dbip-country-lite-*.csv

# 3. 配置iptables规则
echo ""
echo "[3] 配置规则..."

# 仅允许中国IP连接(示例)
sudo iptables -A INPUT -p udp --dport 51820 -m geoip --src-cc CN -j ACCEPT

# 拒绝其他国家
sudo iptables -A INPUT -p udp --dport 51820 -j LOG --log-prefix "GEOIP-BLOCK: "
sudo iptables -A INPUT -p udp --dport 51820 -j DROP

# 4. 保存规则
sudo netfilter-persistent save

echo ""
echo "✓ 地理位置限制配置完成"

查看被阻止的连接:

# 查看日志
sudo journalctl -k | grep "GEOIP-BLOCK"

# 实时监控
sudo tail -f /var/log/kern.log | grep "GEOIP-BLOCK"

33.2 端口敲门

33.2.1 配置knockd

安装和配置:

# 安装knockd
sudo apt install -y knockd

# 配置knockd
sudo nano /etc/knockd.conf

配置内容:

[options]
    UseSyslog

[openWireGuard]
    sequence    = 7000,8000,9000
    seq_timeout = 15
    command     = /usr/sbin/iptables -I INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
    tcpflags    = syn

[closeWireGuard]
    sequence    = 9000,8000,7000
    seq_timeout = 15
    command     = /usr/sbin/iptables -D INPUT -s %IP% -p udp --dport 51820 -j ACCEPT
    tcpflags    = syn

启用服务:

# 修改配置启用knockd
sudo nano /etc/default/knockd

# 设置
START_KNOCKD=1

# 启动服务
sudo systemctl enable knockd
sudo systemctl start knockd

客户端使用:

# 发送敲门序列(开启)
knock server.example.com 7000 8000 9000

# 连接WireGuard
wg-quick up wg0

# 发送关闭序列(可选)
knock server.example.com 9000 8000 7000

33.2.2 端口跳跃

动态端口脚本:

#!/bin/bash
# port-hopping.sh

# 端口池
PORTS=(51820 41194 33891 28765 19283)

# 当前端口索引文件
INDEX_FILE="/var/run/wireguard-port-index"

# 读取当前索引
if [ -f "$INDEX_FILE" ]; then
    CURRENT_INDEX=$(cat $INDEX_FILE)
else
    CURRENT_INDEX=0
fi

# 计算下一个索引
NEXT_INDEX=$(( (CURRENT_INDEX + 1) % ${#PORTS[@]} ))
NEW_PORT=${PORTS[$NEXT_INDEX]}

echo "=== 端口跳跃 ==="
echo "当前端口: ${PORTS[$CURRENT_INDEX]}"
echo "新端口: $NEW_PORT"

# 1. 停止WireGuard
sudo wg-quick down wg0

# 2. 修改配置
sudo sed -i "s/ListenPort = .*/ListenPort = $NEW_PORT/" /etc/wireguard/wg0.conf

# 3. 更新防火墙
sudo ufw delete allow ${PORTS[$CURRENT_INDEX]}/udp
sudo ufw allow $NEW_PORT/udp

# 4. 启动WireGuard
sudo wg-quick up wg0

# 5. 保存新索引
echo $NEXT_INDEX > $INDEX_FILE

echo "✓ 端口已更换为: $NEW_PORT"

# 通知客户端(需要实现)
# send_notification_to_clients $NEW_PORT

定时端口跳跃:

# 每小时更换端口
0 * * * * /usr/local/bin/port-hopping.sh >> /var/log/port-hopping.log 2>&1

33.3 fail2ban集成

33.3.1 安装配置fail2ban

安装fail2ban:

sudo apt install -y fail2ban

创建WireGuard过滤器:

sudo nano /etc/fail2ban/filter.d/wireguard.conf

内容:

[Definition]
# 匹配WireGuard认证失败
failregex = ^.*WireGuard.*Invalid handshake.*from <HOST>.*$
            ^.*wireguard.*authentication failed.*<HOST>.*$
            ^.*wg0.*handshake.*failed.*<HOST>.*$

ignoreregex =

创建jail配置:

sudo nano /etc/fail2ban/jail.d/wireguard.conf

内容:

[wireguard]
enabled = true
port = 51820
protocol = udp
filter = wireguard
logpath = /var/log/syslog
          /var/log/kern.log
maxretry = 3
findtime = 600
bantime = 3600
action = iptables-allports[name=wireguard, protocol=all]

重启fail2ban:

sudo systemctl restart fail2ban

33.3.2 监控和管理

查看fail2ban状态:

# 查看所有jail状态
sudo fail2ban-client status

# 查看WireGuard jail详情
sudo fail2ban-client status wireguard

# 查看被禁IP列表
sudo fail2ban-client get wireguard banip

手动操作:

# 手动封禁IP
sudo fail2ban-client set wireguard banip 203.0.113.100

# 解除封禁
sudo fail2ban-client set wireguard unbanip 203.0.113.100

# 查看日志
sudo tail -f /var/log/fail2ban.log

33.4 多因素认证

33.4.1 使用预共享密钥

生成预共享密钥:

# 生成PSK
wg genpsk > preshared.key

# 查看PSK
cat preshared.key

服务器配置:

[Interface]
PrivateKey = <服务器私钥>
Address = 10.8.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <客户端公钥>
PresharedKey = <从preshared.key读取>
AllowedIPs = 10.8.0.2/32

客户端配置:

[Interface]
PrivateKey = <客户端私钥>
Address = 10.8.0.2/24

[Peer]
PublicKey = <服务器公钥>
PresharedKey = <相同的PSK>
Endpoint = 192.168.1.66:51820
AllowedIPs = 10.8.0.0/24

批量添加PSK脚本:

#!/bin/bash
# add-psk-to-all-peers.sh

CONFIG_FILE="/etc/wireguard/wg0.conf"
BACKUP_FILE="${CONFIG_FILE}.bak.$(date +%Y%m%d_%H%M%S)"

echo "=== 为所有Peer添加PSK ==="

# 备份配置
sudo cp $CONFIG_FILE $BACKUP_FILE
echo "✓ 配置已备份: $BACKUP_FILE"

# 为每个peer生成PSK
sudo grep -n "^\[Peer\]" $CONFIG_FILE | while read line; do
    line_num=$(echo $line | cut -d: -f1)
    
    # 生成PSK
    psk=$(wg genpsk)
    
    # 插入PSK
    sudo sed -i "${line_num}a PresharedKey = $psk" $CONFIG_FILE
    
    echo "✓ Peer at line $line_num: PSK added"
done

# 重新加载
sudo wg syncconf wg0 <(wg-quick strip wg0)

echo ""
echo "✓ 所有Peer已添加PSK"
echo "备份文件: $BACKUP_file"

33.4.2 结合TOTP(时间基准一次性密码)

概念设计:

#!/bin/bash
# wireguard-totp-wrapper.sh

# 这是一个概念脚本,展示如何集成TOTP
# 实际实现需要额外开发

USERNAME=$1
TOTP_CODE=$2

if [ -z "$USERNAME" ] || [ -z "$TOTP_CODE" ]; then
    echo "用法: $0 <用户名> <TOTP代码>"
    exit 1
fi

# 验证TOTP
if ! verify_totp "$USERNAME" "$TOTP_CODE"; then
    echo "✗ TOTP验证失败"
    # 记录失败尝试
    logger "WireGuard TOTP failed for user: $USERNAME"
    exit 1
fi

echo "✓ TOTP验证成功"

# 临时允许用户连接(5分钟)
USER_IP=$(get_user_ip "$USERNAME")
sudo iptables -I INPUT -s $USER_IP -p udp --dport 51820 -j ACCEPT

# 5分钟后自动删除规则
(sleep 300; sudo iptables -D INPUT -s $USER_IP -p udp --dport 51820 -j ACCEPT) &

echo "✓ 已授权连接(5分钟)"

34. 密钥管理

34.1 密钥生成最佳实践

34.1.1 安全的密钥生成

使用强随机源:

#!/bin/bash
# secure-key-generation.sh

echo "=== 安全密钥生成 ==="

# 1. 检查随机源
echo "[1] 检查随机源..."
if [ -c /dev/urandom ]; then
    echo "✓ /dev/urandom 可用"
else
    echo "✗ /dev/urandom 不可用"
    exit 1
fi

# 2. 检查熵池
echo ""
echo "[2] 检查系统熵..."
ENTROPY=$(cat /proc/sys/kernel/random/entropy_avail)
echo "可用熵: $ENTROPY"

if [ $ENTROPY -lt 1000 ]; then
    echo "⚠ 警告: 熵较低,建议安装rng-tools"
    echo "sudo apt install rng-tools"
fi

# 3. 生成密钥
echo ""
echo "[3] 生成密钥对..."

# 设置umask确保文件权限
umask 077

# 生成私钥
PRIVATE_KEY=$(wg genkey)
PUBLIC_KEY=$(echo $PRIVATE_KEY | wg pubkey)

# 保存到安全位置
KEY_DIR="/etc/wireguard/keys"
sudo mkdir -p $KEY_DIR
sudo chmod 700 $KEY_DIR

echo $PRIVATE_KEY | sudo tee $KEY_DIR/private.key > /dev/null
echo $PUBLIC_KEY | sudo tee $KEY_DIR/public.key > /dev/null

# 设置权限
sudo chmod 600 $KEY_DIR/private.key
sudo chmod 644 $KEY_DIR/public.key
sudo chown root:root $KEY_DIR/*.key

echo "✓ 密钥已生成"
echo ""
echo "私钥: $KEY_DIR/private.key"
echo "公钥: $KEY_DIR/public.key"

# 4. 验证密钥
echo ""
echo "[4] 验证密钥..."
if [ ${#PRIVATE_KEY} -eq 44 ] && [ ${#PUBLIC_KEY} -eq 44 ]; then
    echo "✓ 密钥格式正确"
else
    echo "✗ 密钥格式错误"
    exit 1
fi

# 5. 记录密钥指纹
echo ""
echo "[5] 记录密钥指纹..."
FINGERPRINT=$(echo $PUBLIC_KEY | sha256sum | awk '{print $1}')
echo "公钥指纹: $FINGERPRINT"

{
    echo "密钥生成记录"
    echo "时间: $(date)"
    echo "公钥: $PUBLIC_KEY"
    echo "指纹: $FINGERPRINT"
} | sudo tee $KEY_DIR/keyinfo.txt > /dev/null

echo ""
echo "=== 生成完成 ==="

34.1.2 密钥强度验证

密钥质量检查:

#!/bin/bash
# validate-key-strength.sh

PRIVATE_KEY=$1

if [ -z "$PRIVATE_KEY" ]; then
    echo "用法: $0 <私钥>"
    exit 1
fi

echo "=== 密钥强度验证 ==="

# 1. 长度检查
echo "[1] 长度检查..."
if [ ${#PRIVATE_KEY} -eq 44 ]; then
    echo "✓ 长度正确 (44字符)"
else
    echo "✗ 长度错误: ${#PRIVATE_KEY}"
    exit 1
fi

# 2. Base64验证
echo ""
echo "[2] Base64格式验证..."
if echo "$PRIVATE_KEY" | base64 -d > /dev/null 2>&1; then
    echo "✓ 有效的Base64编码"
else
    echo "✗ 无效的Base64编码"
    exit 1
fi

# 3. 解码长度
echo ""
echo "[3] 解码后长度检查..."
DECODED_LEN=$(echo "$PRIVATE_KEY" | base64 -d | wc -c)
if [ $DECODED_LEN -eq 32 ]; then
    echo "✓ 解码后长度正确 (32字节)"
else
    echo "✗ 解码后长度错误: $DECODED_LEN"
    exit 1
fi

# 4. 生成公钥测试
echo ""
echo "[4] 公钥生成测试..."
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | wg pubkey)
if [ ${#PUBLIC_KEY} -eq 44 ]; then
    echo "✓ 可以生成有效公钥"
    echo "公钥: ${PUBLIC_KEY:0:20}..."
else
    echo "✗ 无法生成有效公钥"
    exit 1
fi

echo ""
echo "=== 验证通过 ==="

34.2 密钥轮换

34.2.1 服务器密钥轮换

服务器密钥轮换流程:

#!/bin/bash
# rotate-server-keys.sh

echo "=== 服务器密钥轮换 ==="

CONFIG_FILE="/etc/wireguard/wg0.conf"
KEYS_DIR="/etc/wireguard/keys"
BACKUP_DIR="/var/backups/wireguard/key-rotation"

# 创建备份目录
sudo mkdir -p $BACKUP_DIR
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# 1. 备份当前配置和密钥
echo "[1] 备份当前配置..."
sudo cp $CONFIG_FILE $BACKUP_DIR/wg0.conf.$TIMESTAMP
sudo cp -r $KEYS_DIR $BACKUP_DIR/keys.$TIMESTAMP
echo "✓ 备份完成"

# 2. 获取当前密钥
echo ""
echo "[2] 当前密钥信息..."
OLD_PRIVATE=$(sudo grep PrivateKey $CONFIG_FILE | awk '{print $3}')
OLD_PUBLIC=$(echo $OLD_PRIVATE | wg pubkey)
echo "旧公钥: ${OLD_PUBLIC:0:20}..."

# 3. 生成新密钥
echo ""
echo "[3] 生成新密钥..."
NEW_PRIVATE=$(wg genkey)
NEW_PUBLIC=$(echo $NEW_PRIVATE | wg pubkey)
echo "新公钥: ${NEW_PUBLIC:0:20}..."

# 保存新密钥
echo $NEW_PRIVATE | sudo tee $KEYS_DIR/server_private.key.new > /dev/null
echo $NEW_PUBLIC | sudo tee $KEYS_DIR/server_public.key.new > /dev/null

# 4. 更新服务器配置
echo ""
echo "[4] 更新服务器配置..."
sudo sed -i "s|PrivateKey = $OLD_PRIVATE|PrivateKey = $NEW_PRIVATE|" $CONFIG_FILE
echo "✓ 配置已更新"

# 5. 生成新的客户端配置
echo ""
echo "[5] 生成新的客户端配置..."
CLIENT_CONFIG_DIR="/etc/wireguard/clients"
NEW_CLIENT_DIR="/etc/wireguard/clients-new-keys"
sudo mkdir -p $NEW_CLIENT_DIR

for conf in $CLIENT_CONFIG_DIR/*.conf; do
    if [ -f "$conf" ]; then
        filename=$(basename "$conf")
        
        # 替换服务器公钥
        sudo sed "s|PublicKey = $OLD_PUBLIC|PublicKey = $NEW_PUBLIC|" "$conf" \
            > "$NEW_CLIENT_DIR/$filename"
        
        echo "  ✓ 更新: $filename"
    fi
done

# 6. 重启WireGuard
echo ""
echo "[6] 重启WireGuard..."
sudo systemctl restart wg-quick@wg0

if systemctl is-active --quiet wg-quick@wg0; then
    echo "✓ WireGuard重启成功"
else
    echo "✗ WireGuard重启失败"
    echo "恢复旧配置..."
    sudo cp $BACKUP_DIR/wg0.conf.$TIMESTAMP $CONFIG_FILE
    sudo systemctl restart wg-quick@wg0
    exit 1
fi

# 7. 验证
echo ""
echo "[7] 验证新密钥..."
CURRENT_PUBLIC=$(sudo wg show wg0 public-key)
if [ "$CURRENT_PUBLIC" = "$NEW_PUBLIC" ]; then
    echo "✓ 新密钥已生效"
else
    echo "✗ 密钥验证失败"
    exit 1
fi

# 8. 移动新密钥
sudo mv $KEYS_DIR/server_private.key.new $KEYS_DIR/server_private.key
sudo mv $KEYS_DIR/server_public.key.new $KEYS_DIR/server_public.key

echo ""
echo "=== 密钥轮换完成 ==="
echo ""
echo "重要提示:"
echo "1. 新客户端配置位于: $NEW_CLIENT_DIR"
echo "2. 必须将新配置分发给所有客户端"
echo "3. 客户端更新后才能重新连接"
echo "4. 备份文件位于: $BACKUP_DIR"
echo ""
echo "旧公钥: $OLD_PUBLIC"
echo "新公钥: $NEW_PUBLIC"

34.2.2 客户端密钥轮换

单个客户端密钥轮换:

#!/bin/bash
# rotate-client-key.sh

USERNAME=$1

if [ -z "$USERNAME" ]; then
    echo "用法: $0 <用户名>"
    exit 1
fi

echo "=== 客户端密钥轮换: $USERNAME ==="

KEYS_DIR="/etc/wireguard/clients"
CONFIG_FILE="/etc/wireguard/wg0.conf"

# 1. 获取旧公钥
echo "[1] 获取当前密钥..."
OLD_PUBLIC=$(cat $KEYS_DIR/${USERNAME}_public.key 2>/dev/null)

if [ -z "$OLD_PUBLIC" ]; then
    echo "✗ 用户不存在"
    exit 1
fi

echo "旧公钥: ${OLD_PUBLIC:0:20}..."

# 2. 生成新密钥
echo ""
echo "[2] 生成新密钥..."
NEW_PRIVATE=$(wg genkey)
NEW_PUBLIC=$(echo $NEW_PRIVATE | wg pubkey)

# 备份旧密钥
sudo mv $KEYS_DIR/${USERNAME}_private.key \
    $KEYS_DIR/${USERNAME}_private.key.old
sudo mv $KEYS_DIR/${USERNAME}_public.key \
    $KEYS_DIR/${USERNAME}_public.key.old

# 保存新密钥
echo $NEW_PRIVATE | sudo tee $KEYS_DIR/${USERNAME}_private.key > /dev/null
echo $NEW_PUBLIC | sudo tee $KEYS_DIR/${USERNAME}_public.key > /dev/null
sudo chmod 600 $KEYS_DIR/${USERNAME}_private.key

echo "新公钥: ${NEW_PUBLIC:0:20}..."

# 3. 更新服务器配置
echo ""
echo "[3] 更新服务器配置..."
sudo sed -i "s|PublicKey = $OLD_PUBLIC|PublicKey = $NEW_PUBLIC|" $CONFIG_FILE
echo "✓ 配置已更新"

# 4. 重新加载
echo ""
echo "[4] 重新加载配置..."
sudo wg syncconf wg0 <(wg-quick strip wg0)
echo "✓ 配置已重新加载"

# 5. 生成新的客户端配置
echo ""
echo "[5] 生成新客户端配置..."

# 获取客户端IP
CLIENT_IP=$(sudo grep -B 5 "$NEW_PUBLIC" $CONFIG_FILE | grep AllowedIPs | awk '{print $3}' | cut -d'/' -f1)

# 服务器信息
SERVER_PUBLIC=$(sudo wg show wg0 public-key)
SERVER_ENDPOINT="192.168.1.66:51820"

# 生成配置
NEW_CONFIG="$KEYS_DIR/${USERNAME}_new.conf"
cat << EOF | sudo tee $NEW_CONFIG > /dev/null
[Interface]
PrivateKey = $NEW_PRIVATE
Address = $CLIENT_IP/24
DNS = 223.5.5.5, 114.114.114.114

[Peer]
PublicKey = $SERVER_PUBLIC
Endpoint = $SERVER_ENDPOINT
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
EOF

sudo chmod 600 $NEW_CONFIG

echo "✓ 新配置已生成: $NEW_CONFIG"

# 6. 显示配置
echo ""
echo "新客户端配置:"
echo "----------------------------------------"
cat $NEW_CONFIG
echo "----------------------------------------"

echo ""
echo "=== 轮换完成 ==="
echo "请将新配置发送给用户: $USERNAME"

34.3 密钥存储

34.3.1 加密存储

使用GPG加密密钥:

#!/bin/bash
# encrypt-keys.sh

echo "=== 加密WireGuard密钥 ==="

KEYS_DIR="/etc/wireguard"
ENCRYPTED_DIR="/root/wireguard-keys-encrypted"

# 创建加密目录
sudo mkdir -p $ENCRYPTED_DIR

# GPG密钥ID(需要预先生成)
GPG_KEY_ID="[email protected]"

# 加密所有密钥文件
echo "加密密钥文件..."
for keyfile in $KEYS_DIR/*.key; do
    if [ -f "$keyfile" ]; then
        filename=$(basename "$keyfile")
        
        # 加密
        sudo gpg --encrypt \
            --recipient $GPG_KEY_ID \
            --output $ENCRYPTED_DIR/${filename}.gpg \
            $keyfile
        
        echo "✓ 已加密: $filename"
    fi
done

# 加密配置文件
sudo gpg --encrypt \
    --recipient $GPG_KEY_ID \
    --output $ENCRYPTED_DIR/wg0.conf.gpg \
    $KEYS_DIR/wg0.conf

echo "✓ 已加密: wg0.conf"

# 设置权限
sudo chmod 600 $ENCRYPTED_DIR/*.gpg
sudo chown root:root $ENCRYPTED_DIR/*.gpg

echo ""
echo "加密文件位于: $ENCRYPTED_DIR"
echo "解密命令: sudo gpg --decrypt <文件>.gpg"

解密恢复:

#!/bin/bash
# decrypt-keys.sh

ENCRYPTED_DIR="/root/wireguard-keys-encrypted"
RESTORE_DIR="/tmp/wireguard-restore"

echo "=== 解密WireGuard密钥 ==="

# 创建恢复目录
mkdir -p $RESTORE_DIR

# 解密所有文件
for encrypted in $ENCRYPTED_DIR/*.gpg; do
    if [ -f "$encrypted" ]; then
        filename=$(basename "$encrypted" .gpg)
        
        # 解密
        sudo gpg --decrypt \
            --output $RESTORE_DIR/$filename \
            $encrypted
        
        echo "✓ 已解密: $filename"
    fi
done

echo ""
echo "解密文件位于: $RESTORE_DIR"
echo "验证文件后,可以恢复到 /etc/wireguard/"

34.3.2 密钥保险库

使用Vault存储密钥(概念):

#!/bin/bash
# vault-integration.sh

# 这是一个概念脚本,展示如何与HashiCorp Vault集成

VAULT_ADDR="https://vault.example.com:8200"
VAULT_TOKEN="<your-vault-token>"

# 存储密钥到Vault
store_key_to_vault() {
    local key_name=$1
    local key_value=$2
    
    curl -X POST \
        -H "X-Vault-Token: $VAULT_TOKEN" \
        -d "{\"data\": {\"key\": \"$key_value\"}}" \
        $VAULT_ADDR/v1/secret/data/wireguard/$key_name
}

# 从Vault读取密钥
read_key_from_vault() {
    local key_name=$1
    
    curl -X GET \
        -H "X-Vault-Token: $VAULT_TOKEN" \
        $VAULT_ADDR/v1/secret/data/wireguard/$key_name \
        | jq -r '.data.data.key'
}

# 示例使用
# PRIVATE_KEY=$(read_key_from_vault "server_private")

34.4 密钥泄露响应

34.4.1 检测密钥泄露

检查密钥是否在公开位置:

#!/bin/bash
# check-key-exposure.sh

echo "=== 检查密钥泄露风险 ==="

KEYS_DIR="/etc/wireguard"

# 1. 检查文件权限
echo "[1] 检查文件权限..."
find $KEYS_DIR -name "*.key" -o -name "*.conf" | while read file; do
    perms=$(stat -c %a "$file")
    
    if [ "$perms" != "600" ] && [ "$perms" != "640" ]; then
        echo "⚠ 警告: $file 权限过于开放 ($perms)"
    fi
done

# 2. 检查备份文件
echo ""
echo "[2] 检查备份文件..."
if find $KEYS_DIR -name "*.bak" -o -name "*~" | grep -q .; then
    echo "⚠ 警告: 发现备份文件"
    find $KEYS_DIR -name "*.bak" -o -name "*~"
fi

# 3. 检查Git仓库
echo ""
echo "[3] 检查Git仓库..."
if [ -d "$KEYS_DIR/.git" ]; then
    echo "⚠ 警告: WireGuard目录是Git仓库"
    
    cd $KEYS_DIR
    if git ls-files | grep -E '\.key$'; then
        echo "✗ 密钥文件被Git跟踪"
    fi
fi

# 4. 检查历史命令
echo ""
echo "[4] 检查历史命令..."
if grep -i "PrivateKey" ~/.bash_history 2>/dev/null; then
    echo "⚠ 警告: bash历史中发现私钥相关命令"
fi

# 5. 检查日志文件
echo ""
echo "[5] 检查日志文件..."
if sudo grep -i "PrivateKey" /var/log/syslog 2>/dev/null | grep -v "hidden"; then
    echo "⚠ 警告: 系统日志中可能包含私钥"
fi

# 6. 检查进程内存(需要root)
echo ""
echo "[6] 检查进程内存..."
# 这部分较复杂,仅提示
echo "ℹ 建议定期检查进程内存转储"

echo ""
echo "=== 检查完成 ==="

34.4.2 泄露响应流程

密钥泄露应急响应:

#!/bin/bash
# key-compromise-response.sh

echo "=== 密钥泄露应急响应 ==="
echo "⚠ 警告: 此操作将撤销所有现有密钥"
echo ""

read -p "确认执行应急响应? (输入 YES 继续) " -r
if [ "$REPLY" != "YES" ]; then
    echo "操作已取消"
    exit 0
fi

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
INCIDENT_DIR="/var/log/wireguard-incident-$TIMESTAMP"

# 1. 记录事件
echo ""
echo "[1] 记录安全事件..."
sudo mkdir -p $INCIDENT_DIR

{
    echo "WireGuard密钥泄露事件"
    echo "时间: $(date)"
    echo "响应人员: $(whoami)"
    echo ""
    echo "当前配置快照:"
    sudo wg show wg0
} | sudo tee $INCIDENT_DIR/incident-report.txt

# 2. 备份当前状态
echo ""
echo "[2] 备份当前状态..."
sudo tar czf $INCIDENT_DIR/pre-response-backup.tar.gz /etc/wireguard/
echo "✓ 备份完成"

# 3. 断开所有连接
echo ""
echo "[3] 断开所有连接..."
sudo wg-quick down wg0
echo "✓ WireGuard已停止"

# 4. 轮换服务器密钥
echo ""
echo "[4] 轮换服务器密钥..."
sudo bash /usr/local/bin/rotate-server-keys.sh
echo "✓ 服务器密钥已轮换"

# 5. 轮换所有客户端密钥
echo ""
echo "[5] 轮换所有客户端密钥..."
CLIENTS_DIR="/etc/wireguard/clients"

for pubkey_file in $CLIENTS_DIR/*_public.key; do
    if [ -f "$pubkey_file" ]; then
        username=$(basename "$pubkey_file" _public.key)
        echo "  轮换: $username"
        sudo bash /usr/local/bin/rotate-client-key.sh $username
    fi
done

# 6. 启用增强安全
echo ""
echo "[6] 启用增强安全..."

# 启用IP白名单
echo "  启用IP白名单..."
# sudo bash /usr/local/bin/setup-ip-whitelist.sh

# 启用fail2ban
echo "  启用fail2ban..."
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# 7. 生成事件报告
echo ""
echo "[7] 生成事件报告..."
{
    echo ""
    echo "响应措施:"
    echo "- 服务器密钥已轮换"
    echo "- 所有客户端密钥已轮换"
    echo "- 安全措施已加强"
    echo ""
    echo "后续行动:"
    echo "1. 审计访问日志"
    echo "2. 分发新的客户端配置"
    echo "3. 监控异常活动"
    echo "4. 更新密钥管理流程"
} | sudo tee -a $INCIDENT_DIR/incident-report.txt

echo ""
echo "=== 应急响应完成 ==="
echo "事件记录: $INCIDENT_DIR"
echo ""
echo "⚠ 重要提示:"
echo "1. 所有客户端必须更新配置才能重新连接"
echo "2. 新配置文件位于 /etc/wireguard/clients-new-keys/"
echo "3. 审查日志查找泄露源头"
echo "4. 考虑报告安全事件"

35. 审计和日志

35.1 审计日志配置

35.1.1 启用审计系统

安装和配置auditd:

# 安装auditd
sudo apt install -y auditd audispd-plugins

# 启动服务
sudo systemctl enable auditd
sudo systemctl start auditd

配置WireGuard审计规则:

#!/bin/bash
# setup-wireguard-audit.sh

echo "=== 配置WireGuard审计规则 ==="

# 审计规则文件
AUDIT_RULES="/etc/audit/rules.d/wireguard.rules"

# 创建审计规则
cat << 'EOF' | sudo tee $AUDIT_RULES
# WireGuard配置文件监控
-w /etc/wireguard/ -p wa -k wireguard_config

# WireGuard密钥文件监控
-w /etc/wireguard/wg0.conf -p wa -k wireguard_config_change
-w /etc/wireguard/server_private.key -p ra -k wireguard_key_access
-w /etc/wireguard/clients/ -p wa -k wireguard_client_keys

# WireGuard命令执行监控
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/wg -k wireguard_command
-a always,exit -F arch=b64 -S execve -F exe=/usr/bin/wg-quick -k wireguard_command

# 系统调用监控
-a always,exit -F arch=b64 -S socket -F a0=16 -k wireguard_socket

# 网络配置变更
-w /etc/sysctl.conf -p wa -k sysctl_changes
-w /etc/iptables/ -p wa -k iptables_changes

# systemd服务变更
-w /etc/systemd/system/[email protected] -p wa -k wireguard_service
EOF

echo "✓ 审计规则已创建: $AUDIT_RULES"

# 重新加载审计规则
sudo augenrules --load
echo "✓ 审计规则已加载"

# 查看当前规则
echo ""
echo "当前审计规则:"
sudo auditctl -l | grep wireguard

35.1.2 审计日志查询

查询审计事件:

#!/bin/bash
# query-audit-logs.sh

echo "=== WireGuard审计日志查询 ==="

# 1. 配置文件修改
echo ""
echo "[1] 配置文件修改记录:"
sudo ausearch -k wireguard_config -i | grep -A 5 "type=SYSCALL"

# 2. 密钥访问
echo ""
echo "[2] 密钥文件访问记录:"
sudo ausearch -k wireguard_key_access -i | grep -A 5 "type=PATH"

# 3. 命令执行
echo ""
echo "[3] WireGuard命令执行:"
sudo ausearch -k wireguard_command -i | grep -A 3 "comm="

# 4. 生成报告
echo ""
echo "[4] 生成审计报告..."
REPORT_FILE="/var/log/wireguard-audit-$(date +%Y%m%d).txt"

{
    echo "WireGuard审计报告"
    echo "生成时间: $(date)"
    echo "========================================"
    echo ""
    
    echo "配置变更:"
    sudo ausearch -k wireguard_config -i --start today | grep -c "type=SYSCALL"
    echo ""
    
    echo "密钥访问:"
    sudo ausearch -k wireguard_key_access -i --start today | grep -c "type=PATH"
    echo ""
    
    echo "命令执行:"
    sudo ausearch -k wireguard_command -i --start today | grep -c "comm="
    echo ""
} > $REPORT_FILE

echo "✓ 报告已生成: $REPORT_FILE"

实时监控审计事件:

#!/bin/bash
# monitor-audit-realtime.sh

echo "=== WireGuard审计实时监控 ==="
echo "监控WireGuard相关的审计事件..."
echo "按Ctrl+C退出"
echo ""

# 使用ausearch实时监控
sudo ausearch -k wireguard_config -k wireguard_key_access -k wireguard_command -i -ts recent | \
while read -r line; do
    echo "[$(date '+%H:%M:%S')] $line"
done

35.2 连接日志

35.2.1 记录连接事件

连接日志脚本:

#!/bin/bash
# log-connections.sh

LOG_FILE="/var/log/wireguard-connections.log"

echo "=== WireGuard连接日志记录 ==="

# 持续监控
while true; do
    # 获取当前peer信息
    sudo wg show wg0 dump | tail -n +2 | while IFS=$'\t' read -r pubkey psk endpoint allowed_ips handshake rx tx keepalive; do
        
        # 查找用户名
        username=$(grep -r "$pubkey" /etc/wireguard/clients/*.key 2>/dev/null | \
                   grep public | sed 's/.*\/\(.*\)_public.key.*/\1/')
        
        if [ -z "$username" ]; then
            username="unknown"
        fi
        
        # 提取IP
        client_ip=$(echo $allowed_ips | cut -d'/' -f1)
        
        # 计算握手时间
        now=$(date +%s)
        if [ "$handshake" != "0" ]; then
            age=$((now - handshake))
            
            # 如果是新连接(握手时间<10秒)
            if [ $age -lt 10 ]; then
                # 记录连接事件
                {
                    echo "CONNECTION_ESTABLISHED"
                    echo "Time: $(date '+%Y-%m-%d %H:%M:%S')"
                    echo "User: $username"
                    echo "ClientIP: $client_ip"
                    echo "Endpoint: $endpoint"
                    echo "PublicKey: ${pubkey:0:20}..."
                    echo "---"
                } >> $LOG_FILE
                
                # 记录到syslog
                logger -t wireguard "Connection established: $username from $endpoint"
            fi
        fi
    done
    
    sleep 10
done

配置为systemd服务:

sudo nano /etc/systemd/system/wireguard-connection-logger.service

内容:

[Unit]
Description=WireGuard Connection Logger
After[email protected]
Requires[email protected]

[Service]
Type=simple
ExecStart=/usr/local/bin/log-connections.sh
Restart=always
StandardOutput=null
StandardError=journal

[Install]
WantedBy=multi-user.target

启用:

sudo systemctl enable wireguard-connection-logger
sudo systemctl start wireguard-connection-logger

35.2.2 会话跟踪

跟踪用户会话:

#!/bin/bash
# track-sessions.sh

SESSION_DB="/var/lib/wireguard/sessions.db"

# 创建数据库(SQLite)
init_db() {
    sqlite3 $SESSION_DB << EOF
CREATE TABLE IF NOT EXISTS sessions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT,
    client_ip TEXT,
    endpoint TEXT,
    connect_time INTEGER,
    disconnect_time INTEGER,
    rx_bytes INTEGER,
    tx_bytes INTEGER,
    duration INTEGER
);
EOF
}

# 记录新会话
log_session_start() {
    local username=$1
    local client_ip=$2
    local endpoint=$3
    local timestamp=$(date +%s)
    
    sqlite3 $SESSION_DB << EOF
INSERT INTO sessions (username, client_ip, endpoint, connect_time)
VALUES ('$username', '$client_ip', '$endpoint', $timestamp);
EOF
    
    echo "Session started for $username"
}

# 记录会话结束
log_session_end() {
    local username=$1
    local rx_bytes=$2
    local tx_bytes=$3
    local timestamp=$(date +%s)
    
    # 计算会话时长
    local start_time=$(sqlite3 $SESSION_DB "SELECT connect_time FROM sessions WHERE username='$username' AND disconnect_time IS NULL ORDER BY id DESC LIMIT 1;")
    local duration=$((timestamp - start_time))
    
    sqlite3 $SESSION_DB << EOF
UPDATE sessions 
SET disconnect_time = $timestamp,
    rx_bytes = $rx_bytes,
    tx_bytes = $tx_bytes,
    duration = $duration
WHERE username = '$username' 
  AND disconnect_time IS NULL;
EOF
    
    echo "Session ended for $username (duration: ${duration}s)"
}

# 查询会话历史
query_sessions() {
    local username=$1
    
    echo "=== Session History for $username ==="
    
    sqlite3 -header -column $SESSION_DB << EOF
SELECT 
    datetime(connect_time, 'unixepoch', 'localtime') as Connect,
    datetime(disconnect_time, 'unixepoch', 'localtime') as Disconnect,
    duration || 's' as Duration,
    (rx_bytes / 1048576) || ' MB' as Downloaded,
    (tx_bytes / 1048576) || ' MB' as Uploaded
FROM sessions
WHERE username = '$username'
ORDER BY connect_time DESC
LIMIT 10;
EOF
}

# 初始化数据库
init_db

# 示例使用
# log_session_start "alice" "10.8.0.2" "203.0.113.10:54321"
# query_sessions "alice"

35.3 安全事件监控

35.3.1 异常检测

异常行为检测脚本:

#!/bin/bash
# detect-anomalies.sh

echo "=== WireGuard异常检测 ==="

ALERT_FILE="/var/log/wireguard-alerts.log"

# 1. 检测异常连接频率
echo "[1] 检测异常连接频率..."

# 统计每个IP的连接次数(最近1小时)
sudo journalctl -u wg-quick@wg0 --since "1 hour ago" | \
    grep -i "handshake" | \
    awk '{print $NF}' | \
    sort | uniq -c | \
    while read count ip; do
        if [ $count -gt 100 ]; then
            {
                echo "ALERT: High connection frequency"
                echo "Time: $(date)"
                echo "IP: $ip"
                echo "Count: $count"
                echo "---"
            } | tee -a $ALERT_FILE
        fi
    done

# 2. 检测异常流量
echo ""
echo "[2] 检测异常流量..."

sudo wg show wg0 dump | tail -n +2 | while IFS=$'\t' read -r pubkey psk endpoint allowed_ips handshake rx tx keepalive; do
    
    # 转换为GB
    rx_gb=$((rx / 1073741824))
    tx_gb=$((tx / 1073741824))
    
    # 如果流量超过阈值(例如100GB)
    if [ $rx_gb -gt 100 ] || [ $tx_gb -gt 100 ]; then
        username=$(grep -r "$pubkey" /etc/wireguard/clients/*.key 2>/dev/null | \
                   grep public | sed 's/.*\/\(.*\)_public.key.*/\1/')
        
        {
            echo "ALERT: High traffic usage"
            echo "Time: $(date)"
            echo "User: $username"
            echo "Download: ${rx_gb}GB"
            echo "Upload: ${tx_gb}GB"
            echo "---"
        } | tee -a $ALERT_FILE
    fi
done

# 3. 检测多地登录
echo ""
echo "[3] 检测多地登录..."

# 检测同一用户从多个地理位置连接
# (需要geoip数据库)

# 4. 检测端口扫描
echo ""
echo "[4] 检测端口扫描..."

# 检查是否有大量连接失败
failed_count=$(sudo journalctl -u wg-quick@wg0 --since "1 hour ago" | \
               grep -ic "failed\|invalid\|denied")

if [ $failed_count -gt 50 ]; then
    {
        echo "ALERT: Possible port scanning"
        echo "Time: $(date)"
        echo "Failed attempts: $failed_count"
        echo "---"
    } | tee -a $ALERT_FILE
fi

# 5. 检测配置篡改
echo ""
echo "[5] 检测配置篡改..."

CONFIG_FILE="/etc/wireguard/wg0.conf"
HASH_FILE="/var/lib/wireguard/config.sha256"

# 计算当前哈希
current_hash=$(sha256sum $CONFIG_FILE | awk '{print $1}')

# 检查是否有记录的哈希
if [ -f "$HASH_FILE" ]; then
    saved_hash=$(cat $HASH_FILE)
    
    if [ "$current_hash" != "$saved_hash" ]; then
        {
            echo "ALERT: Configuration file modified"
            echo "Time: $(date)"
            echo "File: $CONFIG_FILE"
            echo "Old hash: $saved_hash"
            echo "New hash: $current_hash"
            echo "---"
        } | tee -a $ALERT_FILE
        
        # 更新哈希
        echo $current_hash > $HASH_FILE
    fi
else
    # 首次运行,保存哈希
    echo $current_hash > $HASH_FILE
fi

echo ""
echo "=== 检测完成 ==="
echo "告警记录: $ALERT_FILE"

定时执行异常检测:

# 每10分钟检测一次
*/10 * * * * /usr/local/bin/detect-anomalies.sh

35.3.2 入侵检测集成

与OSSEC集成:

#!/bin/bash
# setup-ossec-wireguard.sh

echo "=== 配置OSSEC监控WireGuard ==="

# OSSEC规则文件
OSSEC_RULES="/var/ossec/rules/wireguard_rules.xml"

# 创建WireGuard规则
cat << 'EOF' | sudo tee $OSSEC_RULES
<group name="wireguard,">
  
  <!-- WireGuard连接失败 -->
  <rule id="100001" level="5">
    <decoded_as>wireguard</decoded_as>
    <match>handshake.*failed</match>
    <description>WireGuard handshake failed</description>
  </rule>

  <!-- 多次连接失败 -->
  <rule id="100002" level="10" frequency="5" timeframe="300">
    <if_matched_sid>100001</if_matched_sid>
    <description>Multiple WireGuard connection failures</description>
  </rule>

  <!-- 配置文件修改 -->
  <rule id="100003" level="7">
    <decoded_as>syscheck</decoded_as>
    <match>/etc/wireguard/</match>
    <description>WireGuard configuration modified</description>
  </rule>

  <!-- 密钥文件访问 -->
  <rule id="100004" level="8">
    <decoded_as>auditd</decoded_as>
    <match>wireguard_key_access</match>
    <description>WireGuard private key accessed</description>
  </rule>

  <!-- 异常流量 -->
  <rule id="100005" level="6">
    <match>High traffic usage</match>
    <description>WireGuard high traffic detected</description>
  </rule>

</group>
EOF

# 配置syscheck监控
OSSEC_CONF="/var/ossec/etc/ossec.conf"

# 添加WireGuard目录监控
sudo sed -i '/<syscheck>/a \
  <directories check_all="yes" realtime="yes">/etc/wireguard</directories>' \
  $OSSEC_CONF

# 重启OSSEC
sudo systemctl restart ossec

echo "✓ OSSEC配置完成"

35.4 合规性报告

35.4.1 生成合规报告

合规性检查脚本:

#!/bin/bash
# compliance-report.sh

REPORT_FILE="/var/reports/wireguard-compliance-$(date +%Y%m%d).html"

echo "=== 生成WireGuard合规性报告 ==="

# 创建HTML报告
cat << 'EOF' > $REPORT_FILE
<!DOCTYPE html>
<html>
<head>
    <title>WireGuard Compliance Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h1 { color: #333; }
        h2 { color: #666; border-bottom: 2px solid #ddd; }
        table { border-collapse: collapse; width: 100%; margin: 20px 0; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
        .pass { color: green; font-weight: bold; }
        .fail { color: red; font-weight: bold; }
        .warning { color: orange; font-weight: bold; }
    </style>
</head>
<body>
    <h1>WireGuard VPN Compliance Report</h1>
    <p>Generated: $(date)</p>
    <p>Server: $(hostname)</p>
EOF

# 1. 密钥安全检查
cat << EOF >> $REPORT_FILE
    <h2>1. Key Security</h2>
    <table>
        <tr>
            <th>Check</th>
            <th>Status</th>
            <th>Details</th>
        </tr>
EOF

# 检查密钥权限
for keyfile in /etc/wireguard/*.key; do
    if [ -f "$keyfile" ]; then
        perms=$(stat -c %a "$keyfile")
        if [ "$perms" = "600" ]; then
            status="<span class='pass'>PASS</span>"
        else
            status="<span class='fail'>FAIL</span>"
        fi
        
        echo "        <tr><td>$(basename $keyfile) permissions</td><td>$status</td><td>$perms</td></tr>" >> $REPORT_FILE
    fi
done

# 2. 配置安全检查
cat << EOF >> $REPORT_FILE
    </table>

    <h2>2. Configuration Security</h2>
    <table>
        <tr>
            <th>Check</th>
            <th>Status</th>
            <th>Details</th>
        </tr>
EOF

# IP转发
ip_forward=$(sysctl -n net.ipv4.ip_forward)
if [ "$ip_forward" = "1" ]; then
    status="<span class='pass'>PASS</span>"
else
    status="<span class='fail'>FAIL</span>"
fi
echo "        <tr><td>IP Forwarding</td><td>$status</td><td>$ip_forward</td></tr>" >> $REPORT_FILE

# 防火墙规则
if sudo iptables -L FORWARD -n | grep -q wg0; then
    status="<span class='pass'>PASS</span>"
    details="Enabled"
else
    status="<span class='fail'>FAIL</span>"
    details="Missing"
fi
echo "        <tr><td>Firewall Rules</td><td>$status</td><td>$details</td></tr>" >> $REPORT_FILE

# 3. 用户访问审计
cat << EOF >> $REPORT_FILE
    </table>

    <h2>3. User Access Audit</h2>
    <table>
        <tr>
            <th>Username</th>
            <th>Last Connection</th>
            <th>Total Data</th>
            <th>Status</th>
        </tr>
EOF

# 统计用户信息
sudo wg show wg0 dump | tail -n +2 | while IFS=$'\t' read -r pubkey psk endpoint allowed_ips handshake rx tx keepalive; do
    username=$(grep -r "$pubkey" /etc/wireguard/clients/*.key 2>/dev/null | \
               grep public | sed 's/.*\/\(.*\)_public.key.*/\1/')
    
    if [ -z "$username" ]; then
        username="unknown"
    fi
    
    # 最后连接时间
    if [ "$handshake" != "0" ]; then
        last_seen=$(date -d @$handshake '+%Y-%m-%d %H:%M:%S')
        
        # 检查是否活跃(最近7天)
        now=$(date +%s)
        age=$((now - handshake))
        if [ $age -lt 604800 ]; then
            status="<span class='pass'>Active</span>"
        else
            status="<span class='warning'>Inactive</span>"
        fi
    else
        last_seen="Never"
        status="<span class='warning'>Never Connected</span>"
    fi
    
    # 总流量
    total_bytes=$((rx + tx))
    total_gb=$((total_bytes / 1073741824))
    
    echo "        <tr><td>$username</td><td>$last_seen</td><td>${total_gb}GB</td><td>$status</td></tr>" >> $REPORT_FILE
done

# 4. 安全事件
cat << EOF >> $REPORT_FILE
    </table>

    <h2>4. Security Events (Last 30 Days)</h2>
    <table>
        <tr>
            <th>Event Type</th>
            <th>Count</th>
        </tr>
EOF

# 统计安全事件
failed_auth=$(sudo journalctl -u wg-quick@wg0 --since "30 days ago" | grep -ic "failed\|invalid")
config_changes=$(sudo ausearch -k wireguard_config --start $(date -d '30 days ago' +%Y-%m-%d) 2>/dev/null | grep -c "type=SYSCALL" || echo "0")
key_access=$(sudo ausearch -k wireguard_key_access --start $(date -d '30 days ago' +%Y-%m-%d) 2>/dev/null | grep -c "type=PATH" || echo "0")

echo "        <tr><td>Failed Authentication</td><td>$failed_auth</td></tr>" >> $REPORT_FILE
echo "        <tr><td>Configuration Changes</td><td>$config_changes</td></tr>" >> $REPORT_FILE
echo "        <tr><td>Key Access Events</td><td>$key_access</td></tr>" >> $REPORT_FILE

# 结束HTML
cat << 'EOF' >> $REPORT_FILE
    </table>

    <h2>5. Recommendations</h2>
    <ul>
EOF

# 生成建议
recommendations=()

# 检查不活跃用户
inactive_users=$(sudo wg show wg0 latest-handshakes | awk -v now=$(date +%s) '$2 < now - 2592000' | wc -l)
if [ $inactive_users -gt 0 ]; then
    recommendations+=("<li>Review and remove $inactive_users inactive users (no connection in 30 days)</li>")
fi

# 检查密钥年龄
key_age=$((($(date +%s) - $(stat -c %Y /etc/wireguard/server_private.key)) / 86400))
if [ $key_age -gt 365 ]; then
    recommendations+=("<li>Server key is $key_age days old - consider key rotation</li>")
fi

# 输出建议
if [ ${#recommendations[@]} -eq 0 ]; then
    echo "        <li>No recommendations at this time</li>" >> $REPORT_FILE
else
    for rec in "${recommendations[@]}"; do
        echo "        $rec" >> $REPORT_FILE
    done
fi

cat << 'EOF' >> $REPORT_FILE
    </ul>

    <hr>
    <p><small>This is an automated compliance report. Please review all findings and take appropriate action.</small></p>
</body>
</html>
EOF

echo "✓ 报告已生成: $REPORT_FILE"

# 发送邮件(可选)
# mail -s "WireGuard Compliance Report" -a $REPORT_FILE [email protected] < /dev/null

35.4.2 定期审计

月度审计脚本:

#!/bin/bash
# monthly-audit.sh

AUDIT_DIR="/var/audits/wireguard"
MONTH=$(date +%Y-%m)
AUDIT_FILE="$AUDIT_DIR/audit-$MONTH.txt"

mkdir -p $AUDIT_DIR

echo "=== WireGuard月度审计:$MONTH ===" | tee $AUDIT_FILE

# 1. 用户活动审计
{
    echo ""
    echo "========================================="
    echo "1. 用户活动审计"
    echo "========================================="
    echo ""
    
    echo "活跃用户:"
    sudo wg show wg0 latest-handshakes | \
        awk -v now=$(date +%s) '$2 > now - 2592000' | \
        wc -l
    
    echo ""
    echo "不活跃用户(30天未连接):"
    sudo wg show wg0 latest-handshakes | \
        awk -v now=$(date +%s) '$2 < now - 2592000 && $2 != 0'
    
    echo ""
    echo "从未连接:"
    sudo wg show wg0 latest-handshakes | \
        awk '$2 == 0'
} | tee -a $AUDIT_FILE

# 2. 流量统计
{
    echo ""
    echo "========================================="
    echo "2. 流量统计"
    echo "========================================="
    echo ""
    
    echo "总流量统计:"
    sudo wg show wg0 transfer | \
        awk '{rx+=$2; tx+=$3} END {
            printf "接收: %.2f GB\n", rx/1073741824;
            printf "发送: %.2f GB\n", tx/1073741824;
            printf "总计: %.2f GB\n", (rx+tx)/1073741824
        }'
} | tee -a $AUDIT_FILE

# 3. 安全事件统计
{
    echo ""
    echo "========================================="
    echo "3. 安全事件"
    echo "========================================="
    echo ""
    
    echo "配置修改次数:"
    sudo ausearch -k wireguard_config --start $(date -d 'last month' +%Y-%m-01) 2>/dev/null | \
        grep -c "type=SYSCALL" || echo "0"
    
    echo ""
    echo "认证失败次数:"
    sudo journalctl -u wg-quick@wg0 --since "$(date -d 'last month' +%Y-%m-01)" | \
        grep -ic "failed\|invalid" || echo "0"
    
    echo ""
    echo "密钥访问次数:"
    sudo ausearch -k wireguard_key_access --start $(date -d 'last month' +%Y-%m-01) 2>/dev/null | \
        grep -c "type=PATH" || echo "0"
} | tee -a $AUDIT_FILE

# 4. 系统健康
{
    echo ""
    echo "========================================="
    echo "4. 系统健康"
    echo "========================================="
    echo ""
    
    echo "服务运行时间:"
    systemctl show wg-quick@wg0 --property=ActiveEnterTimestamp
    
    echo ""
    echo "系统负载:"
    uptime
    
    echo ""
    echo "磁盘使用:"
    df -h / | tail -1
    
    echo ""
    echo "内存使用:"
    free -h | grep Mem
} | tee -a $AUDIT_FILE

# 5. 合规性检查
{
    echo ""
    echo "========================================="
    echo "5. 合规性状态"
    echo "========================================="
    echo ""
    
    # 密钥权限
    echo "密钥文件权限检查:"
    find /etc/wireguard -name "*.key" -exec ls -l {} \; | \
        awk '{print $1, $9}'
    
    echo ""
    echo "配置文件完整性:"
    sha256sum /etc/wireguard/wg0.conf
    
    echo ""
    echo "审计系统状态:"
    systemctl is-active auditd
    
    echo ""
    echo "fail2ban状态:"
    systemctl is-active fail2ban
} | tee -a $AUDIT_FILE

# 6. 建议
{
    echo ""
    echo "========================================="
    echo "6. 审计建议"
    echo "========================================="
    echo ""
    
    # 检查需要密钥轮换的用户
    echo "密钥年龄检查:"
    for keyfile in /etc/wireguard/clients/*_private.key; do
        if [ -f "$keyfile" ]; then
            age=$((($(date +%s) - $(stat -c %Y "$keyfile")) / 86400))
            if [ $age -gt 180 ]; then
                echo "  $(basename $keyfile): $age 天(建议轮换)"
            fi
        fi
    done
    
    echo ""
    echo "不活跃用户清理建议:"
    # 列出60天未活跃用户
    sudo wg show wg0 latest-handshake | \
        awk -v now=$(date +%s) '$2 < now - 5184000 && $2 != 0 {print "  " $1}'
} | tee -a $AUDIT_FILE

# 生成摘要
{
    echo ""
    echo "========================================="
    echo "审计完成"
    echo "========================================="
    echo "审计日期: $(date)"
    echo "报告文件: $AUDIT_FILE"
} | tee -a $AUDIT_FILE

echo ""
echo "✓ 月度审计完成"
echo "报告保存在: $AUDIT_FILE"

定时执行:

# 每月1号生成审计报告
0 2 1 * * /usr/local/bin/monthly-audit.sh

XBR

© 2026 XBR

bilibili bluesky discord