Security Configuration Assessment (SCA) in Wazuh

The Security Configuration Assessment (SCA) module in Wazuh evaluates endpoint configurations against established security standards. It compares current system settings with reference policies and produces a report of passed, failed, and not-applicable checks. The built-in policies align with CIS Benchmarks and can be extended with custom rules tailored to organizational needs.

How It Works

SCA evaluates endpoint configuration through a three-stage process:

  1. Policy loading - the agent loads YAML policy files from its local directory or receives them centrally from the server
  2. Check execution - each check in the policy tests a specific configuration aspect (file, process, registry, command)
  3. Result aggregation - results are sent to the server and indexed for visualization in the dashboard
Agent loads policy -> Executes checks ->
-> Results (passed/failed/not applicable) ->
-> Sent to server -> Indexer -> Dashboard

Configuring SCA in ossec.conf

The SCA module is configured in the <sca> block of /var/ossec/etc/ossec.conf:

<sca>
  <enabled>yes</enabled>
  <scan_on_start>yes</scan_on_start>
  <interval>12h</interval>
  <skip_nfs>yes</skip_nfs>

  <policies>
    <policy>etc/shared/cis_ubuntu22-04.yml</policy>
    <policy>etc/shared/cis_apache_24.yml</policy>
    <policy enabled="no">etc/shared/cis_win2022.yml</policy>
  </policies>
</sca>

Configuration Parameters

ParameterDescriptionDefault
enabledEnable the SCA moduleyes
scan_on_startRun scan when the agent startsyes
intervalInterval between scans12h
skip_nfsSkip network filesystemsyes
policiesList of policy files to apply-

Built-in CIS Benchmark Policies

Wazuh ships with policies based on CIS (Center for Internet Security) standards. These policies cover operating systems and services.

Linux

PolicyFile
CIS Ubuntu 22.04cis_ubuntu22-04.yml
CIS Ubuntu 20.04cis_ubuntu20-04.yml
CIS Debian 11cis_debian11.yml
CIS Debian 10cis_debian10.yml
CIS CentOS 8cis_centos8.yml
CIS CentOS 7cis_centos7.yml
CIS RHEL 9cis_rhel9.yml
CIS RHEL 8cis_rhel8.yml
CIS RHEL 7cis_rhel7.yml
CIS Amazon Linux 2cis_amazonlinux2.yml
CIS SUSE Linux 15cis_sles15.yml

Windows

PolicyFile
CIS Windows Server 2022cis_win2022.yml
CIS Windows Server 2019cis_win2019.yml
CIS Windows Server 2016cis_win2016.yml
CIS Windows 11 Enterprisecis_win11_enterprise.yml
CIS Windows 10 Enterprisecis_win10_enterprise.yml

Applications and Services

PolicyFile
CIS Apache HTTP Server 2.4cis_apache_24.yml
CIS MySQL 8.0cis_mysql80.yml
CIS PostgreSQL 13cis_postgresql13.yml
CIS Dockercis_docker.yml
CIS Kubernetescis_kubernetes.yml
CIS Nginxcis_nginx.yml

Policy File Format (YAML)

Each SCA policy file consists of four sections: policy, requirements, variables, and checks.

The policy Section

Contains policy metadata:

policy:
  id: "custom_ssh_hardening"
  file: "ssh_hardening.yml"
  name: "SSH Server Hardening Policy"
  description: "Security checks for OpenSSH server configuration"
  references:
    - https://www.cisecurity.org/benchmark/distribution_independent_linux

The requirements Section

Defines prerequisites for policy execution:

requirements:
  title: "Check SSH server is installed"
  description: "Requirements for running the SSH hardening policy"
  condition: any
  rules:
    - 'f:/etc/ssh/sshd_config'
    - 'p:sshd'

If the requirements are not met, the policy is skipped and all checks receive a “Not applicable” status.

The variables Section

Defines reusable variables for checks:

variables:
  $sshd_config: /etc/ssh/sshd_config
  $pam_dir: /etc/pam.d
  $ssh_service: sshd
  $audit_log: /var/log/auth.log,/var/log/secure

Variables are prefixed with $ and can contain multiple paths separated by commas.

The checks Section

Contains the set of checks. Each check includes metadata and test rules.

checks:
  - id: 5001
    title: "Ensure SSH root login is disabled"
    description: "The PermitRootLogin parameter specifies if root can log in using SSH"
    rationale: "Disabling root login forces administrators to use personal accounts"
    remediation: "Set PermitRootLogin to no in /etc/ssh/sshd_config"
    compliance:
      - cis: ["5.2.10"]
      - pci_dss: ["2.2.4"]
      - nist_800_53: ["AC.6"]
      - mitre_attack: ["T1078"]
    condition: all
    rules:
      - 'f:$sshd_config -> !r:^# && r:PermitRootLogin\s+no'

