Repair official CISA fallback and preserve scan recovery in the installer

This commit is contained in:
2026-10-04 14:41:38 +02:00
parent e728d74686
commit 87771e6c1d
+43 -17
View File
@@ -164,7 +164,7 @@ if [[ $MODE == host ]]; then
fi
fi
if [[ $MODE == manager ]]; then
ask 'Auf diesem Manager werden die JSON-Regeln 110800-110805 ergaenzt und Wazuh neu gestartet. Bestehende Regeln/Discord-Einstellungen bleiben erhalten. Bitte INSTALL eingeben:'
ask 'Auf diesem Manager werden die JSON-Regeln 110800-110806 ergaenzt und Wazuh neu gestartet. Bestehende Regeln/Discord-Einstellungen bleiben erhalten. Bitte INSTALL eingeben:'
else
ask "Auf diesem Docker-Host einrichten: Listener=$(yesno_label "$LISTENER"), Image-Scans=$(yesno_label "$SCANS"), Abstand=${HOURS}h, Umfang=$SCOPE. Der Wazuh-Agent wird neu gestartet; Docker-Container bleiben in Betrieb. Bitte INSTALL eingeben:"
fi
@@ -301,6 +301,29 @@ CONFIG = Path('/etc/wazuh-docker-security/config.json')
LOG = Path('/var/log/wazuh-docker-security/events.jsonl')
SOCKET = 'unix:///var/run/docker.sock'
KEV_URL = 'https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json'
KEV_URLS = (KEV_URL, 'https://raw.githubusercontent.com/cisagov/kev-data/main/known_exploited_vulnerabilities.json')
def fetch_kev(url, now):
"""Only publisher-controlled sources; reject invalid/old mirror snapshots."""
request = urllib.request.Request(url, headers={'User-Agent': 'wazuh-docker-security/1'})
with urllib.request.urlopen(request, timeout=15) as response:
raw = response.read(12 * 1024 * 1024 + 1)
if len(raw) > 12 * 1024 * 1024:
raise ValueError('KEV response too large')
document = json.loads(raw)
published = dt.datetime.fromisoformat(document['dateReleased'].replace('Z', '+00:00')).timestamp()
if not -86400 <= now - published <= 14 * 86400:
raise ValueError('KEV publication timestamp outside freshness window')
entries = document['vulnerabilities']
if document.get('count') != len(entries):
raise ValueError('incomplete KEV catalog')
ids = sorted({v['cveID'] for v in entries
if re.fullmatch(r'CVE-\d{4}-\d{4,}', v.get('cveID', ''))})
if not ids or len(ids) != len(entries):
raise ValueError('empty or invalid KEV catalog')
return {'fetched_at': now, 'published_at': published, 'ids': ids,
'catalog_version': document.get('catalogVersion'), 'source': url}
def atomic_json(path, data):
@@ -369,21 +392,16 @@ def kev_catalog():
now = time.time()
error = None
if now - cached.get('fetched_at', 0) >= 86400:
for url in KEV_URLS:
try:
request = urllib.request.Request(KEV_URL, headers={'User-Agent': 'wazuh-docker-security/1'})
with urllib.request.urlopen(request, timeout=30) as response:
raw = response.read(12 * 1024 * 1024 + 1)
if len(raw) > 12 * 1024 * 1024:
raise ValueError('KEV response too large')
document = json.loads(raw)
ids = sorted({v['cveID'] for v in document['vulnerabilities']
if re.fullmatch(r'CVE-\d{4}-\d{4,}', v.get('cveID', ''))})
if not ids:
raise ValueError('empty KEV catalog')
cached = {'fetched_at': now, 'ids': ids}
atomic_json(path, cached)
updated = fetch_kev(url, now)
atomic_json(path, updated)
cached = updated
break
except Exception:
error = 'KEV refresh failed; cached information may be incomplete'
continue
else:
error = 'KEV refresh failed on both official sources; cached information may be incomplete'
fresh = now - cached.get('fetched_at', 0) <= 7 * 86400
if not fresh:
error = 'KEV catalog unavailable or older than seven days'
@@ -518,6 +536,8 @@ def main():
for key in state['health']:
if key not in errors:
events.append({'event': 'scan_recovered', 'component': key})
events.append({'event': 'scan_status', 'complete': 'yes' if inventory_ok and not any(k.startswith('image:') for k in errors) else 'no',
'kev_fresh': 'yes' if fresh else 'no', 'problem_count': len(errors)})
append_events(events)
atomic_json(state_path, {'findings': merged, 'health': errors, 'last_scan': time.time()})
atomic_json(BASE / 'inventory.json', {'updated_at': time.time(), 'scope': scope,
@@ -535,7 +555,7 @@ if __name__ == '__main__':
raise SystemExit(main())
SCAN_PY
cat >"$TMP/rules.xml" <<'RULES_XML'
<!-- Managed by wazuh-docker-security; custom range 110800-110805. -->
<!-- Managed by wazuh-docker-security; custom range 110800-110806. -->
<group name="docker_security,trivy,">
<rule id="110800" level="0">
<decoded_as>json</decoded_as>
@@ -562,16 +582,22 @@ cat >"$TMP/rules.xml" <<'RULES_XML'
<description>Docker image scanner needs attention: $(component): $(message).</description>
<group>docker_security_health,</group>
</rule>
<rule id="110804" level="0">
<rule id="110804" level="3">
<if_sid>110800</if_sid>
<field name="event" type="pcre2">^finding_(cleared|out_of_scope)$</field>
<description>Image finding cleared or no longer in scan scope.</description>
</rule>
<rule id="110805" level="0">
<rule id="110805" level="3">
<if_sid>110800</if_sid>
<field name="event">^scan_recovered$</field>
<description>Scanner component recovered.</description>
</rule>
<rule id="110806" level="3">
<if_sid>110800</if_sid>
<field name="event">^scan_status$</field>
<description>Image scanner status: complete=$(complete), fresh KEV=$(kev_fresh), problems=$(problem_count).</description>
<group>docker_security_status,</group>
</rule>
</group>
RULES_XML
BACKUP=/var/backups/wazuh-docker-security/$(date +%Y%m%d-%H%M%S)-$$