Skip to main content

Architecture

This page describes the technical architecture of Guardimesh for platform engineers, security reviewers, and anyone who needs to understand what runs in their cluster and how data flows.

System Overview

Scanner Pod Architecture

Each node in the cluster runs a single scanner pod managed by a DaemonSet. The pod contains five containers that collaborate via shared volumes and Unix sockets:

Container Responsibilities

ContainerPrivilegesPurpose
init: signature-pullerNoneOne-time download of ClamAV signature databases before the antivirus starts
guardimesh-scannerPrivileged, hostPID, host filesystemWatches Kubernetes API for pod events, reads container overlay filesystems, scans /proc for deleted binaries and memfd, sends results to backend
guardimesh-antivirusNoneRuns clamd daemon, accepts scan requests via Unix socket, returns verdicts
guardimesh-inspectorPrivileged, host filesystemProvides container runtime metadata (image layers, overlay paths) via RPC socket; uses crictl or direct runtime queries
guardimesh-pullerNonePeriodically (every 12h) checks for updated signatures from the SaaS storage service
guardimesh-obfuscation-scannerNoneYARA rules, entropy analysis, and ML model for detecting packed/obfuscated binaries

Why Privileged Access?

The scanner and inspector containers require elevated privileges because:

  • Host filesystem mount (/host): Needed to read container overlay filesystems (upperdir) where runtime-written files live
  • Host PID namespace: Required to inspect /proc/[pid]/exe for deleted binary detection and /proc/[pid]/fd for memfd scanning
  • Container runtime access: The inspector queries the container runtime (Docker/CRI-O) to map container IDs to overlay filesystem paths

No other containers in the pod require privileged access.

Data Flow

Scan Result Pipeline

  1. Scanner detects a finding — ClamAV returns a positive verdict, or drift/memfd/deleted-binary detection triggers
  2. Scanner marshals a protobuf — The ClamResult message includes pod name, namespace, image, container ID, and findings (signature name, file path, scan source)
  3. Scanner POSTs to backend-apiContent-Type: application/x-protobuf, authenticated with Authorization: Bearer <API_KEY>, sent over TLS
  4. backend-api validates and republishes — Checks subscription status, node limits, and rate limits. Publishes protobuf bytes to Google Pub/Sub
  5. cr-shipper processes the event — Cloud Function consumes from Pub/Sub, writes to BigQuery via the Storage Write API
  6. notification-shipper fires alerts — If the scan has findings, a separate notification event triggers webhook delivery to configured channels
  7. Web console queries BigQuery — Users view results through the authenticated web console UI

Pod Log Pipeline

Pod metadata (name, namespace, images, node, owner) follows the same pattern via a separate PodLog protobuf message and pl-shipper Cloud Function.

Remote Configuration

The scanner polls GET /api/v1/scan/config from the backend every 5 minutes (configurable). The response includes:

  • Active/scheduled scan toggles
  • Namespace skip lists
  • Feature flags (fanotify enabled/disabled based on subscription tier)
  • Scan deduplication TTL
  • Signature database selections

This allows customers to change scanning behavior from the web console without redeploying the scanner.

Network Requirements

Outbound (cluster to internet)

DestinationPortPurpose
api.guardimesh.io443Scan result ingest, remote config, version checks
storage.guardimesh.io443Signature file downloads
quay.io443Container image pulls (initial install and upgrades)

Intra-cluster

SourceDestinationProtocol
Scanner containerAntivirus containerUnix socket (/clam/clamd.sock)
Scanner containerInspector containerUnix socket
Scanner containerObfuscation scannerUnix socket
Scanner containerKubernetes APIHTTPS (pod watch, metadata)

No inbound connections from the internet are required.

RBAC Requirements

The scanner runs with a ClusterRole that grants:

ResourceVerbsReason
podsget, list, watchMonitor pod creation/deletion events for active scanning
nodesget, listReport node metadata and enforce node limits
namespacesget, listEvaluate namespace skip rules

The operator has additional permissions to manage DaemonSets, Services, and the GuardimeshScanner custom resource.

Signature Update Pipeline

Signatures are refreshed every 12 hours by default. The puller downloads incremental updates (.cdiff files when available) to minimize bandwidth.

High Availability

  • Scanner DaemonSet: One pod per node by design. If a scanner pod crashes, Kubernetes restarts it automatically.
  • Backend API: Multiple replicas behind a load balancer. Scanners retry failed sends with exponential backoff and maintain an in-memory retry buffer (default: 1000 entries).
  • Pub/Sub: Google-managed, highly available message bus with at-least-once delivery.
  • BigQuery: Google-managed, no operational burden.

Air-Gapped Deployments

For environments without internet access, Guardimesh offers an enterprise deployment model using the GuardimeshPlatform custom resource. This deploys the entire stack in-cluster:

  • Backend API (receives scan results locally)
  • Web console (serves UI and queries local database)
  • PostgreSQL (replaces BigQuery)
  • Signature server (serves ClamAV databases from a PVC)

See the Air-Gap Deployment Guide for details.

Next Steps