111 lines
3.1 KiB
Rust
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");
|
|
}
|
|
});
|
|
}
|
|
}
|