diff --git a/README.md b/README.md index d4dca8b..8b8aa43 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ openshield/ --- + ## Quick Start ```bash @@ -185,4 +186,20 @@ MIT — free to use, modify, and distribute. --- +> Built with ❤️ by security engineers and students who believe cloud security tooling should be accessible to everyone. + +--- + +## Learn OpenShield + +Explore the OpenShield learning portal to understand: + +- Azure CSPM fundamentals +- OpenShield architecture +- Compliance mappings +- Remediation workflows +- Contributor onboarding +- Documentation navigation + +👉 [OpenShield Learn](docs/learn/index.html) > Built by security engineers and students who believe cloud security tooling should be accessible to everyone. diff --git a/compliance/frameworks/cis_azure_benchmark.json b/compliance/frameworks/cis_azure_benchmark.json index f5c1989..00e45c0 100644 --- a/compliance/frameworks/cis_azure_benchmark.json +++ b/compliance/frameworks/cis_azure_benchmark.json @@ -98,6 +98,11 @@ "control_name": "Ensure that 'OS disk' are encrypted", "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control." }, + "AZ-CMP-003": { + "control_id": "8.2", + "control_name": "Ensure that 'Endpoint protection solution' is installed on VMs", + "description": "The virtual machine does not have a recognised endpoint protection extension installed. CIS 8.2 requires that an approved endpoint protection solution is installed and running on all virtual machines. Without endpoint protection, malware and ransomware can execute without detection." + }, "AZ-KV-001": { "control_id": "8.5", "control_name": "Ensure the Key Vault is Recoverable", diff --git a/compliance/frameworks/iso27001.json b/compliance/frameworks/iso27001.json index 697052e..2b7c271 100644 --- a/compliance/frameworks/iso27001.json +++ b/compliance/frameworks/iso27001.json @@ -98,6 +98,11 @@ "control_name": "Policy on the use of cryptographic controls", "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). A.10.1.1 requires that a policy on the use of cryptographic controls is developed and implemented. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." }, + "AZ-CMP-003": { + "control_id": "A.12.2.1", + "control_name": "Controls against malware", + "description": "The virtual machine does not have a recognised endpoint protection extension installed. A.12.2.1 requires that detection, prevention and recovery controls are implemented to protect against malware. Without endpoint protection, malware executing on the VM will not be detected or prevented." + }, "AZ-KV-001": { "control_id": "A.17.2.1", "control_name": "Availability of information processing facilities", diff --git a/compliance/frameworks/nist_csf.json b/compliance/frameworks/nist_csf.json index ad41cc2..d249fe0 100644 --- a/compliance/frameworks/nist_csf.json +++ b/compliance/frameworks/nist_csf.json @@ -98,6 +98,11 @@ "control_name": "Data-at-rest is protected", "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). PR.DS-1 requires that data at rest is protected using appropriate controls. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." }, + "AZ-CMP-003": { + "control_id": "DE.CM-4", + "control_name": "Malicious code is detected", + "description": "The virtual machine does not have a recognised endpoint protection extension installed. DE.CM-4 requires that malicious code is detected on organisational systems. Without endpoint protection, malware and ransomware executing on the VM will not be detected or blocked." + }, "AZ-KV-001": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", diff --git a/compliance/frameworks/soc2.json b/compliance/frameworks/soc2.json index a793241..db100f7 100644 --- a/compliance/frameworks/soc2.json +++ b/compliance/frameworks/soc2.json @@ -103,6 +103,11 @@ "control_name": "Protects Data in Transit and At Rest", "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CC6.7 requires that data is protected using encryption. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." }, + "AZ-CMP-003": { + "control_id": "CC6.8", + "control_name": "Prevents or Detects Unauthorized or Malicious Software", + "description": "The virtual machine does not have a recognised endpoint protection extension installed. CC6.8 requires that controls are implemented to prevent or detect and act upon the introduction of unauthorized or malicious software. Without endpoint protection, malicious code executing on the VM will not be detected or blocked." + }, "AZ-KV-001": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", diff --git a/docs/learn/index.html b/docs/learn/index.html new file mode 100644 index 0000000..93c5164 --- /dev/null +++ b/docs/learn/index.html @@ -0,0 +1,479 @@ + + + + + + OpenShield Learn + + + +
+
Open Source Azure CSPM Platform
+