Check Types

File Checks (f:)

Verify file existence and content:

# Check file exists
- 'f:/etc/ssh/sshd_config'

# Negation - file must NOT exist
- 'not f:/etc/hosts.equiv'

# Content match (literal)
- 'f:/etc/ssh/sshd_config -> PermitRootLogin no'

# Content match (regex)
- 'f:/etc/ssh/sshd_config -> r:^PermitRootLogin\s+no'

# Numeric comparison
- 'f:/etc/ssh/sshd_config -> n:MaxAuthTries\s+(\d+) compare <= 4'

# Compound condition (AND)
- 'f:/etc/ssh/sshd_config -> !r:^# && r:PermitRootLogin && r:no'

Directory Checks (d:)

Verify directory existence and file contents:

# Check directory exists
- 'd:/etc/ssh'

# Find files matching pattern in directory
- 'd:/etc/cron.d -> r:\.cron$'

# Check file content within directory
- 'd:/etc/sudoers.d -> r:NOPASSWD'

Process Checks (p:)

Verify the presence or absence of running processes:

# Process must be running
- 'p:sshd'
- 'p:auditd'

# Process must NOT be running
- 'not p:telnetd'
- 'not p:rshd'

Command Checks (c:)

Execute a command and verify the output:

# Check command output
- 'c:systemctl is-enabled sshd -> r:enabled'

# Numeric comparison of output
- 'c:sshd -T -> n:maxauthtries\s+(\d+) compare <= 4'

# Check service status
- 'c:systemctl status firewalld -> r:active'

# Check file permissions
- 'c:stat -c %a /etc/shadow -> r:^0?600$'

Registry Checks (r:) - Windows Only

Verify Windows Registry keys and values:

# Check key exists
- 'r:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa'

# Check value
- 'r:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa -> LimitBlankPasswordUse -> 1'

# Numeric comparison
- 'r:HKEY_LOCAL_MACHINE\...\Lsa -> n:LmCompatibilityLevel compare >= 3'

Evaluation Logic

The condition Field

The condition field determines how individual rule results are aggregated into the final check result:

ValueDescription
allCheck passes if ALL rules pass
anyCheck passes if AT LEAST ONE rule passes
noneCheck passes if NO rules pass

Check Results

StatusDescription
PassedConfiguration meets policy requirements
FailedConfiguration does not meet requirements
Not applicableCheck cannot be executed (target does not exist)

Comparison Operators

OperatorDescription
r:Regex match
!r:Negated regex match
n:Numeric comparison
&&Logical AND (combine conditions)

Numeric operators: <, <=, ==, !=, >=, >

Writing Custom Policies

Complete Policy Example

policy:
  id: "web_server_hardening"
  file: "web_server_hardening.yml"
  name: "Web Server Security Hardening"
  description: "Custom security checks for Apache/Nginx web servers"
  references:
    - https://httpd.apache.org/docs/2.4/misc/security_tips.html

requirements:
  title: "Check web server is installed"
  description: "At least one web server must be present"
  condition: any
  rules:
    - 'p:apache2'
    - 'p:httpd'
    - 'p:nginx'

variables:
  $apache_conf: /etc/apache2/apache2.conf,/etc/httpd/conf/httpd.conf
  $nginx_conf: /etc/nginx/nginx.conf

checks:
  - id: 10001
    title: "Ensure ServerTokens is set to Prod"
    description: "ServerTokens controls the information returned in HTTP headers"
    rationale: "Detailed server information aids attackers in reconnaissance"
    remediation: "Set ServerTokens Prod in the Apache configuration"
    compliance:
      - cis: ["5.13"]
      - pci_dss: ["2.2.4"]
    condition: all
    rules:
      - 'f:$apache_conf -> !r:^# && r:ServerTokens\s+Prod'

  - id: 10002
    title: "Ensure directory listing is disabled"
    description: "Options -Indexes prevents directory listing"
    rationale: "Directory listing exposes file structure to potential attackers"
    remediation: "Add Options -Indexes to directory configuration"
    compliance:
      - cis: ["5.7"]
    condition: all
    rules:
      - 'f:$apache_conf -> !r:^# && r:Options.*-Indexes'

  - id: 10003
    title: "Ensure TRACE method is disabled"
    description: "TraceEnable Off disables HTTP TRACE method"
    rationale: "TRACE method can be used for cross-site tracing attacks"
    remediation: "Set TraceEnable Off in the Apache configuration"
    compliance:
      - cis: ["5.8"]
      - mitre_attack: ["T1190"]
    condition: all
    rules:
      - 'f:$apache_conf -> !r:^# && r:TraceEnable\s+Off'

  - id: 10004
    title: "Ensure Nginx server_tokens is off"
    description: "server_tokens off hides Nginx version in HTTP headers"
    rationale: "Version disclosure assists in targeted exploit selection"
    remediation: "Set server_tokens off in nginx.conf"
    condition: all
    rules:
      - 'f:$nginx_conf -> !r:^# && r:server_tokens\s+off'

  - id: 10005
    title: "Ensure SSL/TLS is configured"
    description: "Web server should use TLS for encrypted communications"
    rationale: "Unencrypted traffic exposes data to interception"
    remediation: "Configure SSL certificate and enable TLS"
    compliance:
      - pci_dss: ["4.1"]
      - nist_800_53: ["SC.8"]
    condition: any
    rules:
      - 'f:$apache_conf -> r:SSLEngine\s+on'
      - 'f:$nginx_conf -> r:ssl_certificate'

