Files
kca/ocsp-responder/src/config.rs
T

125 lines
3.0 KiB
Rust

//! OCSP responder configuration.
use std::net::SocketAddr;
use std::path::PathBuf;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
#[serde(default = "default_listen")]
pub listen: SocketAddr,
#[serde(default)]
pub s3: S3Config,
#[serde(default)]
pub issuers: Vec<IssuerConfig>,
#[serde(default = "default_ocsp_next_update_seconds")]
pub next_update_seconds: u64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct IssuerConfig {
pub name: String,
pub ca_id: String,
pub ca_cert: PathBuf,
pub signer_cert: PathBuf,
pub signer_key: PathBuf,
}
#[derive(Debug, Clone, Deserialize)]
pub struct S3Config {
pub bucket: String,
#[serde(default = "default_prefix")]
pub prefix: String,
pub region: Option<String>,
pub endpoint: Option<String>,
#[serde(default)]
pub force_path_style: bool,
#[serde(default = "default_cache_ttl_ms")]
pub cache_ttl_ms: u64,
#[serde(default = "default_stale_grace_seconds")]
pub stale_grace_seconds: u64,
}
impl Default for S3Config {
fn default() -> Self {
Self {
bucket: String::new(),
prefix: default_prefix(),
region: None,
endpoint: None,
force_path_style: false,
cache_ttl_ms: default_cache_ttl_ms(),
stale_grace_seconds: default_stale_grace_seconds(),
}
}
}
impl S3Config {
pub fn object_key(&self, ca_id: &str) -> String {
let prefix = self.prefix.trim_matches('/');
let name = format!("{}.json", ca_id.to_lowercase());
if prefix.is_empty() {
name
} else {
format!("{prefix}/{name}")
}
}
}
fn default_listen() -> SocketAddr {
"0.0.0.0:2560"
.parse()
.expect("valid default listen address")
}
fn default_prefix() -> String {
"ocsp".to_string()
}
fn default_cache_ttl_ms() -> u64 {
1000
}
fn default_stale_grace_seconds() -> u64 {
60
}
fn default_ocsp_next_update_seconds() -> u64 {
10
}
pub fn load_config() -> Result<Config, Box<dyn std::error::Error + Send + Sync>> {
let path =
std::env::var("OCSP_CONFIG").unwrap_or_else(|_| "/etc/ocsp/responder.yaml".to_string());
let text = std::fs::read_to_string(&path)?;
let mut config: Config = serde_yaml::from_str(&text)?;
if config.issuers.is_empty() {
return Err("configuration must contain at least one issuer".into());
}
if config.s3.bucket.trim().is_empty() {
return Err("s3.bucket must be configured".into());
}
if let Ok(listen) = std::env::var("OCSP_LISTEN") {
config.listen = listen.parse()?;
}
Ok(config)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn object_key_uses_ca_id() {
let config = S3Config {
prefix: "ocsp".to_string(),
..Default::default()
};
assert_eq!(
config.object_key("123E4567-E89B-12D3-A456-426614174000"),
"ocsp/123e4567-e89b-12d3-a456-426614174000.json"
);
}
}