本章概述
本章将深入介绍OpenVPN的PKI(公钥基础设施)体系、证书管理、基础配置文件编写和安全参数设置,为构建安全可靠的VPN连接奠定基础。
graph TD
A[基础配置与证书管理] --> B[PKI体系概述]
A --> C[CA根证书管理]
A --> D[服务端证书配置]
A --> E[客户端证书管理]
A --> F[配置文件编写]
A --> G[安全参数设置]
B --> B1[PKI原理]
B --> B2[证书链结构]
B --> B3[密钥管理]
C --> C1[CA证书创建]
C --> C2[CA密钥保护]
C --> C3[证书撤销列表]
D --> D1[服务端证书生成]
D --> D2[DH参数生成]
D --> D3[TLS认证密钥]
E --> E1[客户端证书生成]
E --> E2[证书分发]
E --> E3[证书更新]
F --> F1[服务端配置]
F --> F2[客户端配置]
F --> F3[配置验证]
G --> G1[加密算法选择]
G --> G2[认证方式配置]
G --> G3[安全策略设置]
3.1 PKI体系概述
3.1.1 PKI基本概念
# PKI体系结构说明
class PKIStructure:
"""
PKI(Public Key Infrastructure)公钥基础设施
"""
def __init__(self):
self.components = {
'ca': 'Certificate Authority - 证书颁发机构',
'certificate': 'Digital Certificate - 数字证书',
'private_key': 'Private Key - 私钥',
'public_key': 'Public Key - 公钥',
'crl': 'Certificate Revocation List - 证书撤销列表',
'csr': 'Certificate Signing Request - 证书签名请求'
}
def explain_certificate_chain(self):
"""
证书链结构说明
"""
chain_structure = {
'root_ca': {
'description': '根CA证书',
'purpose': '签发中间CA或直接签发终端证书',
'security_level': '最高',
'storage': '离线存储,高度保护'
},
'intermediate_ca': {
'description': '中间CA证书',
'purpose': '签发终端用户证书',
'security_level': '高',
'storage': '在线存储,适度保护'
},
'end_entity': {
'description': '终端实体证书',
'purpose': '服务端或客户端身份认证',
'security_level': '中等',
'storage': '设备本地存储'
}
}
return chain_structure
def certificate_lifecycle(self):
"""
证书生命周期管理
"""
lifecycle = {
'generation': '证书生成',
'distribution': '证书分发',
'validation': '证书验证',
'renewal': '证书更新',
'revocation': '证书撤销',
'archival': '证书归档'
}
return lifecycle
3.1.2 OpenVPN中的PKI应用
# OpenVPN PKI配置结构
openvpn_pki:
ca_certificate:
file: "ca.crt"
purpose: "验证所有证书的根信任锚点"
validity: "10年"
server_certificate:
file: "server.crt"
key_file: "server.key"
purpose: "服务端身份认证和加密"
validity: "1年"
client_certificates:
files: ["client1.crt", "client2.crt"]
key_files: ["client1.key", "client2.key"]
purpose: "客户端身份认证"
validity: "1年"
dh_parameters:
file: "dh2048.pem"
purpose: "Diffie-Hellman密钥交换"
key_size: 2048
tls_auth:
file: "ta.key"
purpose: "TLS握手认证,防止DoS攻击"
crl:
file: "crl.pem"
purpose: "证书撤销列表"
update_frequency: "定期更新"
3.2 CA根证书管理
3.2.1 初始化PKI环境
#!/bin/bash
# PKI环境初始化脚本
# 设置工作目录
PKI_DIR="/etc/openvpn/easy-rsa"
cd $PKI_DIR
# 清理旧的PKI环境(如果存在)
if [ -d "pki" ]; then
echo "警告: PKI目录已存在,是否要重新初始化?(y/N)"
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
rm -rf pki
echo "已清理旧的PKI环境"
else
echo "保留现有PKI环境"
exit 0
fi
fi
# 配置Easy-RSA变量
cat > vars << 'EOF'
# Easy-RSA 3.x 变量配置文件
# 证书信息
set_var EASYRSA_REQ_COUNTRY "CN"
set_var EASYRSA_REQ_PROVINCE "Beijing"
set_var EASYRSA_REQ_CITY "Beijing"
set_var EASYRSA_REQ_ORG "MyCompany Ltd"
set_var EASYRSA_REQ_EMAIL "admin@mycompany.com"
set_var EASYRSA_REQ_OU "IT Department"
# 密钥和证书配置
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 3650 # CA证书有效期10年
set_var EASYRSA_CERT_EXPIRE 365 # 普通证书有效期1年
set_var EASYRSA_CRL_DAYS 30 # CRL更新周期30天
# 安全配置
set_var EASYRSA_DIGEST "sha256"
set_var EASYRSA_BATCH "1" # 批处理模式
EOF
# 初始化PKI
echo "初始化PKI环境..."
./easyrsa init-pki
echo "PKI环境初始化完成"
echo "配置文件: $PKI_DIR/vars"
echo "PKI目录: $PKI_DIR/pki"
3.2.2 创建CA根证书
#!/bin/bash
# 创建CA根证书
PKI_DIR="/etc/openvpn/easy-rsa"
cd $PKI_DIR
# 加载配置变量
source ./vars
# 创建CA根证书和私钥
echo "创建CA根证书..."
echo "请输入CA证书的通用名称(CN),建议使用: MyCompany-CA"
./easyrsa build-ca
# 验证CA证书
echo "\n=== CA证书信息 ==="
openssl x509 -in pki/ca.crt -text -noout | grep -A 5 "Subject:"
openssl x509 -in pki/ca.crt -text -noout | grep -A 2 "Validity"
# 设置CA私钥权限
chmod 600 pki/private/ca.key
echo "CA私钥权限已设置为600"
# 备份CA证书和私钥
echo "\n创建CA证书备份..."
mkdir -p /root/ca-backup
cp pki/ca.crt /root/ca-backup/
cp pki/private/ca.key /root/ca-backup/
echo "CA证书已备份到 /root/ca-backup/"
echo "\nCA根证书创建完成!"
echo "CA证书位置: $PKI_DIR/pki/ca.crt"
echo "CA私钥位置: $PKI_DIR/pki/private/ca.key"
echo "\n重要提醒: 请妥善保管CA私钥,建议离线存储!"
3.2.3 CA证书安全管理
#!/usr/bin/env python3
# CA证书安全管理工具
import os
import shutil
import hashlib
import datetime
from pathlib import Path
class CASecurityManager:
def __init__(self, pki_dir="/etc/openvpn/easy-rsa/pki"):
self.pki_dir = Path(pki_dir)
self.backup_dir = Path("/root/ca-backup")
self.ca_cert = self.pki_dir / "ca.crt"
self.ca_key = self.pki_dir / "private" / "ca.key"
def verify_ca_integrity(self):
"""
验证CA证书完整性
"""
if not self.ca_cert.exists():
return False, "CA证书文件不存在"
if not self.ca_key.exists():
return False, "CA私钥文件不存在"
# 验证证书和私钥匹配
try:
import subprocess
# 获取证书公钥指纹
cert_cmd = f"openssl x509 -in {self.ca_cert} -pubkey -noout | openssl rsa -pubin -outform DER | openssl dgst -sha256"
cert_result = subprocess.run(cert_cmd, shell=True, capture_output=True, text=True)
# 获取私钥公钥指纹
key_cmd = f"openssl rsa -in {self.ca_key} -pubout -outform DER | openssl dgst -sha256"
key_result = subprocess.run(key_cmd, shell=True, capture_output=True, text=True)
if cert_result.stdout == key_result.stdout:
return True, "CA证书和私钥匹配"
else:
return False, "CA证书和私钥不匹配"
except Exception as e:
return False, f"验证过程出错: {e}"
def backup_ca_files(self):
"""
备份CA文件
"""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_subdir = self.backup_dir / f"backup_{timestamp}"
backup_subdir.mkdir(parents=True, exist_ok=True)
# 备份CA证书
if self.ca_cert.exists():
shutil.copy2(self.ca_cert, backup_subdir / "ca.crt")
# 备份CA私钥
if self.ca_key.exists():
shutil.copy2(self.ca_key, backup_subdir / "ca.key")
# 设置严格权限
os.chmod(backup_subdir / "ca.key", 0o600)
# 创建校验和文件
self._create_checksums(backup_subdir)
return backup_subdir
def _create_checksums(self, backup_dir):
"""
创建文件校验和
"""
checksum_file = backup_dir / "checksums.txt"
with open(checksum_file, 'w') as f:
for file_path in backup_dir.glob("*.crt"):
checksum = self._calculate_sha256(file_path)
f.write(f"{checksum} {file_path.name}\n")
for file_path in backup_dir.glob("*.key"):
checksum = self._calculate_sha256(file_path)
f.write(f"{checksum} {file_path.name}\n")
def _calculate_sha256(self, file_path):
"""
计算文件SHA256校验和
"""
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
sha256_hash.update(chunk)
return sha256_hash.hexdigest()
def secure_ca_key(self):
"""
加强CA私钥安全
"""
if self.ca_key.exists():
# 设置严格权限
os.chmod(self.ca_key, 0o600)
# 设置文件属性(仅限Linux)
try:
import subprocess
subprocess.run(["chattr", "+i", str(self.ca_key)], check=True)
return True, "CA私钥已设置为不可修改"
except (subprocess.CalledProcessError, FileNotFoundError):
return False, "无法设置文件不可修改属性"
return False, "CA私钥文件不存在"
def generate_security_report(self):
"""
生成安全报告
"""
report = {
'timestamp': datetime.datetime.now().isoformat(),
'ca_cert_exists': self.ca_cert.exists(),
'ca_key_exists': self.ca_key.exists(),
'ca_cert_permissions': oct(os.stat(self.ca_cert).st_mode)[-3:] if self.ca_cert.exists() else None,
'ca_key_permissions': oct(os.stat(self.ca_key).st_mode)[-3:] if self.ca_key.exists() else None,
}
# 验证完整性
integrity_ok, integrity_msg = self.verify_ca_integrity()
report['integrity_check'] = {
'status': integrity_ok,
'message': integrity_msg
}
return report
if __name__ == "__main__":
manager = CASecurityManager()
# 验证CA完整性
integrity_ok, msg = manager.verify_ca_integrity()
print(f"CA完整性检查: {msg}")
# 备份CA文件
if integrity_ok:
backup_dir = manager.backup_ca_files()
print(f"CA文件已备份到: {backup_dir}")
# 生成安全报告
report = manager.generate_security_report()
print("\n=== CA安全报告 ===")
for key, value in report.items():
print(f"{key}: {value}")
3.3 服务端证书配置
3.3.1 生成服务端证书
#!/bin/bash
# 生成OpenVPN服务端证书
PKI_DIR="/etc/openvpn/easy-rsa"
SERVER_NAME="openvpn-server"
cd $PKI_DIR
# 加载配置变量
source ./vars
echo "=== 生成OpenVPN服务端证书 ==="
# 1. 生成服务端证书请求和私钥
echo "1. 生成服务端证书请求..."
./easyrsa gen-req $SERVER_NAME nopass
# 2. 签发服务端证书
echo "2. 签发服务端证书..."
./easyrsa sign-req server $SERVER_NAME
# 3. 生成Diffie-Hellman参数
echo "3. 生成DH参数(这可能需要几分钟)..."
./easyrsa gen-dh
# 4. 生成TLS认证密钥
echo "4. 生成TLS认证密钥..."
openvpn --genkey --secret pki/ta.key
# 5. 复制证书到OpenVPN目录
echo "5. 复制证书文件..."
mkdir -p /etc/openvpn/server
cp pki/ca.crt /etc/openvpn/server/
cp pki/issued/$SERVER_NAME.crt /etc/openvpn/server/
cp pki/private/$SERVER_NAME.key /etc/openvpn/server/
cp pki/dh.pem /etc/openvpn/server/
cp pki/ta.key /etc/openvpn/server/
# 6. 设置文件权限
echo "6. 设置文件权限..."
chmod 644 /etc/openvpn/server/ca.crt
chmod 644 /etc/openvpn/server/$SERVER_NAME.crt
chmod 600 /etc/openvpn/server/$SERVER_NAME.key
chmod 644 /etc/openvpn/server/dh.pem
chmod 600 /etc/openvpn/server/ta.key
# 7. 验证证书
echo "\n=== 服务端证书验证 ==="
echo "证书主题信息:"
openssl x509 -in /etc/openvpn/server/$SERVER_NAME.crt -subject -noout
echo "\n证书有效期:"
openssl x509 -in /etc/openvpn/server/$SERVER_NAME.crt -dates -noout
echo "\n证书指纹:"
openssl x509 -in /etc/openvpn/server/$SERVER_NAME.crt -fingerprint -noout
echo "\n=== 服务端证书生成完成 ==="
echo "证书文件位置:"
echo " CA证书: /etc/openvpn/server/ca.crt"
echo " 服务端证书: /etc/openvpn/server/$SERVER_NAME.crt"
echo " 服务端私钥: /etc/openvpn/server/$SERVER_NAME.key"
echo " DH参数: /etc/openvpn/server/dh.pem"
echo " TLS认证密钥: /etc/openvpn/server/ta.key"
3.3.2 服务端配置文件
#!/bin/bash
# 创建OpenVPN服务端配置文件
SERVER_CONFIG="/etc/openvpn/server/server.conf"
SERVER_NAME="openvpn-server"
cat > $SERVER_CONFIG << EOF
# OpenVPN服务端配置文件
# 生成时间: $(date)
#################################################
# 基本配置
#################################################
# 监听端口和协议
port 1194
proto udp
# 设备类型(tun为路由模式,tap为桥接模式)
dev tun
# 证书和密钥文件
ca ca.crt
cert $SERVER_NAME.crt
key $SERVER_NAME.key
dh dh.pem
# TLS认证(防止DoS攻击)
tls-auth ta.key 0
#################################################
# 网络配置
#################################################
# VPN子网配置(服务端IP池)
server 10.8.0.0 255.255.255.0
# 维持客户端和虚拟IP地址之间的关联
ifconfig-pool-persist /var/log/openvpn/ipp.txt
# 推送路由到客户端
# 推送默认网关,使所有流量通过VPN
push "redirect-gateway def1 bypass-dhcp"
# 推送DNS服务器
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
# 允许客户端之间通信
client-to-client
#################################################
# 安全配置
#################################################
# 加密算法
cipher AES-256-GCM
auth SHA256
# 密钥协商算法
tls-version-min 1.2
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
# 完美前向保密
tls-crypt ta.key
# 用户权限降级
user nobody
group nogroup
# 持久化选项
persist-key
persist-tun
#################################################
# 日志配置
#################################################
# 日志级别(0-9,9为最详细)
verb 3
# 静默重复消息
mute 20
# 状态日志文件
status /var/log/openvpn/openvpn-status.log
# 日志文件
log-append /var/log/openvpn/openvpn.log
#################################################
# 性能优化
#################################################
# 启用压缩
comp-lzo
# 最大客户端连接数
max-clients 100
# 客户端超时设置
keepalive 10 120
# 快速TLS模式
fast-io
#################################################
# 管理接口(可选)
#################################################
# 管理接口(用于监控和管理)
# management localhost 7505
EOF
echo "服务端配置文件已创建: $SERVER_CONFIG"
# 创建日志目录
mkdir -p /var/log/openvpn
chown openvpn:openvpn /var/log/openvpn 2>/dev/null || true
# 验证配置文件语法
echo "\n验证配置文件语法..."
openvpn --config $SERVER_CONFIG --test-crypto
if [ $? -eq 0 ]; then
echo "✓ 配置文件语法正确"
else
echo "✗ 配置文件语法错误,请检查"
fi
3.3.3 高级服务端配置
#!/bin/bash
# 高级服务端配置模板
cat > /etc/openvpn/server/server-advanced.conf << 'EOF'
# OpenVPN高级服务端配置
# 适用于生产环境
#################################################
# 网络接口配置
#################################################
# 多端口监听
port 1194
port 443
proto udp
# 多协议支持
proto-force udp
# 设备配置
dev tun0
dev-type tun
# 拓扑模式
topology subnet
#################################################
# 证书和加密配置
#################################################
# 证书文件
ca ca.crt
cert openvpn-server.crt
key openvpn-server.key
dh dh.pem
# 高级TLS配置
tls-auth ta.key 0
tls-version-min 1.2
tls-version-max 1.3
# 强加密套件
cipher AES-256-GCM
auth SHA512
ncp-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC
# ECDH曲线
ecdh-curve secp384r1
#################################################
# 网络和路由配置
#################################################
# 服务端网络
server 10.8.0.0 255.255.255.0
# 客户端配置目录
client-config-dir /etc/openvpn/ccd
# 路由推送
push "route 192.168.1.0 255.255.255.0"
push "route 192.168.2.0 255.255.255.0"
# DNS推送
push "dhcp-option DNS 192.168.1.1"
push "dhcp-option DNS 8.8.8.8"
# 域名推送
push "dhcp-option DOMAIN company.local"
#################################################
# 安全策略
#################################################
# 客户端证书验证
verify-client-cert require
# 证书撤销列表
crl-verify /etc/openvpn/server/crl.pem
# 远程证书类型验证
remote-cert-tls client
# 用户名密码验证(可选)
# auth-user-pass-verify /etc/openvpn/scripts/auth.sh via-env
# 客户端连接脚本
client-connect /etc/openvpn/scripts/client-connect.sh
client-disconnect /etc/openvpn/scripts/client-disconnect.sh
#################################################
# 性能和稳定性
#################################################
# 连接保持
keepalive 10 60
# 重连设置
ping-timer-rem
# 压缩
comp-lzo adaptive
# 并发连接
max-clients 500
# 连接速率限制
connect-freq 1 10
# 内存优化
mlock
#################################################
# 日志和监控
#################################################
# 详细日志
verb 4
mute 10
# 状态文件
status /var/log/openvpn/status.log 30
# 日志文件
log /var/log/openvpn/server.log
# 管理接口
management 127.0.0.1 7505 /etc/openvpn/server/mgmt-password
#################################################
# 系统集成
#################################################
# 权限降级
user openvpn
group openvpn
# 持久化
persist-key
persist-tun
persist-local-ip
persist-remote-ip
# 脚本安全
script-security 2
EOF
echo "高级服务端配置文件已创建"
3.4 客户端证书管理
3.4.1 生成客户端证书
#!/bin/bash
# 客户端证书生成脚本
PKI_DIR="/etc/openvpn/easy-rsa"
CLIENT_DIR="/etc/openvpn/clients"
# 函数:生成单个客户端证书
generate_client_cert() {
local client_name=$1
if [ -z "$client_name" ]; then
echo "错误: 请提供客户端名称"
echo "用法: $0 <客户端名称>"
exit 1
fi
cd $PKI_DIR
source ./vars
echo "=== 生成客户端证书: $client_name ==="
# 检查客户端是否已存在
if [ -f "pki/issued/$client_name.crt" ]; then
echo "警告: 客户端 $client_name 的证书已存在"
echo "是否要重新生成?(y/N)"
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
echo "操作取消"
exit 0
fi
# 撤销现有证书
./easyrsa revoke $client_name
./easyrsa gen-crl
fi
# 生成客户端证书请求和私钥
echo "1. 生成客户端证书请求..."
./easyrsa gen-req $client_name nopass
# 签发客户端证书
echo "2. 签发客户端证书..."
./easyrsa sign-req client $client_name
# 创建客户端目录
mkdir -p $CLIENT_DIR/$client_name
# 复制证书文件
echo "3. 复制证书文件..."
cp pki/ca.crt $CLIENT_DIR/$client_name/
cp pki/issued/$client_name.crt $CLIENT_DIR/$client_name/
cp pki/private/$client_name.key $CLIENT_DIR/$client_name/
cp pki/ta.key $CLIENT_DIR/$client_name/
# 设置权限
chmod 644 $CLIENT_DIR/$client_name/ca.crt
chmod 644 $CLIENT_DIR/$client_name/$client_name.crt
chmod 600 $CLIENT_DIR/$client_name/$client_name.key
chmod 600 $CLIENT_DIR/$client_name/ta.key
echo "\n=== 客户端证书生成完成 ==="
echo "证书目录: $CLIENT_DIR/$client_name"
# 验证证书
echo "\n证书验证:"
openssl x509 -in $CLIENT_DIR/$client_name/$client_name.crt -subject -noout
openssl x509 -in $CLIENT_DIR/$client_name/$client_name.crt -dates -noout
}
# 函数:批量生成客户端证书
batch_generate_clients() {
local client_list_file=$1
if [ ! -f "$client_list_file" ]; then
echo "错误: 客户端列表文件不存在: $client_list_file"
exit 1
fi
echo "=== 批量生成客户端证书 ==="
while IFS= read -r client_name; do
# 跳过空行和注释行
if [[ -z "$client_name" || "$client_name" =~ ^#.* ]]; then
continue
fi
echo "\n处理客户端: $client_name"
generate_client_cert "$client_name"
echo "等待2秒后处理下一个客户端..."
sleep 2
done < "$client_list_file"
echo "\n=== 批量生成完成 ==="
}
# 主程序
if [ "$1" = "--batch" ]; then
batch_generate_clients "$2"
else
generate_client_cert "$1"
fi
3.4.2 客户端配置文件生成
#!/usr/bin/env python3
# 客户端配置文件生成工具
import os
import sys
import argparse
from pathlib import Path
import ipaddress
class OpenVPNClientConfigGenerator:
def __init__(self, server_ip, server_port=1194, protocol="udp"):
self.server_ip = server_ip
self.server_port = server_port
self.protocol = protocol
self.client_dir = Path("/etc/openvpn/clients")
def generate_config(self, client_name, config_type="separate"):
"""
生成客户端配置文件
config_type: 'separate' 或 'inline'
"""
client_path = self.client_dir / client_name
if not client_path.exists():
raise FileNotFoundError(f"客户端目录不存在: {client_path}")
if config_type == "inline":
return self._generate_inline_config(client_name, client_path)
else:
return self._generate_separate_config(client_name, client_path)
def _generate_separate_config(self, client_name, client_path):
"""
生成分离式配置文件(证书文件分开)
"""
config_content = f"""# OpenVPN客户端配置文件
# 客户端: {client_name}
# 生成时间: {self._get_timestamp()}
##############################################
# 客户端配置
##############################################
# 指定这是客户端
client
# 使用tun设备
dev tun
# 协议类型
proto {self.protocol}
# 服务器地址和端口
remote {self.server_ip} {self.server_port}
# 保持尝试连接
resolv-retry infinite
# 不绑定本地端口
nobind
# 权限降级
user nobody
group nogroup
# 持久化选项
persist-key
persist-tun
##############################################
# 证书和密钥文件
##############################################
# CA证书
ca ca.crt
# 客户端证书
cert {client_name}.crt
# 客户端私钥
key {client_name}.key
# TLS认证密钥
tls-auth ta.key 1
##############################################
# 安全配置
##############################################
# 加密算法
cipher AES-256-GCM
auth SHA256
# 验证服务端证书
remote-cert-tls server
# TLS版本
tls-version-min 1.2
##############################################
# 连接配置
##############################################
# 压缩
comp-lzo
# 日志级别
verb 3
# 静默重复消息
mute 20
# 连接保持
keepalive 10 120
##############################################
# 路由配置
##############################################
# 忽略服务端推送的路由(如果需要)
# route-nopull
# 自定义路由(如果需要)
# route 192.168.1.0 255.255.255.0
"""
config_file = client_path / f"{client_name}.ovpn"
with open(config_file, 'w') as f:
f.write(config_content)
return config_file
def _generate_inline_config(self, client_name, client_path):
"""
生成内联式配置文件(证书内容嵌入)
"""
# 读取证书文件内容
ca_content = self._read_file_content(client_path / "ca.crt")
cert_content = self._read_file_content(client_path / f"{client_name}.crt")
key_content = self._read_file_content(client_path / f"{client_name}.key")
ta_content = self._read_file_content(client_path / "ta.key")
config_content = f"""# OpenVPN客户端内联配置文件
# 客户端: {client_name}
# 生成时间: {self._get_timestamp()}
client
dev tun
proto {self.protocol}
remote {self.server_ip} {self.server_port}
resolv-retry infinite
nobind
user nobody
group nogroup
persist-key
persist-tun
cipher AES-256-GCM
auth SHA256
remote-cert-tls server
tls-version-min 1.2
comp-lzo
verb 3
mute 20
keepalive 10 120
<ca>
{ca_content}
</ca>
<cert>
{cert_content}
</cert>
<key>
{key_content}
</key>
<tls-auth>
{ta_content}
</tls-auth>
key-direction 1
"""
config_file = client_path / f"{client_name}-inline.ovpn"
with open(config_file, 'w') as f:
f.write(config_content)
return config_file
def _read_file_content(self, file_path):
"""
读取文件内容
"""
try:
with open(file_path, 'r') as f:
return f.read().strip()
except FileNotFoundError:
raise FileNotFoundError(f"证书文件不存在: {file_path}")
def _get_timestamp(self):
"""
获取当前时间戳
"""
import datetime
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def generate_mobile_config(self, client_name):
"""
生成移动设备优化配置
"""
client_path = self.client_dir / client_name
# 读取证书内容
ca_content = self._read_file_content(client_path / "ca.crt")
cert_content = self._read_file_content(client_path / f"{client_name}.crt")
key_content = self._read_file_content(client_path / f"{client_name}.key")
ta_content = self._read_file_content(client_path / "ta.key")
config_content = f"""# OpenVPN移动设备配置
# 客户端: {client_name}
# 优化移动网络连接
client
dev tun
proto udp
remote {self.server_ip} {self.server_port}
remote {self.server_ip} 443 tcp-client
resolv-retry infinite
nobind
persist-key
persist-tun
# 移动网络优化
connect-retry-max 3
connect-timeout 10
server-poll-timeout 4
# 快速重连
fast-io
sndbuf 524288
rcvbuf 524288
# 安全配置
cipher AES-256-GCM
auth SHA256
remote-cert-tls server
tls-version-min 1.2
# 压缩(移动设备建议关闭以节省CPU)
# comp-lzo
# 日志
verb 3
mute 20
# 连接保持(移动网络优化)
keepalive 10 60
ping-timer-rem
<ca>
{ca_content}
</ca>
<cert>
{cert_content}
</cert>
<key>
{key_content}
</key>
<tls-auth>
{ta_content}
</tls-auth>
key-direction 1
"""
config_file = client_path / f"{client_name}-mobile.ovpn"
with open(config_file, 'w') as f:
f.write(config_content)
return config_file
def list_clients(self):
"""
列出所有客户端
"""
if not self.client_dir.exists():
return []
clients = []
for item in self.client_dir.iterdir():
if item.is_dir():
clients.append(item.name)
return sorted(clients)
def main():
parser = argparse.ArgumentParser(description='OpenVPN客户端配置生成工具')
parser.add_argument('--server', required=True, help='服务器IP地址')
parser.add_argument('--port', type=int, default=1194, help='服务器端口')
parser.add_argument('--protocol', choices=['udp', 'tcp'], default='udp', help='协议类型')
parser.add_argument('--client', help='客户端名称')
parser.add_argument('--type', choices=['separate', 'inline', 'mobile'], default='separate', help='配置类型')
parser.add_argument('--list', action='store_true', help='列出所有客户端')
args = parser.parse_args()
generator = OpenVPNClientConfigGenerator(args.server, args.port, args.protocol)
if args.list:
clients = generator.list_clients()
print("可用的客户端:")
for client in clients:
print(f" - {client}")
return
if not args.client:
print("错误: 请指定客户端名称")
sys.exit(1)
try:
if args.type == 'mobile':
config_file = generator.generate_mobile_config(args.client)
else:
config_file = generator.generate_config(args.client, args.type)
print(f"配置文件已生成: {config_file}")
except Exception as e:
print(f"错误: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
3.4.3 证书撤销管理
#!/bin/bash
# 证书撤销管理脚本
PKI_DIR="/etc/openvpn/easy-rsa"
CLIENT_DIR="/etc/openvpn/clients"
SERVER_DIR="/etc/openvpn/server"
# 函数:撤销客户端证书
revoke_client_cert() {
local client_name=$1
if [ -z "$client_name" ]; then
echo "错误: 请提供客户端名称"
echo "用法: revoke_client_cert <客户端名称>"
return 1
fi
cd $PKI_DIR
# 检查证书是否存在
if [ ! -f "pki/issued/$client_name.crt" ]; then
echo "错误: 客户端 $client_name 的证书不存在"
return 1
fi
echo "=== 撤销客户端证书: $client_name ==="
# 确认操作
echo "警告: 此操作将撤销客户端 $client_name 的证书"
echo "撤销后该客户端将无法连接到VPN服务器"
echo "是否确认撤销?(yes/no)"
read -r confirmation
if [ "$confirmation" != "yes" ]; then
echo "操作取消"
return 0
fi
# 撤销证书
echo "1. 撤销证书..."
./easyrsa revoke $client_name
if [ $? -ne 0 ]; then
echo "错误: 证书撤销失败"
return 1
fi
# 生成新的CRL
echo "2. 生成证书撤销列表..."
./easyrsa gen-crl
# 复制CRL到服务器目录
echo "3. 更新服务器CRL..."
cp pki/crl.pem $SERVER_DIR/
# 备份并移除客户端文件
echo "4. 备份客户端文件..."
if [ -d "$CLIENT_DIR/$client_name" ]; then
mkdir -p "$CLIENT_DIR/revoked"
mv "$CLIENT_DIR/$client_name" "$CLIENT_DIR/revoked/$client_name-$(date +%Y%m%d_%H%M%S)"
fi
# 重启OpenVPN服务以加载新的CRL
echo "5. 重启OpenVPN服务..."
systemctl restart openvpn@server
echo "\n=== 证书撤销完成 ==="
echo "客户端 $client_name 的证书已被撤销"
echo "CRL已更新: $SERVER_DIR/crl.pem"
echo "客户端文件已移动到: $CLIENT_DIR/revoked/"
}
# 函数:列出撤销的证书
list_revoked_certs() {
cd $PKI_DIR
echo "=== 已撤销的证书列表 ==="
if [ -f "pki/index.txt" ]; then
echo "状态 过期时间 撤销时间 序列号 主题"
echo "--------------------------------------------------------------------"
grep "^R" pki/index.txt | while IFS=$'\t' read -r status expiry revoke_time serial subject; do
echo "撤销 $expiry $revoke_time $serial $subject"
done
else
echo "未找到证书索引文件"
fi
}
# 函数:检查CRL状态
check_crl_status() {
echo "=== CRL状态检查 ==="
local crl_file="$PKI_DIR/pki/crl.pem"
if [ -f "$crl_file" ]; then
echo "CRL文件存在: $crl_file"
# 显示CRL信息
echo "\nCRL详细信息:"
openssl crl -in "$crl_file" -text -noout | head -20
# 检查CRL有效期
echo "\nCRL有效期:"
openssl crl -in "$crl_file" -nextupdate -noout
# 统计撤销证书数量
local revoked_count=$(openssl crl -in "$crl_file" -text -noout | grep -c "Serial Number:")
echo "撤销证书数量: $revoked_count"
else
echo "CRL文件不存在"
fi
# 检查服务器CRL
local server_crl="$SERVER_DIR/crl.pem"
if [ -f "$server_crl" ]; then
echo "\n服务器CRL文件存在: $server_crl"
local server_crl_date=$(stat -c %Y "$server_crl")
local pki_crl_date=$(stat -c %Y "$crl_file" 2>/dev/null || echo 0)
if [ $server_crl_date -lt $pki_crl_date ]; then
echo "警告: 服务器CRL文件过期,需要更新"
else
echo "服务器CRL文件是最新的"
fi
else
echo "\n警告: 服务器CRL文件不存在"
fi
}
# 函数:更新CRL
update_crl() {
echo "=== 更新CRL ==="
cd $PKI_DIR
# 生成新的CRL
echo "生成新的CRL..."
./easyrsa gen-crl
# 复制到服务器目录
echo "复制CRL到服务器目录..."
cp pki/crl.pem $SERVER_DIR/
# 重启服务
echo "重启OpenVPN服务..."
systemctl restart openvpn@server
echo "CRL更新完成"
}
# 主程序
case "$1" in
"revoke")
revoke_client_cert "$2"
;;
"list")
list_revoked_certs
;;
"status")
check_crl_status
;;
"update")
update_crl
;;
*)
echo "OpenVPN证书撤销管理工具"
echo "用法: $0 {revoke|list|status|update} [客户端名称]"
echo ""
echo "命令说明:"
echo " revoke <客户端名称> - 撤销指定客户端证书"
echo " list - 列出所有撤销的证书"
echo " status - 检查CRL状态"
echo " update - 更新CRL"
exit 1
;;
esac
3.5 配置文件详解
3.5.1 服务端配置参数详解
# OpenVPN服务端配置参数详解
server_config_parameters:
# 基础网络配置
network:
port:
description: "监听端口"
default: 1194
range: "1-65535"
example: "port 1194"
proto:
description: "协议类型"
options: ["udp", "tcp", "udp4", "udp6", "tcp4", "tcp6"]
default: "udp"
example: "proto udp"
dev:
description: "虚拟网络设备"
options: ["tun", "tap"]
default: "tun"
example: "dev tun0"
topology:
description: "网络拓扑"
options: ["net30", "p2p", "subnet"]
default: "net30"
example: "topology subnet"
# 证书和加密
security:
ca:
description: "CA证书文件"
required: true
example: "ca ca.crt"
cert:
description: "服务端证书文件"
required: true
example: "cert server.crt"
key:
description: "服务端私钥文件"
required: true
example: "key server.key"
dh:
description: "DH参数文件"
required: true
example: "dh dh2048.pem"
cipher:
description: "数据加密算法"
options: ["AES-256-GCM", "AES-128-GCM", "AES-256-CBC"]
default: "AES-256-GCM"
example: "cipher AES-256-GCM"
auth:
description: "HMAC认证算法"
options: ["SHA256", "SHA512", "SHA1"]
default: "SHA256"
example: "auth SHA256"
# 客户端管理
client_management:
server:
description: "VPN子网配置"
format: "network netmask"
example: "server 10.8.0.0 255.255.255.0"
max_clients:
description: "最大客户端连接数"
default: 1024
example: "max-clients 100"
client_to_client:
description: "允许客户端间通信"
default: false
example: "client-to-client"
duplicate_cn:
description: "允许重复通用名"
default: false
example: "duplicate-cn"
# 路由配置
routing:
push_route:
description: "推送路由到客户端"
format: "route network netmask [gateway]"
example: "push \"route 192.168.1.0 255.255.255.0\""
push_redirect_gateway:
description: "重定向默认网关"
options: ["def1", "bypass-dhcp", "bypass-dns"]
example: "push \"redirect-gateway def1 bypass-dhcp\""
push_dhcp_option:
description: "推送DHCP选项"
common_options: ["DNS", "DOMAIN", "NTP"]
example: "push \"dhcp-option DNS 8.8.8.8\""
# 性能优化
performance:
sndbuf:
description: "发送缓冲区大小"
unit: "bytes"
example: "sndbuf 524288"
rcvbuf:
description: "接收缓冲区大小"
unit: "bytes"
example: "rcvbuf 524288"
comp_lzo:
description: "LZO压缩"
options: ["yes", "no", "adaptive"]
example: "comp-lzo adaptive"
fast_io:
description: "快速I/O模式"
example: "fast-io"
# 日志和监控
logging:
verb:
description: "日志详细级别"
range: "0-11"
default: 3
example: "verb 4"
mute:
description: "静默重复消息数量"
default: 20
example: "mute 20"
status:
description: "状态日志文件"
example: "status /var/log/openvpn/status.log 30"
log:
description: "日志文件"
example: "log /var/log/openvpn/server.log"
3.5.2 客户端配置参数详解
# OpenVPN客户端配置参数详解
client_config_parameters:
# 基础配置
basic:
client:
description: "指定为客户端模式"
required: true
example: "client"
dev:
description: "虚拟网络设备类型"
options: ["tun", "tap"]
example: "dev tun"
proto:
description: "协议类型"
options: ["udp", "tcp-client"]
example: "proto udp"
# 服务器连接
connection:
remote:
description: "服务器地址和端口"
format: "hostname/ip [port] [proto]"
example: "remote vpn.example.com 1194"
remote_random:
description: "随机选择服务器"
example: "remote-random"
resolv_retry:
description: "DNS解析重试"
options: ["infinite", "number"]
example: "resolv-retry infinite"
nobind:
description: "不绑定本地端口"
example: "nobind"
connect_retry:
description: "连接重试间隔"
unit: "seconds"
example: "connect-retry 5"
# 安全配置
security:
ca:
description: "CA证书文件"
required: true
example: "ca ca.crt"
cert:
description: "客户端证书文件"
required: true
example: "cert client.crt"
key:
description: "客户端私钥文件"
required: true
example: "key client.key"
tls_auth:
description: "TLS认证密钥"
format: "file direction"
example: "tls-auth ta.key 1"
remote_cert_tls:
description: "验证远程证书类型"
options: ["server", "client"]
example: "remote-cert-tls server"
# 系统配置
system:
user:
description: "运行用户"
example: "user nobody"
group:
description: "运行组"
example: "group nogroup"
persist_key:
description: "持久化密钥"
example: "persist-key"
persist_tun:
description: "持久化TUN设备"
example: "persist-tun"
3.6 安全参数设置
3.6.1 加密算法配置
#!/bin/bash
# 加密算法安全配置脚本
echo "=== OpenVPN加密算法安全配置 ==="
# 推荐的安全配置
cat > /etc/openvpn/security-template.conf << 'EOF'
# OpenVPN安全配置模板
# 基于当前最佳安全实践
#################################################
# 强加密配置
#################################################
# 数据通道加密(推荐AES-256-GCM)
cipher AES-256-GCM
# 备用加密算法
ncp-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC
# HMAC认证算法
auth SHA256
# TLS版本限制
tls-version-min 1.2
tls-version-max 1.3
# TLS加密套件
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
# ECDH曲线
ecdh-curve secp384r1
# 密钥大小
tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256
#################################################
# 认证安全
#################################################
# TLS认证(防DoS)
tls-auth ta.key 0 # 服务端使用0,客户端使用1
# 或者使用tls-crypt(更安全)
# tls-crypt ta.key
# 远程证书验证
remote-cert-tls client # 服务端配置
# remote-cert-tls server # 客户端配置
# 证书撤销列表
crl-verify crl.pem
#################################################
# 连接安全
#################################################
# 重放攻击保护
replay-window 64 15
# 连接频率限制
connect-freq 1 10
# 脚本安全级别
script-security 2
EOF
echo "安全配置模板已创建: /etc/openvpn/security-template.conf"