Deploying Custom Policies

Place custom policy files in /var/ossec/etc/shared/ and register them in the SCA configuration:

<sca>
  <policies>
    <policy>etc/shared/web_server_hardening.yml</policy>
  </policies>
</sca>

Centralized Distribution

To distribute policies centrally through the Wazuh server:

  1. Place the policy file in /var/ossec/etc/shared/default/ on the server
  2. The policy will be delivered automatically to all agents in the default group
  3. For agent groups, use /var/ossec/etc/shared/<group_name>/

Compliance Mapping

SCA policies support mapping to the following standards:

StandardCompliance Key
CIS Benchmarkscis
PCI DSSpci_dss
NIST 800-53nist_800_53
HIPAAhipaa
GDPRgdpr
TSC (SOC 2)tsc
MITRE ATT&CKmitre_attack

SCA Dashboard

The SCA dashboard in Wazuh Dashboard provides:

  • Policy overview - list of policies with pass rate percentages
  • Per-agent detail - SCA results for a specific agent
  • Change history - result trends over time
  • Failed checks - list of non-compliant findings with remediation guidance
  • Filtering - by policy, agent, check status, and compliance standard

Access the dashboard at: Wazuh Dashboard - Modules - Configuration Assessment.

Remediation Guidance

Each SCA check includes a remediation field with instructions for resolving non-compliance. A typical workflow:

  1. Review failed checks in the SCA dashboard
  2. Sort by criticality (CIS Level 1 - essential, Level 2 - defense-in-depth)
  3. Apply the guidance from the remediation field
  4. Wait for the next scan cycle or trigger a manual rescan

To trigger a manual rescan:

/var/ossec/bin/agent_control -r -u <agent_id>

Comparison with Alternative Solutions

FeatureWazuh SCAOpenSCAPLynisNessus Compliance
Policy formatYAMLXCCDF/OVALShellProprietary
CIS BenchmarksYes (built-in)Yes (SCAP)Yes (partial)Yes (paid)
Custom policiesYesYes (complex)YesLimited
Centralized managementYes (agent.conf)NoNoYes
Real-time monitoringPeriodicOn-demandOn-demandPeriodic
SIEM integrationBuilt-inRequires exportRequires exportVia API
LicenseOpen Source (GPLv2)Open SourceGPLCommercial
Windows supportYesLimitedNoYes
Results APIREST APICLICLIREST API

Wazuh SCA stands out through its straightforward YAML policy format, centralized distribution via the server, and native integration with the indexer for long-term result storage.

Troubleshooting

Policy Not Loading

  1. Validate the YAML file syntax:
python3 -c "import yaml; yaml.safe_load(open('/var/ossec/etc/shared/policy.yml'))"
  1. Confirm the policy file is listed in the configuration:
grep -A5 '<sca>' /var/ossec/etc/ossec.conf
  1. Check the agent logs:
grep sca /var/ossec/logs/ossec.log | tail -20

All Checks Show “Not applicable”

  1. Verify that the requirements section conditions are met. If prerequisites are not satisfied, all checks receive “Not applicable” status.

  2. Check that the paths in variables are correct:

ls -la /etc/ssh/sshd_config
  1. Confirm the policy matches the agent’s operating system.

SCA Results Not Appearing in Dashboard

  1. Verify agent-to-server connectivity:
/var/ossec/bin/agent_control -i <agent_id>
  1. Confirm the indexer is accessible:
curl -sk -u admin:password https://localhost:9200/_cat/indices | grep sca
  1. Check for SCA data in the index:
curl -sk -u admin:password \
  "https://localhost:9200/wazuh-states-vulnerabilities-*/_search?size=1" \
  -H "Content-Type: application/json"

Check Not Recognizing Configuration

  1. Verify the regex pattern is correct:
grep -P 'PermitRootLogin\s+no' /etc/ssh/sshd_config
  1. Note that f: checks match the pattern against each line of the file individually.

  2. For compound conditions (&&), all parts must match within a single line.

Related Sections

Last updated on