feat: add persistence and audit trails
This commit is contained in:
1 parent
d381c02946
commit
2f2e9ab3e3
9 files changed
+633
-151
No files matched your search
+30
-2
@@ -4,11 +4,14 @@ import shlex
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import Iterable, List, Optional
|
||||
|
||||
import psutil
|
||||
|
||||
from app.policy import TunnelPolicy
|
||||
from app.storage import Storage
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServiceRecord:
|
||||
@@ -20,13 +23,22 @@ class ServiceRecord:
|
||||
command: Optional[str]
|
||||
container: Optional[str]
|
||||
local_address: str
|
||||
allowed: bool = True
|
||||
policy_reason: Optional[str] = None
|
||||
|
||||
|
||||
class PortScanner:
|
||||
def __init__(self, cache_ttl: float = 2.0) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
cache_ttl: float = 2.0,
|
||||
policy: TunnelPolicy | None = None,
|
||||
storage: Storage | None = None,
|
||||
) -> None:
|
||||
self._cache_ttl = cache_ttl
|
||||
self._last_scan = 0.0
|
||||
self._cache: List[ServiceRecord] = []
|
||||
self._policy = policy
|
||||
self._storage = storage
|
||||
|
||||
def scan(self) -> List[ServiceRecord]:
|
||||
now = time.monotonic()
|
||||
@@ -68,6 +80,10 @@ class PortScanner:
|
||||
process_command = _format_commandline(raw_command)
|
||||
local_address = f"{conn.laddr.ip}:{conn.laddr.port}"
|
||||
container = _container_name_for_pid(pid, container_names) if pid else None
|
||||
allowed = True
|
||||
reason: Optional[str] = None
|
||||
if self._policy:
|
||||
allowed, reason = self._policy.is_port_allowed(port)
|
||||
|
||||
results.append(
|
||||
ServiceRecord(
|
||||
@@ -79,11 +95,23 @@ class PortScanner:
|
||||
command=process_command,
|
||||
container=container,
|
||||
local_address=local_address,
|
||||
allowed=allowed,
|
||||
policy_reason=reason,
|
||||
)
|
||||
)
|
||||
|
||||
self._persist_services(results)
|
||||
return results
|
||||
|
||||
def _persist_services(self, records: List[ServiceRecord]) -> None:
|
||||
if not self._storage:
|
||||
return
|
||||
payload = [asdict(record) for record in records]
|
||||
try:
|
||||
self._storage.record_services(payload)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _protocol_for_conn(sock_type: int) -> str:
|
||||
if sock_type == socket.SOCK_STREAM:
|
||||
|
||||
Reference in new issue
Block a user