187 lines
5.3 KiB
Python
187 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
SSL证书生成脚本
|
||
用于生成自签名证书(开发和测试)或为Let's Encrypt准备
|
||
"""
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
from pathlib import Path
|
||
|
||
|
||
def check_openssl():
|
||
"""检查OpenSSL是否已安装"""
|
||
try:
|
||
result = subprocess.run(['openssl', 'version'], capture_output=True, text=True)
|
||
print(f"✅ OpenSSL 已安装: {result.stdout.strip()}")
|
||
return True
|
||
except FileNotFoundError:
|
||
print("❌ OpenSSL 未安装")
|
||
print("\n请安装 OpenSSL:")
|
||
print(" Ubuntu/Debian: sudo apt-get install openssl")
|
||
print(" CentOS/RHEL: sudo yum install openssl")
|
||
print(" macOS: brew install openssl")
|
||
return False
|
||
|
||
|
||
def generate_self_signed_cert(domain="localhost", days=365):
|
||
"""生成自签名SSL证书"""
|
||
print(f"\n🔒 生成自签名SSL证书...")
|
||
print(f" 域名: {domain}")
|
||
print(f" 有效期: {days} 天")
|
||
|
||
# 创建证书目录
|
||
cert_dir = Path('certs')
|
||
cert_dir.mkdir(exist_ok=True)
|
||
|
||
# 证书文件路径
|
||
key_file = cert_dir / f"{domain}.key"
|
||
cert_file = cert_dir / f"{domain}.crt"
|
||
csr_file = cert_dir / f"{domain}.csr"
|
||
|
||
# 生成私钥
|
||
print("\n1. 生成私钥...")
|
||
cmd_key = [
|
||
'openssl', 'genrsa',
|
||
'-out', str(key_file),
|
||
'2048'
|
||
]
|
||
try:
|
||
subprocess.run(cmd_key, check=True, capture_output=True)
|
||
print(f" ✅ 私钥已生成: {key_file}")
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" ❌ 生成私钥失败: {e.stderr.decode()}")
|
||
return False
|
||
|
||
# 生成证书签名请求
|
||
print("\n2. 生成证书签名请求...")
|
||
cmd_csr = [
|
||
'openssl', 'req',
|
||
'-new',
|
||
'-key', str(key_file),
|
||
'-out', str(csr_file),
|
||
'-subj', f'/C=CN/ST=Beijing/L=Beijing/O=KaMiXiTong/CN={domain}'
|
||
]
|
||
try:
|
||
subprocess.run(cmd_csr, check=True, capture_output=True)
|
||
print(f" ✅ 证书签名请求已生成: {csr_file}")
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" ❌ 生成证书签名请求失败: {e.stderr.decode()}")
|
||
return False
|
||
|
||
# 生成自签名证书
|
||
print("\n3. 生成自签名证书...")
|
||
cmd_cert = [
|
||
'openssl', 'x509',
|
||
'-req',
|
||
'-in', str(csr_file),
|
||
'-signkey', str(key_file),
|
||
'-out', str(cert_file),
|
||
'-days', str(days)
|
||
]
|
||
try:
|
||
subprocess.run(cmd_cert, check=True, capture_output=True)
|
||
print(f" ✅ 自签名证书已生成: {cert_file}")
|
||
except subprocess.CalledProcessError as e:
|
||
print(f" ❌ 生成自签名证书失败: {e.stderr.decode()}")
|
||
return False
|
||
|
||
# 清理临时文件
|
||
csr_file.unlink()
|
||
|
||
# 设置文件权限
|
||
key_file.chmod(0o600)
|
||
cert_file.chmod(0o644)
|
||
|
||
print("\n✅ SSL证书生成完成!")
|
||
print(f"\n📁 文件位置:")
|
||
print(f" 私钥: {key_file.absolute()}")
|
||
print(f" 证书: {cert_file.absolute()}")
|
||
print(f"\n⚠️ 安全提醒:")
|
||
print(f" - 私钥文件权限已设置为600(仅所有者可读写)")
|
||
print(f" - 自签名证书仅用于开发和测试")
|
||
print(f" - 生产环境请使用 Let's Encrypt 或其他CA签发的证书")
|
||
|
||
return True
|
||
|
||
|
||
def generate_certbot_config(domain, email):
|
||
"""生成 Certbot 配置"""
|
||
print(f"\n🔒 生成 Certbot 配置...")
|
||
|
||
cert_dir = Path('certs')
|
||
cert_dir.mkdir(exist_ok=True)
|
||
|
||
config_content = f"""# Certbot 配置文件
|
||
|
||
# 申请 Let's Encrypt 证书
|
||
certbot certonly \\
|
||
--webroot \\
|
||
-w /var/www/html \\
|
||
-d {domain} \\
|
||
--email {email} \\
|
||
--agree-tos \\
|
||
--non-interactive \\
|
||
--keep-until-expiring
|
||
|
||
# 证书自动续期(添加到 crontab)
|
||
0 12 * * * /usr/bin/certbot renew --quiet
|
||
"""
|
||
|
||
config_file = cert_dir / 'certbot.conf'
|
||
with open(config_file, 'w') as f:
|
||
f.write(config_content)
|
||
|
||
print(f"✅ Certbot 配置已生成: {config_file}")
|
||
print(f"\n📋 使用说明:")
|
||
print(f" 1. 安装 Certbot: sudo apt-get install certbot python3-certbot-nginx")
|
||
print(f" 2. 运行配置: sudo bash certbot.conf")
|
||
print(f" 3. 证书自动续期: 每天12点检查")
|
||
print(f" 4. 手动续期: sudo certbot renew")
|
||
|
||
|
||
def main():
|
||
"""主函数"""
|
||
print("=" * 60)
|
||
print("🔒 SSL证书生成工具")
|
||
print("=" * 60)
|
||
|
||
# 检查OpenSSL
|
||
if not check_openssl():
|
||
sys.exit(1)
|
||
|
||
# 获取用户输入
|
||
print("\n请选择证书类型:")
|
||
print("1. 自签名证书(开发和测试)")
|
||
print("2. Let's Encrypt 配置(生产环境推荐)")
|
||
choice = input("\n请选择 (1/2): ").strip()
|
||
|
||
if choice == '1':
|
||
domain = input("\n请输入域名或IP地址 (默认: localhost): ").strip() or 'localhost'
|
||
days = input("请输入有效期天数 (默认: 365): ").strip()
|
||
days = int(days) if days.isdigit() else 365
|
||
|
||
generate_self_signed_cert(domain, days)
|
||
|
||
elif choice == '2':
|
||
domain = input("\n请输入域名: ").strip()
|
||
email = input("请输入邮箱地址: ").strip()
|
||
|
||
if not domain or not email:
|
||
print("❌ 域名和邮箱不能为空")
|
||
sys.exit(1)
|
||
|
||
generate_certbot_config(domain, email)
|
||
|
||
else:
|
||
print("❌ 无效选择")
|
||
sys.exit(1)
|
||
|
||
print("\n" + "=" * 60)
|
||
print("✅ 完成!")
|
||
print("=" * 60)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|