Air-Gap Deployment Guide
This guide explains how to deploy Guardimesh in air-gapped (disconnected) Kubernetes clusters where nodes have no access to the public internet. This deployment model is available on the Enterprise tier.
Overview
Air-gapped deployments are common in:
- Government and defense installations
- Regulated industries (finance, healthcare)
- Isolated production environments with strict network policies
- Environments behind strict egress firewalls
Guardimesh supports fully disconnected operation through:
- Enterprise Operator — Deploys the full platform stack in-cluster using the
GuardimeshPlatformcustom resource - Internal Signature Server — Serves ClamAV databases from a local PVC (no internet required)
- Local PostgreSQL — Replaces BigQuery for scan result storage
- Self-contained Web Console — UI and API run locally within the cluster
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Air-Gapped Kubernetes Cluster │
│ │
│ ┌────────────────────┐ ┌────────────────────── ┐ │
│ │ Signature Server │ │ PostgreSQL │ │
│ │ (Deployment + PVC) │ │ (StatefulSet + PVC) │ │
│ │ │ │ │ │
│ │ Serves ClamAV │ │ Scan results │ │
│ │ signatures via HTTP │ │ User data │ │
│ └────────────────────┘ └──────────────────────┘ │
│ ↓ ↑ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Scanner DaemonSet (one pod per node) │ │
│ │ │ │
│ │ init-puller → antivirus, scanner, inspector, │ │
│ │ puller (updates every 12h) │ │
│ └────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ backend-api (Scan Data Ingestion) │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ web-console (UI + Session API) │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↑
Admin access via kubectl / Ingress
Prerequisites
Container Images
Pre-load all required images into your private registry:
| Image | Purpose |
|---|---|
quay.io/guardimesh/guardimesh-operator-enterprise:latest | Enterprise operator |
quay.io/guardimesh/web-console:latest | Web console backend + UI |
quay.io/guardimesh/backend-api:latest | Scan data ingest API |
quay.io/guardimesh/storage-access-airgap:latest | Internal signature server |
quay.io/guardimesh/guardimesh-scanner:latest | Scanner |
quay.io/guardimesh/guardimesh-antivirus:latest | ClamAV daemon |
quay.io/guardimesh/guardimesh-inspector:latest | System info collector |
quay.io/guardimesh/guardimesh-puller:latest | Signature puller |
postgres:15-alpine | PostgreSQL database |
Transfer images using your preferred air-gap method (e.g., skopeo copy, docker save/load, or image mirroring tools).
ClamAV Signature Files
Download signature files from an internet-connected machine:
mkdir -p ./clamav-signatures && cd ./clamav-signatures
# Official ClamAV signatures
wget http://database.clamav.net/main.cvd
wget http://database.clamav.net/daily.cvd
wget http://database.clamav.net/bytecode.cvd
# Third-party signatures (optional, recommended)
wget https://sanesecurity.com/signatures/sanesecurity_signature_db.ldb.gz
gunzip sanesecurity_signature_db.ldb.gz
cd ..
tar czf clamav-signatures.tar.gz clamav-signatures/
Transfer the tarball to your air-gapped environment.
Cluster Requirements
- Kubernetes 1.24+ or OpenShift 4.10+
- Storage provisioner (local-path, hostpath, or enterprise storage)
- At least 100 Gi available storage
- Cluster networking configured (CNI plugin installed)
kubectlaccess with cluster-admin permissions
Installation
Step 1: Install the Enterprise Operator
# From pre-downloaded manifests
kubectl apply -f guardimesh-operator-enterprise-manifests.yaml
# Verify
kubectl get pods -n guardimesh-system
Step 2: Create Namespace and Secrets
kubectl create namespace guardimesh
# Admin password
kubectl create secret generic guardimesh-admin-secret \
--from-literal=password='your-secure-admin-password' \
-n guardimesh
# License key (provided by Guardimesh sales)
kubectl create secret generic guardimesh-license \
--from-file=license.key=/path/to/license.key \
-n guardimesh
# API key for scanner authentication
kubectl create secret generic guardimesh-api-key \
--from-literal=api-key='generate-a-random-key-here' \
-n guardimesh
Step 3: Load ClamAV Signatures
tar xzf clamav-signatures.tar.gz
kubectl create configmap clamav-signatures \
--from-file=clamav-signatures/ \
-n guardimesh
Step 4: Deploy GuardimeshPlatform
Create the custom resource:
# guardimesh-airgap.yaml
apiVersion: enterprise.guardimesh.io/v1alpha1
kind: GuardimeshPlatform
metadata:
name: guardimesh
namespace: guardimesh
spec:
console:
replicas: 2
image: your-registry.internal/guardimesh/web-console:latest
resources:
requests:
memory: "512Mi"
cpu: "200m"
api:
replicas: 1
image: your-registry.internal/guardimesh/backend-api:latest
resources:
requests:
memory: "256Mi"
cpu: "100m"
database:
managed: true
storage: 50Gi
storageClass: local-path
resources:
requests:
memory: "1Gi"
cpu: "500m"
backup:
enabled: true
schedule: "0 3 * * *"
retentionDays: 14
storage:
type: pvc
size: 100Gi
ingress:
enabled: false
auth:
adminEmail: admin@internal.local
adminPasswordSecret: guardimesh-admin-secret
license:
mode: local
licenseSecret: guardimesh-license
scanner:
enabled: true
image: your-registry.internal/guardimesh/guardimesh-scanner:latest
antivirusImage: your-registry.internal/guardimesh/guardimesh-antivirus:latest
inspectorImage: your-registry.internal/guardimesh/guardimesh-inspector:latest
pullerImage: your-registry.internal/guardimesh/pull:latest
signatureStorage:
mode: internal
updateInterval: 43200
internalServer:
enabled: true
image: your-registry.internal/guardimesh/storage-access-airgap:latest
storage: 10Gi
storageClass: local-path
replicas: 1
resources:
requests:
memory: "128Mi"
cpu: "100m"
initialSignatures:
configMapName: clamav-signatures
resources:
requests:
memory: "512Mi"
cpu: "200m"
tolerations:
- effect: NoSchedule
operator: Exists
Apply:
kubectl apply -f guardimesh-airgap.yaml
Step 5: Verify Deployment
# Watch platform status
kubectl get guardimeshplatforms -n guardimesh -w
# Expected output after ~5 minutes:
# NAME PHASE CONSOLE API DATABASE AGE
# guardimesh Ready true true true 5m
# Check all pods
kubectl get pods -n guardimesh
# Check scanner DaemonSet
kubectl get daemonset -n guardimesh
Step 6: Access the Console
# Port-forward (if ingress is disabled)
kubectl port-forward -n guardimesh svc/guardimesh-console 8080:80
Open http://localhost:8080 and log in with the admin email and password from Step 2.
Signature Updates
ClamAV signatures should be updated periodically (recommended: monthly or when new threats are identified).
Update Procedure
- On an internet-connected machine, download the latest signatures
- Transfer the files to the air-gapped environment
- Update the ConfigMap or PVC:
# Update ConfigMap method
kubectl create configmap clamav-signatures \
--from-file=clamav-signatures/ \
-n guardimesh \
--dry-run=client -o yaml | kubectl apply -f -
# Restart signature server to pick up changes
kubectl rollout restart deployment/signature-server -n guardimesh
Scanner pods will pull the updated signatures on their next update cycle (within 12 hours) or on restart.
Verifying Signature Updates
# Check signature server has the files
kubectl exec -n guardimesh deployment/signature-server -- ls -lh /signatures/
# Check a scanner pod's ClamAV version and signature dates
SCANNER_POD=$(kubectl get pods -n guardimesh -l app.kubernetes.io/component=guardimesh-scanner -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n guardimesh $SCANNER_POD -c guardimesh-antivirus -- clamdscan --version
Database Backups
Automated backups run according to the schedule in your CR. Manual backup:
kubectl create job -n guardimesh manual-backup-$(date +%Y%m%d) \
--from=cronjob/guardimesh-backup
Upgrading
- Load new container image versions into your private registry
- Update the
GuardimeshPlatformCR with new image tags:
kubectl edit guardimeshplatform guardimesh -n guardimesh
- Monitor the rollout:
kubectl rollout status deployment/guardimesh-console -n guardimesh
kubectl rollout status deployment/guardimesh-backend-api -n guardimesh
kubectl rollout status daemonset/guardimesh-guardimesh-scanner -n guardimesh
Troubleshooting
Signature Server Not Starting
kubectl logs -n guardimesh deployment/signature-server
# Check PVC is bound
kubectl get pvc -n guardimesh signature-storage
# Check ConfigMap has files
kubectl get configmap clamav-signatures -n guardimesh -o jsonpath='{.data}' | head -c 200
Scanner Pods Not Pulling Signatures
# Check puller sidecar logs
kubectl logs -n guardimesh $SCANNER_POD -c guardimesh-signatures
# Verify signature server Service is accessible
kubectl exec -n guardimesh $SCANNER_POD -c guardimesh-scanner -- \
curl -s http://signature-server:8080/health
ClamAV Not Starting
ClamAV requires at least 2 GB RAM for large signature databases. If pods are OOMKilled:
kubectl describe pod $SCANNER_POD -n guardimesh | grep -A5 "Last State"
Increase antivirus container memory limits in the CR.
Database Connection Issues
kubectl get statefulset -n guardimesh
kubectl logs -n guardimesh guardimesh-postgresql-0
Advanced Configuration
Ingress
Enable ingress for browser access without port-forwarding:
spec:
ingress:
enabled: true
hostname: guardimesh.internal.example.com
tls:
enabled: true
secretName: guardimesh-tls-cert
Multiple Signature Server Replicas
For large clusters, run multiple replicas for availability:
spec:
scanner:
signatureStorage:
internalServer:
replicas: 3
Custom Storage Classes
spec:
database:
storageClass: fast-ssd
scanner:
signatureStorage:
internalServer:
storageClass: standard-hdd
Network Requirements (Intra-Cluster Only)
No external internet access is required. All communication is within the cluster:
| Source | Destination | Port | Protocol |
|---|---|---|---|
| Scanner pods | Signature server | 8080 | HTTP |
| Scanner pods | backend-api | 8080 | HTTP |
| Console pods | PostgreSQL | 5432 | TCP |
| backend-api | PostgreSQL | 5432 | TCP |
| Admin | Console (via Ingress/port-forward) | 80/443 | HTTP(S) |
Next Steps
- Configuration Reference — Customize scanning behavior
- Custom Signatures — Add organization-specific detection rules
- Troubleshooting — More debugging steps