Overview
Implement the ORSA (OpenWatch Remediation and Security Automation) Plugin Architecture to execute remediation content extracted from SCAP rules. This enables automated security hardening after compliance scans identify failed checks.
Phase 1 Progress: 4/7 tasks completed → 5/7 after this issue
Problem Statement
After scanning identifies failed compliance rules, operators need to remediate them. Currently:
Solution: ORSA Plugin Architecture
Pluggable remediation executor framework supporting multiple automation engines:
- Ansible: Execute playbooks for configuration management
- Bash: Execute shell scripts for simple fixes
- Future: Terraform, Kubernetes manifests, Python scripts
Requirements
Functional Requirements
- Execute remediation content from
ComplianceRule.remediation field
- Support multiple executor types (Ansible, Bash, future extensibility)
- Track remediation execution status (pending/running/completed/failed)
- Store remediation results with stdout/stderr
- Rollback support for failed remediations
- Dry-run mode for preview
- Integration with scan results
Non-Functional Requirements
- Async execution for long-running remediations
- Idempotent execution
- Secure credential handling
- Audit logging of all remediation actions
- Resource isolation (containers/sandboxes)
Architecture
Components
┌─────────────────────────────────────────────────────────────┐
│ Remediation API │
│ POST /remediate/execute │
│ GET /remediate/{id} │
│ POST /remediate/rollback │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ RemediationOrchestrator │
│ - Query rule remediation content │
│ - Route to appropriate executor │
│ - Track execution status │
│ - Store results in MongoDB │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┴─────────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ AnsibleExecutor │ │ BashExecutor │
│ - ansible-playbook│ │ - bash -c │
│ - Inventory mgmt │ │ - Script │
│ - Vault decrypt │ │ validation │
└──────────────────┘ └──────────────────┘
│ │
└─────────────────┬─────────────────┘
▼
┌──────────────────────┐
│ RemediationResult │
│ MongoDB Document │
└──────────────────────┘
Implementation Tasks
1. MongoDB Models (backend/app/models/remediation_models.py)
class RemediationStatus(str, Enum):
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
ROLLED_BACK = "rolled_back"
class RemediationTarget(BaseModel):
type: ScanTargetType # ssh_host, kubernetes, local
identifier: str
credentials: Optional[Dict[str, str]]
class RemediationResult(Document):
remediation_id: str
rule_id: str
rule_title: str
executor_type: str # ansible, bash, terraform
target: RemediationTarget
status: RemediationStatus
started_at: Optional[datetime]
completed_at: Optional[datetime]
dry_run: bool
# Execution details
content_executed: str
variables_applied: Dict[str, str]
stdout: Optional[str]
stderr: Optional[str]
exit_code: Optional[int]
# Tracking
executed_by: str
rollback_available: bool
rollback_content: Optional[str]
class Settings:
name = "remediation_results"
2. Base Executor (backend/app/services/remediators/base_executor.py)
class BaseRemediationExecutor(ABC):
@abstractmethod
async def execute(
self,
content: str,
target: RemediationTarget,
variables: Dict[str, str],
dry_run: bool = False
) -> RemediationExecutionResult:
pass
@abstractmethod
async def rollback(
self,
remediation_id: str,
rollback_content: str,
target: RemediationTarget
) -> RemediationExecutionResult:
pass
@abstractmethod
def validate_content(self, content: str) -> bool:
pass
3. Ansible Executor (backend/app/services/remediators/ansible_executor.py)
Features:
- Execute Ansible playbooks from string content
- Dynamic inventory generation
- Variable substitution
- Ansible Vault support for encrypted credentials
- Check mode (dry-run) support
- Idempotency via Ansible modules
4. Bash Executor (backend/app/services/remediators/bash_executor.py)
Features:
- Execute bash scripts from string content
- Variable expansion
- Script validation (syntax check)
- Timeout support
- SSH execution for remote targets
- Restricted mode (no network access in dry-run)
5. Executor Factory (backend/app/services/remediators/__init__.py)
class RemediationExecutorFactory:
_executors = {
'ansible': AnsibleExecutor,
'bash': BashExecutor,
}
@classmethod
def get_executor(cls, executor_type: str) -> BaseRemediationExecutor:
pass
6. Remediation Orchestrator (backend/app/services/remediation_orchestrator_service.py)
class RemediationOrchestrator:
async def execute_remediation(
self,
rule_id: str,
target: RemediationTarget,
variable_overrides: Dict[str, str] = None,
dry_run: bool = False,
executed_by: str = None
) -> RemediationResult:
# 1. Query rule from MongoDB
# 2. Extract remediation content
# 3. Determine executor type
# 4. Execute remediation
# 5. Store result
pass
async def execute_bulk_remediation(
self,
scan_id: str,
rule_filter: Dict[str, Any] = None,
dry_run: bool = False
) -> List[RemediationResult]:
# Remediate all failed rules from a scan
pass
7. API Endpoints (backend/app/api/v1/endpoints/remediation_api.py)
@router.post("/execute", response_model=RemediationResult)
async def execute_remediation(request: RemediationRequest, ...):
pass
@router.post("/execute-bulk", response_model=List[RemediationResult])
async def execute_bulk_remediation(request: BulkRemediationRequest, ...):
pass
@router.get("/{remediation_id}", response_model=RemediationResult)
async def get_remediation_result(remediation_id: str, ...):
pass
@router.post("/{remediation_id}/rollback", response_model=RemediationResult)
async def rollback_remediation(remediation_id: str, ...):
pass
Example Usage
Execute Single Remediation
curl -X POST http://localhost:8000/api/v1/remediation/execute \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"rule_id": "xccdf_com.hanalyx.openwatch_rule_accounts_tmout",
"target": {
"type": "ssh_host",
"identifier": "prod-web-01.example.com",
"credentials": {
"username": "root",
"ssh_key": "..."
}
},
"variable_overrides": {
"var_accounts_tmout": "300"
},
"dry_run": false
}'
Bulk Remediation (Failed Rules from Scan)
curl -X POST http://localhost:8000/api/v1/remediation/execute-bulk \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scan_id": "550e8400-e29b-41d4-a716-446655440000",
"rule_filter": {
"status": "fail",
"severity": ["high", "critical"]
},
"dry_run": true
}'
Rollback Remediation
curl -X POST http://localhost:8000/api/v1/remediation/{remediation_id}/rollback \
-H "Authorization: Bearer $TOKEN"
Security Considerations
- Credential Encryption: Store SSH keys/passwords encrypted in MongoDB
- Execution Isolation: Run remediations in containers/VMs when possible
- Audit Logging: Log all remediation actions with user attribution
- Approval Workflow: Require manual approval for production systems
- Dry-Run First: Always test with
dry_run=true before production
- Rollback Safety: Generate rollback content before execution
Testing Strategy
Unit Tests
- Executor validation methods
- Variable substitution
- Content parsing
- Error handling
Integration Tests
- Ansible playbook execution against test VM
- Bash script execution
- Rollback functionality
- Bulk remediation
E2E Tests
- Scan → Identify Failed Rules → Remediate → Re-scan → Verify Pass
Dependencies
ansible-core: Ansible playbook execution
paramiko: SSH connectivity for bash executor
- Existing:
motor, beanie, fastapi
Estimated Effort
5-7 days
- Models: 0.5 day
- Base executor: 0.5 day
- Ansible executor: 2 days
- Bash executor: 1 day
- Orchestrator: 1 day
- API: 0.5 day
- Testing: 1.5 days
Acceptance Criteria
Related Issues
References
Overview
Implement the ORSA (OpenWatch Remediation and Security Automation) Plugin Architecture to execute remediation content extracted from SCAP rules. This enables automated security hardening after compliance scans identify failed checks.
Phase 1 Progress: 4/7 tasks completed → 5/7 after this issue
Problem Statement
After scanning identifies failed compliance rules, operators need to remediate them. Currently:
remediationfield (from PR [Phase 1] Enhanced SCAP Converter with Variable and Remediation Extraction #97) with Ansible/Bash contentSolution: ORSA Plugin Architecture
Pluggable remediation executor framework supporting multiple automation engines:
Requirements
Functional Requirements
ComplianceRule.remediationfieldNon-Functional Requirements
Architecture
Components
Implementation Tasks
1. MongoDB Models (
backend/app/models/remediation_models.py)2. Base Executor (
backend/app/services/remediators/base_executor.py)3. Ansible Executor (
backend/app/services/remediators/ansible_executor.py)Features:
4. Bash Executor (
backend/app/services/remediators/bash_executor.py)Features:
5. Executor Factory (
backend/app/services/remediators/__init__.py)6. Remediation Orchestrator (
backend/app/services/remediation_orchestrator_service.py)7. API Endpoints (
backend/app/api/v1/endpoints/remediation_api.py)Example Usage
Execute Single Remediation
Bulk Remediation (Failed Rules from Scan)
Rollback Remediation
curl -X POST http://localhost:8000/api/v1/remediation/{remediation_id}/rollback \ -H "Authorization: Bearer $TOKEN"Security Considerations
dry_run=truebefore productionTesting Strategy
Unit Tests
Integration Tests
E2E Tests
Dependencies
ansible-core: Ansible playbook executionparamiko: SSH connectivity for bash executormotor,beanie,fastapiEstimated Effort
5-7 days
Acceptance Criteria
Related Issues
References