photoncloud-monorepo/mtls-agent/src/policy.rs
centra e1a5d394e5
Some checks failed
Nix CI / filter (push) Successful in 54s
Nix CI / gate (shared crates) (push) Has been skipped
Nix CI / gate () (push) Failing after 6s
Nix CI / build () (push) Has been skipped
Nix CI / ci-status (push) Failing after 1m14s
ci: unify workspace inventory and harden tier0 gating
2026-03-28 00:09:22 +09:00

111 lines
3.1 KiB
Rust

#![allow(dead_code)]
use std::sync::Arc;
use std::time::{Duration, Instant};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;
use tracing::info;
use crate::discovery::ServiceDiscovery;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyDecision {
pub allow: bool,
pub mode: String, // mtls/tls/plain
pub reason: String,
}
pub struct PolicyEnforcer {
discovery: Arc<ServiceDiscovery>,
default_mode: String,
cache: Arc<RwLock<std::collections::HashMap<String, (PolicyDecision, Instant)>>>,
}
impl PolicyEnforcer {
pub fn new(discovery: Arc<ServiceDiscovery>, default_mode: String) -> Self {
Self {
discovery,
default_mode,
cache: Arc::new(RwLock::new(std::collections::HashMap::new())),
}
}
pub async fn evaluate(
&self,
source_service: &str,
target_service: &str,
) -> Result<PolicyDecision> {
let cache_key = format!("{}->{}", source_service, target_service);
// キャッシュをチェック
{
let cache = self.cache.read().await;
if let Some((decision, timestamp)) = cache.get(&cache_key) {
if timestamp.elapsed() < Duration::from_secs(30) {
return Ok(decision.clone());
}
}
}
// Chainfireからポリシーを取得
let policy = self
.discovery
.get_mtls_policy(source_service, target_service)
.await?;
let decision = if let Some(p) = policy {
PolicyDecision {
allow: true,
mode: p.mode.unwrap_or_else(|| {
if p.mtls_required.unwrap_or(false) {
"mtls".to_string()
} else {
"plain".to_string()
}
}),
reason: format!("policy {} applied", p.policy_id),
}
} else {
PolicyDecision {
allow: true,
mode: self.default_mode.clone(),
reason: "default policy applied".to_string(),
}
};
// キャッシュに保存
{
let mut cache = self.cache.write().await;
cache.insert(cache_key, (decision.clone(), Instant::now()));
}
info!(
source = source_service,
target = target_service,
mode = %decision.mode,
"policy decision"
);
Ok(decision)
}
pub async fn start_background_refresh(&self) {
let cache = Arc::clone(&self.cache);
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(60));
loop {
interval.tick().await;
// キャッシュをクリア(簡易実装)
{
let mut cache_guard = cache.write().await;
cache_guard.clear();
}
info!("policy cache cleared, will be refreshed on next request");
}
});
}
}