feat(qualys/agents): bouton Check + page audit cible Qualys agent (status + version + logs agent/systeme via SSH)
This commit is contained in:
parent
dc9c197274
commit
03229d4d08
@ -1351,3 +1351,19 @@ async def qualys_asset_delete(request: Request, asset_id: int, db=Depends(get_db
|
||||
from app.services.qualys_service import delete_qualys_asset
|
||||
res = delete_qualys_asset(db, asset_id)
|
||||
return JSONResponse(res)
|
||||
|
||||
|
||||
@router.get("/qualys/agents/{hostname}/audit-qualys", response_class=HTMLResponse)
|
||||
def qualys_agent_audit_page(hostname: str, request: Request, db=Depends(get_db)):
|
||||
"""Audit cible Qualys Agent : status service + version + logs (agent + systeme)."""
|
||||
user = get_current_user(request)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login")
|
||||
perms = get_user_perms(db, user)
|
||||
if not can_view(perms, "qualys"):
|
||||
return RedirectResponse(url="/dashboard")
|
||||
from app.services.realtime_audit_service import audit_qualys_agent_only
|
||||
audit = audit_qualys_agent_only(hostname)
|
||||
ctx = base_context(request, db, user)
|
||||
ctx.update({"audit": audit, "hostname": hostname})
|
||||
return templates.TemplateResponse("qualys_agent_audit.html", ctx)
|
||||
|
||||
@ -554,3 +554,63 @@ def save_audit_to_db(db, results):
|
||||
|
||||
db.commit()
|
||||
return updated, inserted
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# AUDIT CIBLE QUALYS AGENT — pour bouton "Check" sur page Agents inactifs
|
||||
# Utilise la meme mecanique de connexion que audit_single_server (DB-driven)
|
||||
# ===========================================================================
|
||||
|
||||
QUALYS_AGENT_CMDS = {
|
||||
"agent_status": "systemctl status qualys-cloud-agent --no-pager 2>&1 | head -25 || /etc/init.d/qualys-cloud-agent status 2>&1 | head -25",
|
||||
"agent_log": "tail -50 /var/log/qualys/qualys-cloud-agent.log 2>/dev/null || tail -50 /var/log/qualys-cloud-agent.log 2>/dev/null || echo \"log Qualys introuvable (chemins testes: /var/log/qualys/*, /var/log/qualys-cloud-agent.log)\"",
|
||||
"system_log": "journalctl -u qualys-cloud-agent --no-pager -n 50 2>/dev/null || tail -50 /var/log/messages 2>/dev/null | grep -i qualys || echo \"journalctl + /var/log/messages indisponibles\"",
|
||||
"agent_version": "/usr/local/qualys/cloud-agent/bin/qualys-cloud-agent.sh -v 2>&1 || rpm -q qualys-cloud-agent 2>/dev/null || echo \"version introuvable\"",
|
||||
}
|
||||
|
||||
|
||||
def audit_qualys_agent_only(hostname):
|
||||
"""Audit cible Qualys Agent uniquement: status service + version + logs.
|
||||
Utilise _resolve + _connect + _run comme audit_single_server.
|
||||
Retourne dict {hostname, status, connection_method, resolved_fqdn, ...cmds}."""
|
||||
result = {
|
||||
"hostname": hostname,
|
||||
"audit_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"status": "PENDING",
|
||||
"connection_method": None,
|
||||
"resolved_fqdn": None,
|
||||
}
|
||||
for k in QUALYS_AGENT_CMDS:
|
||||
result[k] = None
|
||||
|
||||
target = _resolve(hostname)
|
||||
if not target:
|
||||
result["status"] = "CONNECTION_FAILED"
|
||||
result["connection_method"] = f"DNS: aucun suffixe resolu ({hostname})"
|
||||
return result
|
||||
result["resolved_fqdn"] = target
|
||||
|
||||
client = _connect(target, hostname)
|
||||
if not client:
|
||||
result["status"] = "CONNECTION_FAILED"
|
||||
result["connection_method"] = f"SSH: connexion echouee a {target}"
|
||||
return result
|
||||
|
||||
method = _resolve_ssh_method(hostname) or "ssh_key"
|
||||
result["connection_method"] = f"{method} -> {target}"
|
||||
|
||||
try:
|
||||
for key, cmd in QUALYS_AGENT_CMDS.items():
|
||||
result[key] = _run(client, cmd) or "(empty)"
|
||||
result["status"] = "OK"
|
||||
except Exception as e:
|
||||
result["status"] = "ERROR"
|
||||
result["error_msg"] = str(e)
|
||||
finally:
|
||||
try:
|
||||
client.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
||||
67
app/templates/qualys_agent_audit.html
Normal file
67
app/templates/qualys_agent_audit.html
Normal file
@ -0,0 +1,67 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Audit Qualys Agent — {{ hostname }}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<div>
|
||||
<h2 class="text-xl font-bold text-cyber-accent">Audit Qualys Agent</h2>
|
||||
<p class="text-xs text-gray-500 mt-1 font-mono">{{ hostname }}{% if audit.resolved_fqdn %} → {{ audit.resolved_fqdn }}{% endif %}</p>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px">
|
||||
<a href="/qualys/agents/{{ hostname }}/audit-qualys" class="btn-sm bg-cyber-border text-gray-300 px-3 py-2 text-xs">Relancer</a>
|
||||
<a href="/qualys/agents#inactive-list" class="btn-sm bg-cyber-border text-gray-300 px-3 py-2 text-xs">← Retour</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bandeau statut connexion -->
|
||||
<div class="card p-3 mb-4" style="
|
||||
{% if audit.status == 'OK' %}border:1px solid #22c55e;background:rgba(34,197,94,0.08);
|
||||
{% elif audit.status == 'CONNECTION_FAILED' %}border:1px solid #ef4444;background:rgba(239,68,68,0.08);
|
||||
{% else %}border:1px solid #f59e0b;background:rgba(245,158,11,0.08);{% endif %}">
|
||||
<div class="flex justify-between items-center text-xs">
|
||||
<div>
|
||||
<span class="font-bold {% if audit.status == 'OK' %}text-cyber-green{% elif audit.status == 'CONNECTION_FAILED' %}text-cyber-red{% else %}text-cyber-yellow{% endif %}">
|
||||
{% if audit.status == 'OK' %}✓ Connecté{% elif audit.status == 'CONNECTION_FAILED' %}✗ Connexion échouée{% else %}⚠ {{ audit.status }}{% endif %}
|
||||
</span>
|
||||
<span class="text-gray-400 ml-3">{{ audit.connection_method or '-' }}</span>
|
||||
{% if audit.error_msg %}<span class="text-cyber-red ml-3">{{ audit.error_msg }}</span>{% endif %}
|
||||
</div>
|
||||
<span class="text-gray-500 font-mono">{{ audit.audit_date }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if audit.status == 'OK' %}
|
||||
|
||||
<!-- Statut du service -->
|
||||
<div class="card p-4 mb-4">
|
||||
<h3 class="text-sm font-bold text-cyber-accent mb-2">État du service <code class="text-cyber-yellow">qualys-cloud-agent</code></h3>
|
||||
<pre style="background:#0b0f1a;color:#e5e7eb;padding:10px;border-radius:4px;font-size:11px;overflow-x:auto;white-space:pre-wrap">{{ audit.agent_status or '(vide)' }}</pre>
|
||||
</div>
|
||||
|
||||
<!-- Version agent -->
|
||||
<div class="card p-4 mb-4">
|
||||
<h3 class="text-sm font-bold text-cyber-accent mb-2">Version agent</h3>
|
||||
<pre style="background:#0b0f1a;color:#e5e7eb;padding:10px;border-radius:4px;font-size:11px;overflow-x:auto;white-space:pre-wrap">{{ audit.agent_version or '(vide)' }}</pre>
|
||||
</div>
|
||||
|
||||
<!-- Log agent Qualys -->
|
||||
<div class="card p-4 mb-4">
|
||||
<h3 class="text-sm font-bold text-cyber-accent mb-2">Log agent Qualys (50 dernières lignes)</h3>
|
||||
<pre style="background:#0b0f1a;color:#e5e7eb;padding:10px;border-radius:4px;font-size:11px;overflow-x:auto;max-height:400px;white-space:pre-wrap">{{ audit.agent_log or '(vide)' }}</pre>
|
||||
</div>
|
||||
|
||||
<!-- Log système -->
|
||||
<div class="card p-4 mb-4">
|
||||
<h3 class="text-sm font-bold text-cyber-accent mb-2">Log système (journalctl / messages)</h3>
|
||||
<pre style="background:#0b0f1a;color:#e5e7eb;padding:10px;border-radius:4px;font-size:11px;overflow-x:auto;max-height:400px;white-space:pre-wrap">{{ audit.system_log or '(vide)' }}</pre>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="card p-4 mb-4">
|
||||
<p class="text-sm text-gray-400">Impossible de récupérer les informations de l'agent. Vérifie : SSH ouvert (port 22), méthode SSH configurée pour ce serveur dans <a href="/server/{{ hostname }}" class="text-cyber-accent hover:underline">la fiche serveur</a>, agent installé, OS supporté.</p>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
@ -290,6 +290,7 @@ function refreshAgents(mode) {
|
||||
<th class="p-2 sortable" onclick="sortTable(this)">Version agent</th>
|
||||
<th class="p-2 sortable" onclick="sortTable(this)">Dernier check-in</th>
|
||||
<th class="p-2 sortable" onclick="sortTable(this)">État</th>
|
||||
<th class="p-2">Action</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{% for a in inactive_agents %}
|
||||
@ -299,6 +300,7 @@ function refreshAgents(mode) {
|
||||
<td class="p-2 text-center font-mono">{{ a.agent_version or '-' }}</td>
|
||||
<td class="p-2 text-center text-cyber-yellow">{% if a.last_checkin %}{{ (a.last_checkin|string)[:10] }}{% else %}-{% endif %}</td>
|
||||
<td class="p-2 text-center">{{ a.etat or '-' }}</td>
|
||||
<td class="p-2 text-center"><a href="/qualys/agents/{{ a.hostname }}/audit-qualys" class="btn-sm bg-cyber-border text-cyber-accent px-2 py-1 text-xs hover:bg-cyber-hover" title="Audit SSH ciblé : status agent + logs">Check</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user