Fix CISA access and publish scanner recovery/status events
This commit is contained in:
+35
-15
@@ -20,6 +20,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):
|
||||
@@ -88,21 +111,16 @@ def kev_catalog():
|
||||
now = time.time()
|
||||
error = None
|
||||
if now - cached.get('fetched_at', 0) >= 86400:
|
||||
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)
|
||||
except Exception:
|
||||
error = 'KEV refresh failed; cached information may be incomplete'
|
||||
for url in KEV_URLS:
|
||||
try:
|
||||
updated = fetch_kev(url, now)
|
||||
atomic_json(path, updated)
|
||||
cached = updated
|
||||
break
|
||||
except Exception:
|
||||
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'
|
||||
@@ -237,6 +255,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,
|
||||
|
||||
Reference in New Issue
Block a user