OpenShield Learn

+

+ A practical learning hub for understanding OpenShield, Azure cloud security posture management, + misconfiguration detection, compliance mapping, drift detection, and remediation workflows. +

+
+ Architecture + Learn CSPM + Contributing + Docs +
+
+ +
+
+

What is OpenShield?

+

+ OpenShield is an open-source Azure CSPM platform designed to identify cloud misconfigurations, + map findings to compliance frameworks, monitor posture drift, and provide remediation guidance. It helps users understand + what is insecure, why it matters, and how to fix it. +

+
+
+

Misconfiguration Scanning

+

Checks Azure resources for risky settings that can expose data, weaken access control, or reduce security visibility.

+
+
+

Compliance Mapping

+

Connects security findings to frameworks such as CIS, NIST, and ISO so issues can be understood in a governance context.

+
+
+

Remediation Guidance

+

Provides practical fix guidance using Azure CLI, ARM templates, Terraform, and validation checks where applicable.

+
+
+

Drift Detection

+

Tracks changes in cloud security posture so teams can identify when previously safe configurations become risky.

+
+
+
+ +
+

How OpenShield Works

+

+ OpenShield follows a simple scanning pipeline: collect Azure resource configuration, evaluate rules, + generate findings, map them to controls, and expose results through the platform. +

+
+
Azure Subscription
+
Scanner Engine
+
Rule Evaluation
+
Findings
+
Compliance Mapping
+
Drift Detection
+
Dashboard & Reporting
+
+
+ +
+

Core Components

+

+ OpenShield is built with a simple MVP-friendly architecture: Python scanner, Flask API, + PostgreSQL storage, React frontend, compliance mapping, Sentinel integration, and supporting remediation playbooks. +

+
+
+

Scanner Engine

+

Python-based scanner that uses Azure SDK clients to inspect Azure resource configuration and evaluate security rules.

+ PythonAzure SDK +
+
+

Flask API

+

Backend API layer responsible for exposing scan results, findings, metadata, and platform data to the frontend.

+ FlaskREST API +
+
+

PostgreSQL

+

Stores scan findings, rule metadata, compliance mappings, and remediation-related information.

+ DatabasePersistence +
+
+

React Dashboard

+

Frontend dashboard for viewing findings, severity, affected resources, and security posture information.

+ ReactDashboard +
+
+

Playbooks

+

Remediation documents that explain how to fix detected issues using CLI, ARM templates, Terraform, and validation steps.

+ Azure CLIARMTerraform +
+
+

Sentinel

+

Supports security monitoring and SIEM-focused documentation where OpenShield findings connect with detection workflows.

+ SIEMDetection +
+
+
+ +
+

CSPM Basics

+

+ Cloud Security Posture Management focuses on continuously identifying insecure cloud configurations. + In Azure, common examples include public storage exposure, weak network rules, missing logging, + overly permissive identities, and disabled security protections. +

+
+
+

Why It Matters

+

Cloud breaches often happen because resources are misconfigured, not because the cloud provider itself failed.

+
+
+

Example Issues

+
    +
  • Public blob access
  • +
  • Weak network security groups
  • +
  • Missing monitoring or logging
  • +
  • Over-permissive access policies
  • +
+
+
+

OpenShield Role

+

OpenShield helps surface these issues, explain their impact, and guide users toward safer Azure configurations.

+
+
+
+ +
+

Compliance Mapping

+

+ A single security finding can map to multiple compliance controls. OpenShield uses mappings to connect + technical misconfigurations with security frameworks such as CIS Benchmarks, NIST CSF, ISO 27001, and SOC 2. +

+
+

CIS

Maps findings to cloud security benchmarks and configuration recommendations.

+

NIST

Connects findings to broader cybersecurity controls and risk management practices.

+

ISO 27001

Supports governance, information security controls, and audit-oriented reporting context.

+

