TL;DR
This guide explains how to apply the Bell-LaPadula model (a security policy) to composite services. We’ll cover understanding sensitivity levels, applying ‘no read up’, ‘no write down’, and dealing with multiple service components.
Understanding Bell-LaPadula
The Bell-LaPadula model is all about controlling access to information based on its sensitivity. Think of it like this:
- Sensitivity Levels: Data gets a label (e.g., ‘Top Secret’, ‘Secret’, ‘Confidential’, ‘Unclassified’).
- Users also have clearances: Users need a clearance level equal to or higher than the data they want to access.
- Two main rules:
- No Read Up: You can’t read data with a higher sensitivity label than your clearance.
- No Write Down: You can’t write data to a location with a lower sensitivity label than the data you’re writing.
Applying Bell-LaPadula to Composite Services
Composite services are built from smaller components. Each component needs to be considered for Bell-LaPadula compliance.
Step 1: Identify Service Components and Data Flows
- List all components: What microservices, APIs, databases, or other parts make up your composite service?
- Map data flows: How does data move between these components? Which component creates the data, which reads it, and which writes to it? A diagram is helpful here.
Step 2: Assign Sensitivity Levels
- Data sensitivity: For each piece of data flowing through your service, decide its appropriate sensitivity level (e.g., ‘Confidential’, ‘Secret’). Be realistic – overclassifying adds overhead; underclassifying is a security risk.
- Component sensitivity: Each component also needs a sensitivity level based on the most sensitive data it handles. If one component processes both ‘Unclassified’ and ‘Secret’ data, assign it ‘Secret’.
Step 3: Enforce ‘No Read Up’
- Check user clearances: Before a component reads data, verify the current user’s clearance is high enough.
- Example (Python):
- API Gateways: Use API gateways to enforce this check before routing requests to backend components.
def can_read(user_clearance, data_sensitivity):
if user_clearance >= data_sensitivity:
return True
else:
return False
# Example usage
user_level = 'Secret'
data_level = 'Top Secret'
if can_read(user_level, data_level):
print("Access granted")
else:
print("Access denied")
Step 4: Enforce ‘No Write Down’
- Check data sensitivity: Before a component writes data, verify the target location’s sensitivity level is high enough.
- Example (Java):
- Database Access Control: Configure database permissions to prevent writing sensitive data to lower-security tables.
public boolean canWrite(String userClearance, String dataSensitivity, String destinationLevel) {
if (destinationLevel >= dataSensitivity) {
return true;
} else {
return false;
}
}
Step 5: Handling Composite Service Interactions
- Trust Boundaries: Identify trust boundaries between components. If a component trusts another, you might need less stringent checks (but still document the risks!).
- Data Transformation: Be careful with data transformation. Down-classifying data requires explicit approval and auditing. Never automatically reduce sensitivity levels.
- Auditing: Log all access attempts (successful and failed) for security monitoring and incident response.
Step 6: Testing
- Unit Tests: Test each component’s Bell-LaPadula checks individually.
- Integration Tests: Test the entire composite service to ensure data flows are secure end-to-end. Try accessing data with different user clearances and verify access is correctly denied when it should be.
- Penetration Testing: Have a security professional attempt to bypass your controls.