Security Guide - ruvnet/ruv-FANN GitHub Wiki
Comprehensive security best practices for deploying and operating ruv-FANN systems in production environments.
- Overview
- Security Architecture
- Authentication and Authorization
- Data Encryption
- Network Security
- Container Security
- Vulnerability Management
- Security Monitoring
- Incident Response
- Compliance
- Best Practices
Security is paramount when deploying AI systems that process sensitive data and make critical decisions. ruv-FANN provides comprehensive security features to protect your neural networks, swarm intelligence systems, and data pipelines.
- Defense in Depth: Multiple layers of security controls
- Zero Trust: Never trust, always verify
- Least Privilege: Minimal permissions required
- Secure by Default: Security enabled out of the box
- Continuous Monitoring: Real-time threat detection
use ruv_fann::security::{SecurityLayer, SecurityConfig};
// Configure multi-layer security
let security_config = SecurityConfig::builder()
.add_layer(SecurityLayer::NetworkIsolation)
.add_layer(SecurityLayer::Authentication)
.add_layer(SecurityLayer::Authorization)
.add_layer(SecurityLayer::Encryption)
.add_layer(SecurityLayer::AuditLogging)
.add_layer(SecurityLayer::IntrusionDetection)
.build()?;
// Apply to neural network system
let secure_system = NeuralSystem::new()
.with_security(security_config)
.build()?;
# threat-model.yaml
threats:
- name: Model Extraction Attack
category: Confidentiality
likelihood: Medium
impact: High
mitigations:
- Rate limiting on inference API
- Differential privacy in responses
- Model watermarking
- name: Adversarial Inputs
category: Integrity
likelihood: High
impact: Medium
mitigations:
- Input validation and sanitization
- Adversarial training
- Anomaly detection
- name: Data Poisoning
category: Integrity
likelihood: Medium
impact: High
mitigations:
- Training data validation
- Outlier detection
- Secure data pipeline
- name: Byzantine Agents
category: Availability
likelihood: Low
impact: High
mitigations:
- Byzantine fault tolerance
- Agent authentication
- Consensus verification
use jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String, // Subject (user ID)
exp: usize, // Expiration time
iat: usize, // Issued at
roles: Vec<String>, // User roles
permissions: Vec<String>, // Specific permissions
}
// Authentication service
pub struct AuthService {
encoding_key: EncodingKey,
decoding_key: DecodingKey,
validation: Validation,
}
impl AuthService {
pub fn new(secret: &[u8]) -> Self {
Self {
encoding_key: EncodingKey::from_secret(secret),
decoding_key: DecodingKey::from_secret(secret),
validation: Validation::default(),
}
}
pub fn generate_token(&self, user_id: &str, roles: Vec<String>) -> Result<String> {
let expiration = Utc::now()
.checked_add_signed(chrono::Duration::hours(24))
.expect("valid timestamp")
.timestamp();
let claims = Claims {
sub: user_id.to_string(),
exp: expiration as usize,
iat: Utc::now().timestamp() as usize,
roles,
permissions: self.derive_permissions(&roles),
};
encode(&Header::default(), &claims, &self.encoding_key)
.map_err(|e| Error::TokenGeneration(e.to_string()))
}
pub fn verify_token(&self, token: &str) -> Result<Claims> {
decode::<Claims>(token, &self.decoding_key, &self.validation)
.map(|data| data.claims)
.map_err(|e| Error::TokenValidation(e.to_string()))
}
}
use ruv_fann::security::rbac::{Role, Permission, Resource};
// Define roles and permissions
#[derive(Debug, Clone)]
enum SystemRole {
Admin,
DataScientist,
MLEngineer,
Viewer,
}
#[derive(Debug, Clone)]
enum SystemPermission {
TrainModel,
DeployModel,
ViewMetrics,
ManageData,
ConfigureSystem,
}
// RBAC implementation
pub struct RBACManager {
role_permissions: HashMap<SystemRole, HashSet<SystemPermission>>,
user_roles: HashMap<String, HashSet<SystemRole>>,
}
impl RBACManager {
pub fn new() -> Self {
let mut role_permissions = HashMap::new();
// Admin has all permissions
role_permissions.insert(SystemRole::Admin,
vec![
SystemPermission::TrainModel,
SystemPermission::DeployModel,
SystemPermission::ViewMetrics,
SystemPermission::ManageData,
SystemPermission::ConfigureSystem,
].into_iter().collect()
);
// Data Scientist permissions
role_permissions.insert(SystemRole::DataScientist,
vec![
SystemPermission::TrainModel,
SystemPermission::ViewMetrics,
SystemPermission::ManageData,
].into_iter().collect()
);
// ML Engineer permissions
role_permissions.insert(SystemRole::MLEngineer,
vec![
SystemPermission::DeployModel,
SystemPermission::ViewMetrics,
SystemPermission::ConfigureSystem,
].into_iter().collect()
);
// Viewer permissions
role_permissions.insert(SystemRole::Viewer,
vec![SystemPermission::ViewMetrics].into_iter().collect()
);
Self {
role_permissions,
user_roles: HashMap::new(),
}
}
pub fn check_permission(
&self,
user_id: &str,
permission: SystemPermission,
) -> bool {
self.user_roles
.get(user_id)
.map(|roles| {
roles.iter().any(|role| {
self.role_permissions
.get(role)
.map(|perms| perms.contains(&permission))
.unwrap_or(false)
})
})
.unwrap_or(false)
}
}
// Authorization middleware
pub async fn require_permission(
permission: SystemPermission,
) -> impl Filter<Extract = (), Error = Rejection> + Clone {
warp::header::<String>("authorization")
.and_then(move |token: String| {
let permission = permission.clone();
async move {
let claims = AUTH_SERVICE.verify_token(&token)
.map_err(|_| warp::reject::unauthorized())?;
if RBAC_MANAGER.check_permission(&claims.sub, permission) {
Ok(())
} else {
Err(warp::reject::forbidden())
}
}
})
.untuple_one()
}
use oauth2::{
AuthorizationCode, AuthUrl, ClientId, ClientSecret,
CsrfToken, PkceCodeChallenge, RedirectUrl, Scope,
TokenResponse, TokenUrl,
};
// OAuth2 client configuration
pub struct OAuth2Config {
client_id: ClientId,
client_secret: ClientSecret,
auth_url: AuthUrl,
token_url: TokenUrl,
redirect_url: RedirectUrl,
}
impl OAuth2Config {
pub fn github() -> Self {
Self {
client_id: ClientId::new(env::var("GITHUB_CLIENT_ID").unwrap()),
client_secret: ClientSecret::new(env::var("GITHUB_CLIENT_SECRET").unwrap()),
auth_url: AuthUrl::new("https://github.com/login/oauth/authorize".to_string()).unwrap(),
token_url: TokenUrl::new("https://github.com/login/oauth/access_token".to_string()).unwrap(),
redirect_url: RedirectUrl::new("http://localhost:8080/auth/callback".to_string()).unwrap(),
}
}
}
use aes_gcm::{Aes256Gcm, Key, Nonce};
use aes_gcm::aead::{Aead, NewAead};
pub struct DataEncryption {
cipher: Aes256Gcm,
}
impl DataEncryption {
pub fn new(key: &[u8; 32]) -> Self {
let key = Key::from_slice(key);
let cipher = Aes256Gcm::new(key);
Self { cipher }
}
pub fn encrypt_model(&self, model: &NeuralNetwork) -> Result<Vec<u8>> {
let serialized = bincode::serialize(model)?;
let nonce = Nonce::from_slice(b"unique nonce"); // Use random nonce in production
self.cipher
.encrypt(nonce, serialized.as_ref())
.map_err(|e| Error::Encryption(e.to_string()))
}
pub fn decrypt_model(&self, encrypted: &[u8]) -> Result<NeuralNetwork> {
let nonce = Nonce::from_slice(b"unique nonce");
let decrypted = self.cipher
.decrypt(nonce, encrypted)
.map_err(|e| Error::Decryption(e.to_string()))?;
bincode::deserialize(&decrypted)
.map_err(|e| Error::Deserialization(e.to_string()))
}
}
// Encrypted model storage
pub struct SecureModelStore {
encryption: DataEncryption,
storage: Box<dyn Storage>,
}
impl SecureModelStore {
pub async fn save_model(
&self,
model_id: &str,
model: &NeuralNetwork,
) -> Result<()> {
let encrypted = self.encryption.encrypt_model(model)?;
// Add metadata
let metadata = ModelMetadata {
id: model_id.to_string(),
created_at: Utc::now(),
encrypted: true,
algorithm: "AES-256-GCM",
};
self.storage.put(
&format!("models/{}", model_id),
&encrypted,
Some(serde_json::to_vec(&metadata)?),
).await
}
}
use rustls::{ServerConfig, Certificate, PrivateKey};
use tokio_rustls::TlsAcceptor;
// TLS configuration
pub fn configure_tls() -> Result<ServerConfig> {
let cert_file = std::fs::File::open("cert.pem")?;
let key_file = std::fs::File::open("key.pem")?;
let cert_chain = rustls_pemfile::certs(&mut BufReader::new(cert_file))?
.into_iter()
.map(Certificate)
.collect();
let mut keys = rustls_pemfile::pkcs8_private_keys(&mut BufReader::new(key_file))?;
let key = PrivateKey(keys.remove(0));
let config = ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(cert_chain, key)?;
Ok(config)
}
// Secure gRPC server
pub async fn start_secure_grpc_server() -> Result<()> {
let addr = "[::1]:50051".parse()?;
let tls_config = configure_tls()?;
let neural_service = NeuralServiceImpl::new();
Server::builder()
.tls_config(tls_config)?
.add_service(NeuralServiceServer::new(neural_service))
.serve(addr)
.await?;
Ok(())
}
use tfhe::prelude::*;
// Homomorphic neural network inference
pub struct HomomorphicNN {
parameters: ServerKey,
weights: Vec<Vec<LweBootstrappingKey>>,
}
impl HomomorphicNN {
pub fn encrypted_inference(
&self,
encrypted_input: &[Ciphertext],
) -> Result<Vec<Ciphertext>> {
let mut activation = encrypted_input.to_vec();
for (layer_idx, layer_weights) in self.weights.iter().enumerate() {
let mut next_activation = Vec::new();
for neuron_weights in layer_weights {
let mut sum = self.parameters.create_trivial(0);
// Homomorphic matrix multiplication
for (w, a) in neuron_weights.iter().zip(&activation) {
let product = self.parameters.mul(w, a);
sum = self.parameters.add(&sum, &product);
}
// Homomorphic activation (approximated ReLU)
let activated = self.homomorphic_relu(&sum);
next_activation.push(activated);
}
activation = next_activation;
}
Ok(activation)
}
}
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: neural-network-policy
spec:
podSelector:
matchLabels:
app: ruv-fann
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ruv-fann
- podSelector:
matchLabels:
role: api-gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
role: database
ports:
- protocol: TCP
port: 5432
- to:
- podSelector:
matchLabels:
role: cache
ports:
- protocol: TCP
port: 6379
# nginx-waf.conf
http {
# Rate limiting
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=inference_limit:10m rate=100r/s;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ModSecurity WAF
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
server {
listen 443 ssl http2;
server_name api.ruv-fann.com;
ssl_certificate /etc/ssl/certs/ruv-fann.crt;
ssl_certificate_key /etc/ssl/private/ruv-fann.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# API endpoints with rate limiting
location /api/v1/inference {
limit_req zone=inference_limit burst=20 nodelay;
proxy_pass http://neural-backend;
}
location /api/v1/training {
limit_req zone=api_limit burst=5 nodelay;
proxy_pass http://training-backend;
}
# Block suspicious patterns
location ~ \.(sql|bak|config|log)$ {
deny all;
}
}
}
use governor::{Quota, RateLimiter};
use std::num::NonZeroU32;
// Rate limiter implementation
pub struct DDoSProtection {
inference_limiter: RateLimiter<String, DefaultKeyedStateStore<String>>,
training_limiter: RateLimiter<String, DefaultKeyedStateStore<String>>,
}
impl DDoSProtection {
pub fn new() -> Self {
Self {
inference_limiter: RateLimiter::keyed(
Quota::per_second(NonZeroU32::new(100).unwrap())
),
training_limiter: RateLimiter::keyed(
Quota::per_minute(NonZeroU32::new(10).unwrap())
),
}
}
pub async fn check_inference_limit(&self, client_id: &str) -> Result<()> {
self.inference_limiter
.check_key(&client_id.to_string())
.map_err(|_| Error::RateLimitExceeded)?;
Ok(())
}
}
// Circuit breaker for downstream services
use circuit_breaker::{CircuitBreaker, Config};
pub struct ServiceProtection {
breaker: CircuitBreaker,
}
impl ServiceProtection {
pub fn new() -> Self {
let config = Config::new()
.failure_rate_threshold(0.5)
.slow_call_rate_threshold(0.5)
.wait_duration_in_open_state(Duration::from_secs(30))
.slow_call_duration_threshold(Duration::from_secs(1))
.permitted_calls_in_half_open_state(10)
.sliding_window_size(100);
Self {
breaker: CircuitBreaker::new(config),
}
}
pub async fn call_service<F, T>(&self, f: F) -> Result<T>
where
F: Future<Output = Result<T>>,
{
self.breaker.call(f).await
}
}
# Secure Dockerfile
FROM rust:1.81-alpine AS builder
# Run as non-root user
RUN addgroup -g 1000 -S rust && \
adduser -u 1000 -S rust -G rust
# Install security updates
RUN apk update && apk upgrade && \
apk add --no-cache ca-certificates
# Copy and build application
WORKDIR /app
COPY --chown=rust:rust . .
USER rust
RUN cargo build --release --locked
# Runtime stage
FROM alpine:3.18
# Install runtime dependencies and security updates
RUN apk update && apk upgrade && \
apk add --no-cache ca-certificates && \
rm -rf /var/cache/apk/*
# Create non-root user
RUN addgroup -g 1000 -S app && \
adduser -u 1000 -S app -G app
# Copy binary
COPY --from=builder --chown=app:app /app/target/release/ruv-fann /usr/local/bin/
# Security configurations
USER app
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD ["ruv-fann", "health"]
ENTRYPOINT ["ruv-fann"]
# .github/workflows/security-scan.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t ruv-fann:scan .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'ruv-fann:scan'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Run Snyk container scan
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: ruv-fann:scan
args: --severity-threshold=high
use seccomp::{Context, Action, Arch, Syscall};
// Seccomp security profile
pub fn apply_seccomp_profile() -> Result<()> {
let mut ctx = Context::new(Action::Errno(libc::EPERM))?;
// Allow only required syscalls
let allowed_syscalls = vec![
Syscall::read,
Syscall::write,
Syscall::open,
Syscall::close,
Syscall::mmap,
Syscall::munmap,
Syscall::brk,
Syscall::rt_sigaction,
Syscall::rt_sigprocmask,
Syscall::ioctl,
Syscall::nanosleep,
Syscall::exit,
Syscall::exit_group,
];
for syscall in allowed_syscalls {
ctx.add_rule(Action::Allow, syscall)?;
}
ctx.load()?;
Ok(())
}
// AppArmor profile
const APPARMOR_PROFILE: &str = r#"
#include <tunables/global>
profile ruv-fann flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# Application binary
/usr/local/bin/ruv-fann ix,
# Read access to models
/models/** r,
# Write access to logs
/var/log/ruv-fann/** w,
# Network access
network tcp,
network udp,
# Deny everything else
deny /** wklx,
deny @{PROC}/** wklx,
deny /sys/** wklx,
}
"#;
# Cargo.toml security configuration
[dependencies]
# Use exact versions for security-critical dependencies
tokio = "=1.35.0"
serde = "=1.0.195"
jsonwebtoken = "=9.2.0"
[profile.release]
# Security hardening
lto = true
codegen-units = 1
panic = "abort"
strip = true
opt-level = 3
# Audit dependencies
[package.metadata.cargo-audit]
ignore = []
#[cfg(test)]
mod security_tests {
use super::*;
#[test]
fn test_sql_injection_prevention() {
let malicious_input = "'; DROP TABLE models; --";
let result = sanitize_input(malicious_input);
assert!(!result.contains("DROP"));
}
#[test]
fn test_xss_prevention() {
let xss_attempt = "<script>alert('XSS')</script>";
let sanitized = html_escape(xss_attempt);
assert_eq!(sanitized, "<script>alert('XSS')</script>");
}
#[test]
fn test_path_traversal_prevention() {
let malicious_path = "../../../etc/passwd";
let result = validate_file_path(malicious_path);
assert!(result.is_err());
}
#[test]
fn test_command_injection_prevention() {
let malicious_cmd = "echo test; rm -rf /";
let result = execute_safe_command(malicious_cmd);
assert!(result.is_err());
}
}
// Fuzzing tests
#[cfg(test)]
mod fuzz_tests {
use arbitrary::{Arbitrary, Unstructured};
#[test]
fn fuzz_input_validation() {
let data = vec![0u8; 1024];
let mut u = Unstructured::new(&data);
for _ in 0..1000 {
if let Ok(input) = String::arbitrary(&mut u) {
let _ = validate_neural_input(&input);
// Should not panic
}
}
}
}
use serde_json::json;
use chrono::Utc;
// Security event logging
#[derive(Debug, Serialize)]
pub struct SecurityEvent {
timestamp: DateTime<Utc>,
event_type: SecurityEventType,
severity: Severity,
source_ip: Option<String>,
user_id: Option<String>,
details: serde_json::Value,
}
#[derive(Debug, Serialize)]
pub enum SecurityEventType {
AuthenticationFailure,
AuthorizationFailure,
RateLimitExceeded,
AnomalousActivity,
DataExfiltrationAttempt,
ModelExtractionAttempt,
}
pub struct SecurityMonitor {
event_sender: mpsc::Sender<SecurityEvent>,
}
impl SecurityMonitor {
pub async fn log_event(&self, event: SecurityEvent) {
// Send to SIEM
if let Err(e) = self.event_sender.send(event).await {
eprintln!("Failed to log security event: {}", e);
}
}
pub async fn detect_anomalies(&self, request: &Request) -> Option<SecurityEvent> {
// Check for unusual patterns
if self.is_model_extraction_attempt(request) {
return Some(SecurityEvent {
timestamp: Utc::now(),
event_type: SecurityEventType::ModelExtractionAttempt,
severity: Severity::High,
source_ip: request.remote_addr().map(|a| a.to_string()),
user_id: request.user_id().cloned(),
details: json!({
"endpoint": request.uri().to_string(),
"query_count": request.query_count(),
}),
});
}
None
}
}
use ml_ids::{AnomalyDetector, NetworkFlow};
pub struct NeuralIDS {
detector: AnomalyDetector,
baseline: NetworkBaseline,
}
impl NeuralIDS {
pub async fn analyze_traffic(&mut self, flow: NetworkFlow) -> Option<Alert> {
// Extract features
let features = self.extract_features(&flow);
// Check against baseline
let anomaly_score = self.detector.predict(&features);
if anomaly_score > self.baseline.threshold {
return Some(Alert {
severity: self.calculate_severity(anomaly_score),
description: format!("Anomalous network traffic detected: score {:.2}", anomaly_score),
source: flow.source_ip,
destination: flow.dest_ip,
timestamp: Utc::now(),
});
}
// Update baseline
self.baseline.update(&features);
None
}
}
# incident-response.yaml
incident_response_plan:
phases:
- name: Detection
steps:
- Monitor security alerts
- Verify incident validity
- Assess initial impact
- name: Containment
steps:
- Isolate affected systems
- Preserve evidence
- Prevent spread
- name: Eradication
steps:
- Remove threat
- Patch vulnerabilities
- Update security controls
- name: Recovery
steps:
- Restore systems
- Verify functionality
- Monitor for recurrence
- name: Post-Incident
steps:
- Document incident
- Conduct post-mortem
- Update response procedures
contacts:
security_team: [email protected]
management: [email protected]
legal: [email protected]
external: [email protected]
pub struct IncidentResponder {
isolation_controller: NetworkIsolation,
evidence_collector: ForensicsCollector,
notification_service: NotificationService,
}
impl IncidentResponder {
pub async fn handle_security_incident(&mut self, incident: SecurityIncident) -> Result<()> {
match incident.severity {
Severity::Critical => {
// Immediate automated response
self.isolation_controller.isolate_system(&incident.affected_system).await?;
self.evidence_collector.start_collection(&incident).await?;
self.notification_service.alert_security_team(&incident).await?;
// Initiate emergency procedures
self.initiate_emergency_response(&incident).await?;
}
Severity::High => {
// Partial automation with human verification
self.evidence_collector.start_collection(&incident).await?;
self.notification_service.request_approval(&incident).await?;
}
_ => {
// Log and monitor
self.log_incident(&incident).await?;
}
}
Ok(())
}
}
// Data privacy implementation
pub struct PrivacyManager {
encryption: DataEncryption,
anonymizer: DataAnonymizer,
}
impl PrivacyManager {
pub fn handle_data_request(&self, request: DataRequest) -> Result<DataResponse> {
match request {
DataRequest::Access { user_id } => {
let data = self.get_user_data(&user_id)?;
Ok(DataResponse::UserData(self.anonymize_pii(data)))
}
DataRequest::Deletion { user_id } => {
self.delete_user_data(&user_id)?;
Ok(DataResponse::Deleted)
}
DataRequest::Portability { user_id } => {
let data = self.export_user_data(&user_id)?;
Ok(DataResponse::Export(data))
}
}
}
fn anonymize_pii(&self, data: UserData) -> UserData {
UserData {
id: self.hash_identifier(&data.id),
email: self.anonymizer.anonymize_email(&data.email),
name: self.anonymizer.anonymize_name(&data.name),
..data
}
}
}
#[derive(Debug, Serialize)]
pub struct AuditLog {
timestamp: DateTime<Utc>,
user_id: String,
action: String,
resource: String,
result: ActionResult,
metadata: HashMap<String, String>,
}
pub struct AuditLogger {
storage: SecureStorage,
signer: MessageSigner,
}
impl AuditLogger {
pub async fn log_action(&self, log: AuditLog) -> Result<()> {
// Sign log entry for tamper detection
let serialized = serde_json::to_string(&log)?;
let signature = self.signer.sign(&serialized)?;
let signed_log = SignedAuditLog {
log,
signature,
};
// Store immutably
self.storage.append_only_write(&signed_log).await?;
Ok(())
}
}
// Security checks in CI/CD
#[cfg(test)]
mod security_ci {
#[test]
fn check_no_hardcoded_secrets() {
let files = glob::glob("**/*.rs").unwrap();
for file in files {
let content = std::fs::read_to_string(file.unwrap()).unwrap();
assert!(!content.contains("password ="));
assert!(!content.contains("api_key ="));
assert!(!content.contains("secret ="));
}
}
}
// Configuration validation
pub struct SecureConfig {
inner: Config,
}
impl SecureConfig {
pub fn load() -> Result<Self> {
let config = Config::builder()
.add_source(config::File::with_name("config"))
.add_source(config::Environment::with_prefix("RUVFANN"))
.build()?;
// Validate security settings
Self::validate_tls_config(&config)?;
Self::validate_auth_config(&config)?;
Self::validate_encryption_config(&config)?;
Ok(Self { inner: config })
}
}
// Security middleware
pub fn security_headers() -> impl Filter<Extract = (), Error = Rejection> + Clone {
warp::reply::with::headers(vec![
("X-Content-Type-Options", "nosniff"),
("X-Frame-Options", "DENY"),
("X-XSS-Protection", "1; mode=block"),
("Strict-Transport-Security", "max-age=31536000; includeSubDomains"),
("Content-Security-Policy", "default-src 'self'"),
("Referrer-Policy", "strict-origin-when-cross-origin"),
("Permissions-Policy", "geolocation=(), microphone=(), camera=()"),
])
}
use validator::{Validate, ValidationError};
#[derive(Debug, Validate)]
pub struct ModelInput {
#[validate(length(min = 1, max = 1000))]
#[validate(custom = "validate_no_injection")]
name: String,
#[validate(range(min = 0.0, max = 1.0))]
learning_rate: f32,
#[validate(range(min = 1, max = 1000000))]
epochs: u32,
}
fn validate_no_injection(value: &str) -> Result<(), ValidationError> {
let forbidden = ["<script>", "DROP", "DELETE", "../", "\\x00"];
for pattern in forbidden {
if value.contains(pattern) {
return Err(ValidationError::new("injection_attempt"));
}
}
Ok(())
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
require_https: true,
min_tls_version: TlsVersion::V1_2,
enable_rate_limiting: true,
max_requests_per_minute: 100,
enable_audit_logging: true,
require_authentication: true,
session_timeout: Duration::from_hours(1),
max_login_attempts: 5,
password_min_length: 12,
require_mfa: true,
}
}
}
Security must be integrated at every level of the ruv-FANN system, from neural network training to production deployment. This guide provides comprehensive security patterns and implementations to protect against modern threats.
Key security principles:
- Defense in Depth: Multiple security layers
- Zero Trust: Verify everything, trust nothing
- Continuous Monitoring: Real-time threat detection
- Incident Response: Prepared for security events
- Compliance: Meet regulatory requirements
For additional security resources, see the Production Deployment and Monitoring & Metrics guides.