Firewall Management
Comprehensive guide to Infinibay's firewall system including rules, service presets, and security best practices
Firewall Management
Firewall system for VM network security using libvirt nwfilters.
Overview
Two-tier architecture using libvirt network filters (nwfilter):
- Department filters (
infinibay-dept-{deptId}): Priority 100 - VM filters (
infinibay-vm-{machineId}): Priority 200 - Filter inheritance via
<filterref>elements - Rule evaluation by priority (lower number = higher priority)
Technical implementation: Uses FirewallRule Prisma model with ServicePreset configuration. Rules tracked by origin (DEPARTMENT, VM, SYSTEM) with automatic risk calculation and conflict detection.
Service Presets
Defined in backend/app/config/servicePresets.ts. Presets create FirewallRule records with predefined port/protocol combinations that map to nwfilter XML rules.
Available presets:
- Web:
https(443/TCP),http(80/TCP) - Remote Access:
ssh(22/TCP),rdp(3389/TCP) - Databases:
mysql(3306/TCP),postgresql(5432/TCP),redis(6379/TCP),mongodb(27017/TCP) - Email:
smtp(25/TCP),pop3(110/TCP),imap(143/TCP) - File Sharing:
ftp(21/TCP),sftp(22/TCP),nfs(2049/TCP),smb(445/TCP) - Other:
dns(53/UDP)
Custom Firewall Rules
You can create custom firewall rules for specific use cases:
mutation CreateCustomRule {
createFirewallRule(input: {
vmId: "vm-123"
description: "Allow custom web app"
action: ACCEPT
direction: INBOUND
protocol: TCP
destPortStart: 8080
destPortEnd: 8080
priority: 500
}) {
id
riskLevel
status
}
}
Risk Assessment
Risk calculation algorithm (in FirewallManager service):
- Base score from port number (0-21: HIGH, 22-1023: MEDIUM, 1024+: LOW)
- Protocol factor (UDP +10 points, TCP +0)
- Direction factor (INBOUND +20, OUTBOUND +0)
- Source IP factor (ANY +30, specific IP +0)
- Final mapping: 0-20=MINIMAL, 21-40=LOW, 41-60=MEDIUM, 61+=HIGH
Example: HTTPS inbound from any source = 0 (well-known) + 0 (TCP) + 20 (inbound) + 30 (any) = 50 (MEDIUM)
Conflict Detection
Validation logic in FirewallManager.validateRule():
Hard conflicts (prevented):
- ACCEPT + DROP rules for same port/protocol/direction/source combination
- Query: Compare new rule against existing rules with
action !== newRule.action
Redundancy detection (warning):
- Exact duplicate rules (same port range, protocol, direction, source, action)
- Suggestion: Delete redundant rule
Implementation: Database query compares rule parameters before insert. Conflicts return error with details.
Blocked Connection Tracking
Data flow:
- InfiniService guest agent captures blocked connections via firewall logs
- Sends data to backend via VirtIO channel
- Backend creates
BlockedConnectionmodel records - Suggestion algorithm analyzes patterns (frequent port/IP combinations)
- Auto-generate suggested rules (available via firewall analysis queries)
Retention: 7-day TTL (configurable). Cron job CleanupBlockedConnections.ts runs daily at midnight.
Suggestion algorithm: Group by destPort + protocol, count occurrences, suggest ACCEPT rule if count >10 in 24h.
Department vs VM Rules
Filter Hierarchy
Department filter: infinibay-dept-{deptId} (priority 100, evaluated first)
VM filter: infinibay-vm-{machineId} (priority 200, inherits from department via <filterref>)
Why single filterref: libvirt does NOT support multiple <filterref> per interface. VM filter includes:
<filter name="infinibay-vm-{machineId}" priority="200">
<filterref filter="infinibay-dept-{deptId}"/>
<!-- VM-specific rules here -->
</filter>
Override Mechanism
overridesDepartmentRule: true flag on VM FirewallRule:
- Adds explicit DROP/ACCEPT rule in VM filter
- Takes precedence due to more specific match
- Example: Department allows SSH (22/TCP), VM blocks it with
overridesDepartmentRule: true
Effective Rule Calculation
FirewallManager.getEffectiveRules(vmId):
- Fetch department rules
- Fetch VM rules
- For each VM rule with
overridesDepartmentRule=true, suppress matching dept rule - Merge lists: VM rules + non-overridden dept rules
- Sort by priority
- Return effective ruleset
Filter Architecture
Nwfilter XML Generation
FirewallManager.generateFilterXML() converts FirewallRule records to libvirt nwfilter XML:
Rule translation:
protocol: Maps to<rule>protocol attribute (tcp, udp, icmp)destPortStart/End: Maps to<tcp>or<udp>dstportstart/dstportend attributessourceIP: Maps to srcipaddr attribute (or omitted for ANY)action: Maps to<rule>action attribute (accept, drop, reject)priority: Maps to<rule>priority attribute
Example:
// FirewallRule
{
action: 'ACCEPT',
protocol: 'TCP',
destPortStart: 443,
destPortEnd: 443,
direction: 'INBOUND',
priority: 500
}
// Becomes nwfilter XML
<rule action='accept' direction='in' priority='500'>
<tcp dstportstart='443' dstportend='443'/>
</rule>
Prisma Callbacks
backend/app/utils/modelCallbacks/machine.ts:
On machine create:
afterCreatehook triggersFirewallManager.createFiltersForVM(machineId, departmentId)- Creates department filter if not exists
- Creates VM filter with
<filterref>to department - Calls
nwfilter.defineXML()via libvirt
On machine delete:
beforeDeletehook triggersFirewallManager.deleteFiltersForVM(machineId)- Undefines VM filter via
nwfilter.undefine() - Checks if department filter still needed (other VMs in dept)
On rule change:
- Manual trigger via GraphQL mutation
- Regenerate filter XML
- Call
nwfilter.undefine()+nwfilter.defineXML()(libvirt requires undefine before redefine) - If VM running: mark rules as
status: PENDING, apply on next restart
GraphQL API
Mutations
createFirewallRule: Creates new rule, validates conflicts, generates risk level, returns rule with status
updateFirewallRule: Updates existing rule, re-validates, marks PENDING if VM running
deleteFirewallRule: Deletes rule, regenerates filter XML
toggleServicePreset: Enables/disables preset (creates/deletes associated rules)
Queries
getVMFirewallRules(vmId: ID!): Returns FirewallRuleSetType with:
id: RuleSet IDtype: RuleSetType (VM or DEPARTMENT)entityId: VM IDrules: Array ofFirewallRuleType
getDepartmentFirewallRules(departmentId: ID!): Returns FirewallRuleSetType for department
getEffectiveFirewallRules(vmId: ID!): Returns EffectiveRuleSetType with:
vmRules: VM-specific rulesdepartmentRules: Inherited department ruleseffectiveRules: Computed effective ruleset (VM rules + non-overridden dept rules)conflicts: Array of detected conflictshasPendingChanges: Boolean if VM running with uncommitted changes
See backend/graphql-api.md and backend/app/schema.graphql for authoritative schema.
Pending Changes
Rules created while VM running have status='PENDING':
- GraphQL mutation creates rule in database
- Service checks VM state via libvirt
- If VM running: Set
status='PENDING', skip nwfilter regeneration - UI shows "Restart VM to apply changes" indicator
- On VM restart:
FirewallManagerregenerates nwfilter XML from all rules, setsstatus='ACTIVE'
Rationale: libvirt requires VM shutdown to apply nwfilter changes safely. Hot-reload risks packet drops or connection issues.