SOC 2

Connects relevant findings to trust-service control areas such as security, availability, and confidentiality.

+
+
+ +
+

Remediation Philosophy

+

+ Detection alone is not enough. A useful CSPM tool should explain the risk, provide fix guidance, + and help validate whether the issue has actually been resolved. +

+
+

Detect

Identify insecure Azure configuration accurately with minimal false positives.

+

Explain

Show why the finding matters, what resource is affected, and what the risk is.

+

Fix

Provide Azure CLI, ARM template, or Terraform-based remediation steps that users can apply safely.

+

Validate

Re-run checks or confirm settings to verify the misconfiguration is resolved.

+
+
+ +
+

Contributor Learning Path

+

+ New contributors should understand the security problem first, then the OpenShield architecture, + then the rule and remediation workflow. +

+
+
+

Suggested Path

+
    +
  1. Understand CSPM fundamentals
  2. +
  3. Review the OpenShield architecture
  4. +
  5. Explore existing documentation and rules
  6. +
  7. Understand findings, mappings, and remediation playbooks
  8. +
  9. Add or improve rules and playbooks
  10. +
  11. Test changes against Azure safely
  12. +
+
+
+

Contribution Focus

+

Good contributions improve detection accuracy, remediation quality, documentation clarity, or platform reliability.

+
+
+
+ +
+

Documentation Links

+

+ Use these links as the starting point for understanding and contributing to OpenShield. +

+
+
+
ArchitectureSystem design, platform components, and scanning workflow.
+ Open +
+
+
API ReferenceBackend API documentation for working with OpenShield data.
+ Open +
+
+
Azure SetupRequired Azure setup and configuration before running scans.
+ Open +
+
+
Rules ReferenceRule documentation and expected structure for security checks.
+ Open +
+
+
Adding a RuleContributor guide for creating and testing new scan rules.
+ Open +
+
+
+ +
+

Open Source Goals

+

+ OpenShield aims to make Azure security posture management easier to understand, easier to test, + and easier to improve through community contribution. +

+
+

Security Research

Encourage practical Azure misconfiguration research and rule development.

+

Education

Help learners understand CSPM, cloud controls, and secure Azure configuration.

+

Community

Build a contributor-friendly platform where improvements are clear and reviewable.

+
+
+ +
+

Future Scope

+

+ OpenShield can grow over time with richer dashboards, stronger compliance reports, + automated remediation workflows, and eventually broader cloud coverage. +

