ADR-024-v4: Security Hardening Architecture - Part 2 (Technical)
Document Specification Block​
Document: ADR-024-v4-security-hardening-architecture-part2-technical
Version: 1.0.1
Purpose: Complete technical implementation blueprint for CODITECT security hardening
Audience: Implementation teams, security engineers, AI agents
Date Created: 2025-09-01
Date Modified: 2025-09-01
Status: DRAFT
Table of Contents​
- Implementation Constraints
- System Architecture
- Core Components
- Database Schema
- API Endpoints
- Security Configurations
- Error Handling
- Logging Implementation
- Testing Requirements
- Deployment Configuration
- Performance Benchmarks
- File Structure
Implementation Constraints​
MUST Requirements​
- Real-time threat detection with <5 second response time
- FoundationDB storage for tamper-proof audit logs
- Zero-trust verification for every request
- Multi-tenant isolation at all security layers
- eBPF monitoring for zero-overhead runtime security
- Automated incident response with human approval gates
- 100% security event logging with structured JSON
MUST NOT Requirements​
- Store secrets in code or configuration files
- Allow cross-tenant data access under any condition
- Disable security features for performance
- Log sensitive data (passwords, tokens, PII)
- Trust client-provided security assertions
System Architecture​
// src/security/mod.rs
use actix_web::{web, HttpResponse, Result};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Clone)]
pub struct SecurityEngine {
threat_detector: Arc<ThreatDetector>,
vulnerability_scanner: Arc<VulnerabilityScanner>,
runtime_monitor: Arc<RuntimeMonitor>,
incident_responder: Arc<IncidentResponder>,
security_logger: Arc<SecurityLogger>,
db: Arc<FoundationDBClient>,
}
impl SecurityEngine {
pub async fn new(db: Arc<FoundationDBClient>) -> Result<Self> {
Ok(Self {
threat_detector: Arc::new(ThreatDetector::new(db.clone())),
vulnerability_scanner: Arc::new(VulnerabilityScanner::new()),
runtime_monitor: Arc::new(RuntimeMonitor::new()),
incident_responder: Arc::new(IncidentResponder::new(db.clone())),
security_logger: Arc::new(SecurityLogger::new(db.clone())),
db,
})
}
pub async fn process_request(&self, req: SecurityRequest) -> Result<SecurityResponse> {
// 1. Pre-request validation
self.validate_request(&req).await?;
// 2. Threat detection
if let Some(threat) = self.threat_detector.analyze(&req).await? {
self.handle_threat(threat).await?;
return Ok(SecurityResponse::Blocked(threat.reason));
}
// 3. Runtime monitoring
let monitor_handle = self.runtime_monitor.track(&req).await?;
// 4. Process request (would be actual business logic)
let result = self.process_business_logic(&req).await?;
// 5. Post-request validation
self.validate_response(&result).await?;
// 6. Log security event
self.security_logger.log_request(&req, &result).await?;
Ok(result)
}
}
Core Components​
1. Threat Detection Engine​
// src/security/threat_detector.rs
pub struct ThreatDetector {
ml_model: Arc<ThreatMLModel>,
rule_engine: Arc<RuleEngine>,
reputation_checker: Arc<ReputationChecker>,
behavior_analyzer: Arc<BehaviorAnalyzer>,
db: Arc<FoundationDBClient>,
}
impl ThreatDetector {
pub async fn analyze(&self, req: &SecurityRequest) -> Result<Option<Threat>> {
// Parallel threat analysis
let (ml_score, rule_match, reputation, behavior_anomaly) = tokio::join!(
self.ml_model.score(req),
self.rule_engine.check(req),
self.reputation_checker.check(&req.ip_address),
self.behavior_analyzer.is_anomalous(&req.user_id, req)
);
// Combine signals into threat assessment
let threat_score = self.calculate_threat_score(
ml_score?,
rule_match?,
reputation?,
behavior_anomaly?
);
if threat_score > THREAT_THRESHOLD {
Ok(Some(Threat {
id: Uuid::new_v4(),
severity: self.classify_severity(threat_score),
type_: self.identify_threat_type(req),
confidence: threat_score,
reason: self.build_threat_reason(req),
recommended_action: self.recommend_action(threat_score),
}))
} else {
Ok(None)
}
}
}
// ML-based threat detection
pub struct ThreatMLModel {
model: onnx::Model,
feature_extractor: FeatureExtractor,
}
impl ThreatMLModel {
pub async fn score(&self, req: &SecurityRequest) -> Result<f32> {
let features = self.feature_extractor.extract(req)?;
let input = ndarray::Array2::from_shape_vec((1, features.len()), features)?;
let output = self.model.run(vec![input])?;
Ok(output[0][[0, 0]])
}
}
2. Vulnerability Scanner​
// src/security/vulnerability_scanner.rs
pub struct VulnerabilityScanner {
image_scanner: Arc<ContainerImageScanner>,
dependency_scanner: Arc<DependencyScanner>,
config_scanner: Arc<ConfigurationScanner>,
code_scanner: Arc<CodeScanner>,
}
impl VulnerabilityScanner {
pub async fn scan_deployment(&self, deployment: &Deployment) -> Result<VulnerabilityReport> {
let mut report = VulnerabilityReport::new();
// Scan container image
let image_vulns = self.image_scanner
.scan(&deployment.container_image)
.await?;
report.add_vulnerabilities(image_vulns);
// Scan dependencies
let dep_vulns = self.dependency_scanner
.scan(&deployment.dependencies)
.await?;
report.add_vulnerabilities(dep_vulns);
// Scan configuration
let config_vulns = self.config_scanner
.scan(&deployment.config)
.await?;
report.add_vulnerabilities(config_vulns);
// Prioritize by CVSS score and exploitability
report.prioritize();
Ok(report)
}
}
#[derive(Serialize, Deserialize)]
pub struct Vulnerability {
pub id: String, // CVE-YYYY-NNNNN
pub severity: Severity,
pub cvss_score: f32,
pub component: String,
pub version: String,
pub fixed_version: Option<String>,
pub exploit_available: bool,
pub patch_available: bool,
}
3. Runtime Security Monitor​
// src/security/runtime_monitor.rs
use redbpf::{Program, Module};
pub struct RuntimeMonitor {
ebpf_module: Module,
anomaly_detector: Arc<AnomalyDetector>,
policy_enforcer: Arc<PolicyEnforcer>,
}
impl RuntimeMonitor {
pub fn new() -> Result<Self> {
// Load eBPF programs for system call monitoring
let mut module = Module::parse(include_bytes!("../bpf/monitor.o"))?;
// Attach to system calls
for program in module.programs.iter_mut() {
program.attach()?;
}
Ok(Self {
ebpf_module: module,
anomaly_detector: Arc::new(AnomalyDetector::new()),
policy_enforcer: Arc::new(PolicyEnforcer::new()),
})
}
pub async fn track(&self, req: &SecurityRequest) -> Result<MonitorHandle> {
let handle = MonitorHandle::new();
// Start monitoring container
let container_id = req.container_id.clone();
tokio::spawn(async move {
self.monitor_container(container_id).await
});
Ok(handle)
}
async fn monitor_container(&self, container_id: String) -> Result<()> {
// Real-time monitoring via eBPF
let events = self.ebpf_module.events();
while let Some(event) = events.next().await {
match event {
SystemCall { pid, syscall, args } => {
if self.is_suspicious_syscall(&syscall, &args) {
self.handle_suspicious_activity(pid, syscall, args).await?;
}
}
NetworkConnection { src, dst, protocol } => {
if !self.policy_enforcer.is_allowed(&src, &dst, &protocol) {
self.block_connection(src, dst).await?;
}
}
FileAccess { pid, path, mode } => {
if self.is_sensitive_path(&path) {
self.audit_file_access(pid, path, mode).await?;
}
}
}
}
Ok(())
}
}
4. Incident Response Platform​
// src/security/incident_responder.rs
pub struct IncidentResponder {
playbook_engine: Arc<PlaybookEngine>,
forensics_collector: Arc<ForensicsCollector>,
containment_engine: Arc<ContainmentEngine>,
notification_service: Arc<NotificationService>,
db: Arc<FoundationDBClient>,
}
impl IncidentResponder {
pub async fn handle_incident(&self, threat: Threat) -> Result<IncidentResponse> {
// 1. Create incident record
let incident = Incident::from_threat(threat);
self.save_incident(&incident).await?;
// 2. Execute playbook based on threat type
let playbook = self.playbook_engine.select(&incident)?;
// 3. Automated containment (with approval gates)
if playbook.requires_immediate_action() {
self.containment_engine.isolate(&incident).await?;
}
// 4. Collect forensic evidence
let evidence = self.forensics_collector
.collect(&incident)
.await?;
// 5. Notify security team
self.notification_service
.alert_security_team(&incident)
.await?;
// 6. Execute remediation steps
let response = self.execute_playbook(playbook, &incident).await?;
Ok(response)
}
async fn execute_playbook(&self, playbook: Playbook, incident: &Incident) -> Result<IncidentResponse> {
let mut response = IncidentResponse::new();
for step in playbook.steps {
match step.action {
Action::DisableUser(user_id) => {
self.disable_user(&user_id).await?;
response.add_action("User disabled", user_id);
}
Action::IsolateContainer(container_id) => {
self.isolate_container(&container_id).await?;
response.add_action("Container isolated", container_id);
}
Action::BlockIP(ip) => {
self.block_ip(&ip).await?;
response.add_action("IP blocked", ip);
}
Action::RollbackDeployment(deployment_id) => {
self.rollback_deployment(&deployment_id).await?;
response.add_action("Deployment rolled back", deployment_id);
}
Action::RequireHumanApproval => {
self.await_human_approval(&incident).await?;
}
}
}
Ok(response)
}
}
Database Schema​
# Security Events
/{tenant_id}/security_events/{timestamp}_{event_id}:
event_type: enum
severity: enum
user_id: string
ip_address: string
threat_score: f32
action_taken: string
details: json
# Vulnerabilities
/{tenant_id}/vulnerabilities/{component}/{cve_id}:
severity: enum
cvss_score: f32
discovered_at: timestamp
patched_at: timestamp?
exploit_available: bool
# Incidents
/{tenant_id}/incidents/{incident_id}:
threat_id: string
severity: enum
status: enum
created_at: timestamp
resolved_at: timestamp?
responder: string
playbook_used: string
evidence: string[]
# Security Policies
/{tenant_id}/security_policies/{policy_id}:
name: string
type: enum
rules: json
enabled: bool
created_by: string
updated_at: timestamp
API Endpoints​
# Threat Detection
POST /api/v1/security/threats/analyze:
body: { request_context: RequestContext }
response: { threat_detected: bool, threat?: Threat, recommendation?: string }
# Vulnerability Management
GET /api/v1/security/vulnerabilities:
response: { vulnerabilities: Vulnerability[], summary: VulnSummary }
POST /api/v1/security/vulnerabilities/scan:
body: { target: ScanTarget }
response: { scan_id: string, status: string }
# Incident Response
POST /api/v1/security/incidents:
body: { threat: Threat, context: IncidentContext }
response: { incident_id: string, response: IncidentResponse }
GET /api/v1/security/incidents/{id}:
response: { incident: Incident, timeline: Event[], evidence: Evidence[] }
# Security Policies
PUT /api/v1/security/policies/{id}:
body: { policy: SecurityPolicy }
response: { updated: bool, validation: PolicyValidation }
Security Configurations​
# k8s/security-policies.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: coditect-authz
spec:
selector:
matchLabels:
app: coditect
rules:
- from:
- source:
principals: ["cluster.local/ns/coditect/sa/api-server"]
to:
- operation:
methods: ["GET", "POST", "PUT", "DELETE"]
---
apiVersion: v1
kind: NetworkPolicy
metadata:
name: coditect-network-policy
spec:
podSelector:
matchLabels:
app: coditect
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: coditect
ports:
- protocol: TCP
port: 8080
Error Handling​
#[derive(Debug, thiserror::Error)]
pub enum SecurityError {
#[error("Authentication failed")]
AuthenticationFailed,
#[error("Authorization denied")]
AuthorizationDenied,
#[error("Threat detected: {0}")]
ThreatDetected(String),
#[error("Security policy violation")]
PolicyViolation,
#[error("Incident response failed")]
IncidentResponseFailed,
}
impl SecurityError {
pub fn user_message(&self) -> String {
match self {
Self::AuthenticationFailed => "Invalid credentials".into(),
Self::AuthorizationDenied => "Access denied".into(),
Self::ThreatDetected(_) => "Request blocked for security reasons".into(),
Self::PolicyViolation => "Action violates security policy".into(),
Self::IncidentResponseFailed => "Security incident being handled".into(),
}
}
pub fn should_alert_security(&self) -> bool {
matches!(self,
Self::ThreatDetected(_) |
Self::PolicyViolation |
Self::IncidentResponseFailed
)
}
}
Logging Implementation​
// src/security/logging.rs
use coditect::logging::{Logger, LogLevel, LogEntry};
pub struct SecurityLogger {
logger: Arc<Logger>,
db: Arc<FoundationDBClient>,
}
impl SecurityLogger {
pub async fn log_security_event(&self, event: SecurityEvent) {
let entry = LogEntry {
timestamp: Utc::now(),
level: self.severity_to_level(event.severity),
component: "security",
action: event.event_type.to_string(),
tenant_id: Some(event.tenant_id),
user_id: event.user_id,
details: json!({
"ip_address": event.ip_address,
"threat_score": event.threat_score,
"action_taken": event.action_taken,
"metadata": event.metadata,
}),
};
// Log to both logging system and permanent security audit
self.logger.log(entry.clone()).await;
self.store_security_audit(entry).await;
}
async fn store_security_audit(&self, entry: LogEntry) {
let key = format!(
"{}/security_audit/{}_{}",
entry.tenant_id.unwrap_or_default(),
entry.timestamp.timestamp_nanos(),
Uuid::new_v4()
);
self.db.transact(|txn| {
txn.set(&key, &serialize(&entry)?);
Ok(())
}).await.unwrap_or_else(|e| {
error!("Failed to store security audit: {}", e);
});
}
}
Testing Requirements​
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_threat_detection() {
let engine = SecurityEngine::new_test().await;
// Test SQL injection detection
let malicious_req = SecurityRequest {
path: "/api/users",
params: vec![("id", "1'; DROP TABLE users; --")],
..Default::default()
};
let result = engine.process_request(malicious_req).await;
assert!(matches!(result, Err(SecurityError::ThreatDetected(_))));
}
#[tokio::test]
async fn test_incident_response() {
let responder = IncidentResponder::new_test().await;
let threat = Threat {
severity: Severity::Critical,
type_: ThreatType::DataExfiltration,
..Default::default()
};
let response = responder.handle_incident(threat).await.unwrap();
assert!(response.actions.contains(&"User disabled"));
assert!(response.actions.contains(&"Container isolated"));
}
#[tokio::test]
async fn test_vulnerability_scanning() {
let scanner = VulnerabilityScanner::new();
let deployment = Deployment {
container_image: "nginx:1.14.0", // Known vulnerable version
..Default::default()
};
let report = scanner.scan_deployment(&deployment).await.unwrap();
assert!(!report.vulnerabilities.is_empty());
assert!(report.has_critical_vulnerabilities());
}
}
Deployment Configuration​
# k8s/security-engine-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: security-engine
spec:
replicas: 3
template:
spec:
serviceAccountName: security-engine
securityContext:
runAsNonRoot: true
fsGroup: 65534
containers:
- name: security-engine
image: coditect/security-engine:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsUser: 65534
capabilities:
drop:
- ALL
add:
- NET_ADMIN # For eBPF
env:
- name: FDB_CLUSTER_FILE
value: /etc/fdb/fdb.cluster
- name: RUST_LOG
value: security=debug,info
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
volumeMounts:
- name: ebpf-maps
mountPath: /sys/fs/bpf
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8080
volumes:
- name: ebpf-maps
hostPath:
path: /sys/fs/bpf
type: Directory
Performance Benchmarks​
- Threat detection latency: P99 < 50ms
- Vulnerability scan time: <30s for container image
- Incident response time: <5s for automated actions
- Security event logging: 100K events/second
- Memory usage: <512MB per instance
- CPU overhead: <5% for runtime monitoring
File Structure​
src/security/
├── mod.rs # Main security engine
├── threat_detector.rs # Threat detection logic
├── vulnerability_scanner.rs # Vulnerability scanning
├── runtime_monitor.rs # eBPF runtime monitoring
├── incident_responder.rs # Incident response
├── logging.rs # Security logging
├── policies/
│ ├── mod.rs # Policy engine
│ └── rules.rs # Security rules
├── ml/
│ ├── mod.rs # ML models
│ └── features.rs # Feature extraction
└── bpf/
└── monitor.c # eBPF programs
This implementation provides comprehensive security hardening with real-time threat detection, automated incident response, and continuous monitoring while maintaining CODITECT's performance and multi-tenant isolation requirements.