Security Guide¶
Security best practices for AirsSys components.
OSL Security Model¶
Deny-by-Default¶
All operations are denied by default unless explicitly allowed by security policies.
// Without policy - operation denied
let result = read_file("/data/secret.txt", "user").await;
// Error: Access denied
// With policy - operation allowed
let acl = AccessControlList::new()
.add_entry(AclEntry::new(
"user".to_string(),
"/data/*".to_string(),
vec!["read".to_string()],
AclPolicy::Allow,
));
Access Control Lists (ACL)¶
Path-based access control with glob patterns:
use airssys_osl::middleware::security::*;
let acl = AccessControlList::new()
// Allow read/write to /tmp
.add_entry(AclEntry::new(
"alice".to_string(),
"/tmp/*".to_string(),
vec!["read".to_string(), "write".to_string()],
AclPolicy::Allow,
))
// Allow read-only to /data
.add_entry(AclEntry::new(
"alice".to_string(),
"/data/**".to_string(),
vec!["read".to_string()],
AclPolicy::Allow,
))
// Explicitly deny sensitive files
.add_entry(AclEntry::new(
"alice".to_string(),
"/data/sensitive/*".to_string(),
vec!["read".to_string(), "write".to_string()],
AclPolicy::Deny, // Deny takes precedence
));
Role-Based Access Control (RBAC)¶
Role hierarchies with permission inheritance:
let rbac = RoleBasedAccessControl::new()
// Define roles
.add_role("admin", vec!["read", "write", "delete", "execute"])
.add_role("developer", vec!["read", "write", "execute"])
.add_role("operator", vec!["read", "execute"])
.add_role("viewer", vec!["read"])
// Define role hierarchy (inheritance)
.add_role_hierarchy("admin", "developer")
.add_role_hierarchy("developer", "operator")
.add_role_hierarchy("operator", "viewer");
// Assign user to role
rbac.assign_user("alice", "developer")?;
// alice inherits: read, write, execute (from developer)
// + read (from operator via hierarchy)
// + read (from viewer via hierarchy)
Combining Policies¶
Multiple policies can be combined:
let security = SecurityMiddlewareBuilder::new()
.add_policy(Box::new(acl))
.add_policy(Box::new(rbac))
.add_policy(Box::new(rate_limiter))
.build()?;
// All policies must allow the operation
RT Security Model¶
Actor Isolation¶
Actors have private state enforced by Rust ownership:
struct BankAccount {
balance: i64, // Private, cannot be accessed by other actors
}
// Other actors CANNOT:
// - Read balance directly
// - Modify balance directly
// - Share references to balance
// Other actors CAN:
// - Send messages to request balance
// - Send messages to request transfers
Message Validation¶
Validate messages before processing:
#[async_trait]
impl Actor for SecureActor {
async fn handle_message<B: MessageBroker<Self::Message>>(
&mut self,
msg: Self::Message,
_ctx: &mut ActorContext<Self::Message, B>,
) -> Result<(), Self::Error> {
// Validate message
if !self.validate_message(&msg) {
return Err("Invalid message".into());
}
// Process message
// ...
Ok(())
}
}
Supervisor Security¶
Supervisors enforce fault isolation:
// Failed actor is isolated and restarted
// Failure does NOT propagate to siblings
let supervisor = SupervisorBuilder::new()
.with_strategy(RestartStrategy::OneForOne) // Isolate failures
.with_max_restarts(3, Duration::from_secs(60))
.build();
Audit Logging¶
OSL Audit Trails¶
All operations are logged:
{
"timestamp": "2025-12-10T10:30:00Z",
"principal": "alice",
"operation": "FileRead",
"resource": "/data/customer_data.csv",
"result": "allowed",
"policy": "acl:data-read",
"duration_ms": 15
}
Configure logging:
use airssys_osl::middleware::logger::*;
let logger = FileActivityLogger::new("/var/log/airssys/audit.log").await?;
let middleware = LoggerMiddleware::with_config(
logger,
LoggerConfig {
log_success: true,
log_failures: true,
include_principal: true,
include_duration: true,
}
);
RT Event Monitoring¶
Monitor actor events:
use airssys_rt::monitoring::*;
let monitor = InMemoryMonitor::new();
// Events logged:
// - Actor spawned
// - Actor stopped
// - Message sent
// - Message received
// - Supervision events
// - Health check results
Security Best Practices¶
Principle of Least Privilege¶
Grant minimum required permissions:
// ❌ Bad: Overly permissive
let acl = AccessControlList::new()
.add_entry(AclEntry::new(
"app".to_string(),
"/**".to_string(), // Access to everything!
vec!["read".to_string(), "write".to_string(), "delete".to_string()],
AclPolicy::Allow,
));
// ✅ Good: Specific permissions
let acl = AccessControlList::new()
.add_entry(AclEntry::new(
"app".to_string(),
"/app/data/*".to_string(), // Only app data
vec!["read".to_string(), "write".to_string()], // No delete
AclPolicy::Allow,
));
Defense in Depth¶
Layer multiple security mechanisms:
let security = SecurityMiddlewareBuilder::new()
.add_policy(Box::new(acl)) // Path-based control
.add_policy(Box::new(rbac)) // Role-based control
.add_policy(Box::new(rate_limit)) // Rate limiting
.add_policy(Box::new(time_based)) // Time-based access
.build()?;
Secure Defaults¶
Use secure defaults:
// Default security included in helpers
read_file(path, principal).await?; // ✅ Security checked
// Explicit security for custom use
read_file_with_middleware(path, principal, security).await?; // ✅ Custom policy
Input Validation¶
Validate all inputs:
fn validate_path(path: &str) -> Result<(), Error> {
// Check path traversal
if path.contains("..") {
return Err("Path traversal detected");
}
// Check absolute path
if !path.starts_with("/") {
return Err("Absolute path required");
}
// Check allowed directory
if !path.starts_with("/app/data") {
return Err("Path not in allowed directory");
}
Ok(())
}
Error Handling¶
Don't leak sensitive information in errors:
// ❌ Bad: Leaks path details
return Err(format!("Failed to read {}", full_system_path));
// ✅ Good: Generic error
return Err("File operation failed");
// ✅ Good: Log details, return generic error
log::error!("Failed to read {}", full_system_path);
return Err("File operation failed");
Compliance Considerations¶
SOC 2 / HIPAA / GDPR¶
AirsSys provides features for compliance:
- Audit logs: Complete operation history
- Access control: Granular permissions
- Data isolation: Actor-based separation
- Encryption: Use with file encryption middleware
- Retention: Configurable log retention
Example compliance configuration:
// Audit logging for compliance
let audit_logger = FileActivityLogger::new("/audit/operations.log").await?;
let audit_middleware = LoggerMiddleware::with_config(
audit_logger,
LoggerConfig {
log_success: true,
log_failures: true,
include_principal: true,
include_duration: true,
}
);
// Access control for data protection
let acl = AccessControlList::new()
.add_entry(AclEntry::new(
"medical_staff".to_string(),
"/medical/records/**".to_string(),
vec!["read".to_string()],
AclPolicy::Allow,
));
// Combine for compliance
let security = SecurityMiddlewareBuilder::new()
.add_middleware(audit_middleware)
.add_policy(Box::new(acl))
.build()?;
Security Checklist¶
Before Deployment¶
- Security policies configured
- Audit logging enabled
- Log files secured (permissions)
- Error messages don't leak sensitive data
- Input validation implemented
- Least privilege principle applied
- Security policies tested
- Failure scenarios tested
During Operation¶
- Monitor audit logs
- Review access patterns
- Update security policies as needed
- Rotate log files
- Review and respond to security events