+
+ +
+ Note: This page is a static documentation hub. Do not add fake file upload buttons here. + Real uploads require backend storage, authentication, authorization, file validation, and access control. +
+
+ + + + diff --git a/playbooks/cli/fix_az_cmp_003.sh b/playbooks/cli/fix_az_cmp_003.sh new file mode 100644 index 0000000..f2c83f1 --- /dev/null +++ b/playbooks/cli/fix_az_cmp_003.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# OpenShield Remediation Playbook +# Rule: AZ-CMP-003 — VM without endpoint protection installed +# Usage: ./fix_az_cmp_003.sh [windows|linux] +# Severity: HIGH + +set -e + +RG=$1 +VM=$2 +OS=${3:-windows} + +if [ -z "$RG" ] || [ -z "$VM" ]; then + echo "Usage: $0 [windows|linux]" + exit 1 +fi + +if [ "${OS,,}" = "linux" ]; then + echo "Installing MDE.Linux on $VM..." + az vm extension set \ + --resource-group "$RG" \ + --vm-name "$VM" \ + --name "MDE.Linux" \ + --publisher "Microsoft.Azure.AzureDefenderForServers" \ + --version "1.0" \ + --auto-upgrade-minor-version true + echo "Done. Finish onboarding in the Defender portal." +else + echo "Enabling IaaSAntimalware on $VM..." + SETTINGS='{ + "AntimalwareEnabled": true, + "RealtimeProtectionEnabled": true, + "ScheduledScanSettings": { + "isEnabled": true, + "day": "1", + "time": "120", + "scanType": "Quick" + } + }' + az vm extension set \ + --resource-group "$RG" \ + --vm-name "$VM" \ + --name "IaaSAntimalware" \ + --publisher "Microsoft.Azure.Security" \ + --version "1.3" \ + --auto-upgrade-minor-version true \ + --settings "$SETTINGS" + echo "IaaSAntimalware enabled on $VM." +fi diff --git a/scanner/azure_client.py b/scanner/azure_client.py index e65f567..5dc9bd0 100644 --- a/scanner/azure_client.py +++ b/scanner/azure_client.py @@ -240,6 +240,7 @@ def get_virtual_networks(self) -> List[Any]: logger.error("get_virtual_networks failed: %s", exc) return [] + def get_public_ip_addresses(self) -> List[Any]: """List all public IP addresses in the subscription.""" try: @@ -262,6 +263,16 @@ def get_virtual_machines(self) -> List[Any]: logger.error("get_virtual_machines failed: %s", exc) return [] + + + def get_vm_extensions(self, resource_group: str, vm_name: str) -> Optional[List[Any]]: + try: + result = ComputeManagementClient(self.credential, self.subscription_id).virtual_machine_extensions.list(resource_group, vm_name) + return list(getattr(result, "value", []) or []) + except Exception as exc: + logger.error("get_vm_extensions failed for %s/%s: %s", resource_group, vm_name, exc) + return None + # ------------------------------------------------------------------ # # Databases # # ------------------------------------------------------------------ # diff --git a/scanner/rules/az_cmp_003.py b/scanner/rules/az_cmp_003.py new file mode 100644 index 0000000..96c88a0 --- /dev/null +++ b/scanner/rules/az_cmp_003.py @@ -0,0 +1,80 @@ +"""AZ-CMP-003: VM without endpoint protection installed.""" + +import logging +from typing import Any, Dict, List + +RULE_ID = "AZ-CMP-003" +RULE_NAME = "VM Without Endpoint Protection Installed" +SEVERITY = "HIGH" +CATEGORY = "Compute" +FRAMEWORKS = { + "CIS": "8.2", + "NIST": "DE.CM-4", + "ISO27001": "A.12.2.1", + "SOC2": "CC6.8", +} +DESCRIPTION = ( + "VM has no recognised endpoint protection extension installed. " + "Without it malware and ransomware can run undetected. " + "CIS 8.2 requires an approved AV/EDR solution on all VMs." +) +REMEDIATION = ( + "Install IaaSAntimalware or onboard to MDE (MDE.Windows / MDE.Linux) " + "depending on the OS." +) +PLAYBOOK = "playbooks/cli/fix_az_cmp_003.sh" + +KNOWN_EP_EXTENSIONS = { + "microsoftmonitoringagent", + "mde.linux", + "mde.windows", + "iaasantimalware", +} + +logger = logging.getLogger(__name__) + + +def scan(azure_client: Any, subscription_id: str) -> List[Dict[str, Any]]: + findings: List[Dict[str, Any]] = [] + + for vm in azure_client.get_virtual_machines(): + parsed = azure_client.parse_resource_id(getattr(vm, "id", "")) + rg = parsed.get("resource_group", "") + vm_name = parsed.get("name", "") + if not rg or not vm_name: + continue + + exts = azure_client.get_vm_extensions(rg, vm_name) + if exts is None: + continue + + installed = set() + for e in exts: + t = ( + getattr(e, "type_properties_type", None) + or getattr(e, "virtual_machine_extension_type", None) + or getattr(e, "type", "") + ) + if t: + installed.add(t.lower()) + + if not installed.intersection(KNOWN_EP_EXTENSIONS): + findings.append({ + "rule_id": RULE_ID, + "rule_name": RULE_NAME, + "severity": SEVERITY, + "category": CATEGORY, + "resource_id": vm.id, + "resource_name": vm_name, + "resource_type": "Microsoft.Compute/virtualMachines", + "description": DESCRIPTION, + "remediation": REMEDIATION, + "playbook": PLAYBOOK, + "frameworks": FRAMEWORKS, + "metadata": { + "resource_group": rg, + "installed_extensions": sorted(installed), + }, + }) + + return findings