Files
honey-biscuit-workshop/workshop-cert/src/main.rs
T
2025-11-13 23:49:16 +08:00

145 lines
4.5 KiB
Rust

use clap::{Parser, Subcommand};
use std::path::PathBuf;
use workshop_cert::{CertConfig, CertificateGenerator, Result};
#[derive(Parser)]
#[command(name = "workshop-certgen")]
#[command(about = "Generate TLS certificates for Workshop CI/CD system")]
struct Cli {
#[command(subcommand)]
command: Commands,
/// Configuration file path
#[arg(short, long, default_value = "cert.toml")]
config: PathBuf,
/// Output directory for certificates
#[arg(short, long, default_value = "./certs")]
output_dir: PathBuf,
}
#[derive(Subcommand)]
enum Commands {
/// Generate CA certificate (one-time operation)
GenCa,
/// Generate server certificate (one-time operation)
GenServer,
/// Generate client certificate(s)
GenClient {
/// Client ID(s) to generate certificates for
#[arg(required = true)]
client_ids: Vec<String>,
},
/// Generate all certificates (CA, server, and sample client)
GenAll {
/// Also generate sample client certificates
#[arg(short, long)]
with_clients: bool,
/// Number of sample client certificates to generate
#[arg(short, long, default_value = "3")]
sample_count: usize,
},
/// Show current configuration
ShowConfig,
}
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let args = Cli::parse();
// 加载配置
let config = if args.config.exists() {
CertConfig::from_file(&args.config)?
} else {
println!("⚠️ 配置文件 {} 不存在,使用默认配置", args.config.display());
CertConfig::default_config()
};
let generator = CertificateGenerator::new(config, args.output_dir.clone());
generator.ensure_output_dir()?;
match args.command {
Commands::GenCa => {
println!("🔐 生成 CA 证书...");
generator.generate_ca()?;
}
Commands::GenServer => {
println!("🔐 生成服务器证书...");
// 首先需要 CA 证书
let ca_bundle = if generator.output_dir.join("ca-cert.pem").exists() {
// 从文件加载现有的 CA 证书
let cert_pem = std::fs::read_to_string(generator.output_dir.join("ca-cert.pem"))?;
let key_pem = std::fs::read_to_string(generator.output_dir.join("ca-key.pem"))?;
workshop_cert::CertificateBundle {
certificate: cert_pem,
private_key: key_pem,
public_key: None,
}
} else {
println!("❌ 未找到 CA 证书,请先运行 'gen-ca' 命令");
return Ok(());
};
generator.generate_server_certificate(&ca_bundle)?;
}
Commands::GenClient { client_ids } => {
println!("🔐 生成客户端证书: {:?}...", client_ids);
// 需要 CA 证书
let ca_bundle = if generator.output_dir.join("ca-cert.pem").exists() {
let cert_pem = std::fs::read_to_string(generator.output_dir.join("ca-cert.pem"))?;
let key_pem = std::fs::read_to_string(generator.output_dir.join("ca-key.pem"))?;
workshop_cert::CertificateBundle {
certificate: cert_pem,
private_key: key_pem,
public_key: None,
}
} else {
println!("❌ 未找到 CA 证书,请先运行 'gen-ca' 命令");
return Ok(());
};
generator.generate_client_certificates(&ca_bundle, &client_ids)?;
}
Commands::GenAll { with_clients, sample_count } => {
println!("🔐 生成所有证书...");
// 1. 生成 CA
let ca_bundle = generator.generate_ca()?;
// 2. 生成服务器证书
generator.generate_server_certificate(&ca_bundle)?;
// 3. 可选:生成示例客户端证书
if with_clients {
let sample_clients: Vec<String> = (1..=sample_count)
.map(|i| format!("sample{}", i))
.collect();
println!("👥 生成示例客户端证书: {:?}", sample_clients);
generator.generate_client_certificates(&ca_bundle, &sample_clients)?;
}
}
Commands::ShowConfig => {
println!("📋 当前配置:");
println!("{:#?}", generator.config);
}
}
println!("✅ 操作完成!");
Ok(())
}