This guide explains how firewall rules control network access to and from virtual machines in Kubermatic Virtualization, and how to manage them from the dashboard.
A firewall rule controls which traffic may reach a virtual machine, and which traffic that machine may send. Every rule sets four things:
| Part | What it sets |
|---|---|
| Direction | Inbound or outbound. |
| Target | The VM or VM pool the rule applies to. |
| Source / Destination | Where the traffic comes from, or goes to. |
| Ports and protocols | What the rule permits. |
Manage rules from the Firewalls page. Each VM also lists the rules that apply to it on its own Networking tab.
Behind each rule is a Kubernetes NetworkPolicy in the VM’s namespace, labelled
kubevirt-manager.io/managed=true. The Firewalls list shows the policies carrying that
label, including ones too detailed for the form — see
Rules that open as YAML.
Two things matter more than any individual setting:
Rules allow traffic. There is no deny rule. You open what you need, and everything else stays closed.
Rules are additive. When several rules target the same VM, traffic is permitted if any of them allows it. Adding a rule opens more traffic, never less.
So to restrict a VM, turn its firewall on and then add rules for what you want to permit. The switch covers inbound traffic; for the other direction see Outbound rules and DNS.
Open the VM, go to the Networking tab, and use the Firewall switch.
| Switch | What it means |
|---|---|
| Off | The VM accepts all inbound traffic. This is the default for a new VM. |
| On | Inbound traffic is blocked unless one of the VM’s rules allows it. |
| Unavailable | The VM was created outside this dashboard, so it does not carry the label firewall rules select on. See Which VMs can be targeted. |
Switching it on creates a policy named <vm-name>-vm-default-deny, listed under
Firewalls as Default deny. Switching it off deletes that policy again, and so does
deleting the row from the Firewalls list. The delete dialog tells you what to expect first:
either the VM opens to all inbound traffic, or it stays closed because other inbound rules
still apply.
The switch covers inbound traffic only. What the VM sends stays unrestricted until you add an outbound rule.
A VM also closes as soon as you add its first inbound rule, even with the switch off — that is how Kubernetes network policies work. The Networking tab tells you when a VM is closed this way, and deleting that last rule opens it again. Use the switch when you want the VM closed deliberately and kept that way, whatever happens to its rules.
Go to Firewalls and choose New Firewall Rule.
| Field | What it does |
|---|---|
| Name | Identifies the rule. Lowercase letters, numbers and hyphens, fixed once created. Names ending in -default-deny or -allow-dns are reserved for the policies the platform manages. |
| Direction | Inbound controls traffic arriving at the target. Outbound controls traffic the target sends. |
| Target Type / Target | The VM or VM pool the rule applies to: the receiver for an inbound rule, the sender for an outbound one. |
| Source / Destination | Where the traffic comes from or goes to. See the table below. |
| All ports | Allow every port for the chosen peer, instead of listing them. |
| From port / To port / Protocol | The ports to permit. Leave To port empty for a single port, or set it for a range. |
| Strict enforcement | See Ping and DHCP. Leave this off unless you need full isolation. |
| Labels | Optional labels for your own grouping. The fw.kubevirt-manager.io/ prefix is reserved for the platform. |
The source or destination can be:
| Type | Matches |
|---|---|
| IP range | A CIDR, such as 10.0.0.0/8 or 2001:db8::/32. |
| Virtual Machine / VM Pool | Another VM or pool in the same namespace. |
| Namespace | Every workload in the named namespace. |
| Anywhere | Any address. Use this to open a port to the world. |
When a rule is the one that closes its target, the form says so before you save: the target “allows all inbound traffic today” (or outbound), and afterwards anything not listed below is blocked. A target already closed in that direction — by the Firewall switch, or by an earlier rule — needs no such warning, so you do not see it again.
Set From port and To port for a contiguous range, for example 30000 to 32767
for Kubernetes NodePorts. Leave To port empty for a single port.
Add a row for each further port or protocol, up to eight rows per rule. Need more? Put them in a second rule against the same target — rules are additive, so the two add up.
New rules use a relaxed enforcement mode, which filters TCP, UDP and SCTP and lets
other IP traffic through. That keeps ping and DHCP working on a firewalled VM whatever
the rules say, which is almost always what you want:
TCP, UDP and SCTP, so no port row can describe
ping.Tick Strict enforcement when you need complete isolation. It blocks every IP protocol except what the rules permit, ping and DHCP included.
| Mode | Enforces | Stored as |
|---|---|---|
| Relaxed (default) | The rules, on TCP, UDP and SCTP. Other IP traffic — ping included — is allowed. |
Annotation ovn.kubernetes.io/network_policy_enforcement: "lax" on the policy |
| Strict | The rules alone, on every IP protocol | No such annotation |
Relaxed and strict are a Kube-OVN feature. What a policy without the annotation means is set
cluster-wide by the Kube-OVN controller’s --np-enforcement flag, which defaults to
standard — the setting that makes such a rule strict. Confirm it before relying on a strict
rule for isolation:
kubectl -n kube-system get deploy kube-ovn-controller \
-o jsonpath='{.spec.template.spec.containers[0].args}' | tr ',' '\n' | grep np-enforcement
An outbound rule permits what it lists and closes everything else the target sends — DNS
queries included, which would leave the VM unable to resolve names. So the first outbound
rule you create for a target comes with a companion policy that keeps DNS working, named
<vm-name>-vm-allow-dns (or <pool-name>-pool-allow-dns for a pool) and listed as
System DNS.
The platform maintains it for you, and View YAML shows what it allows. Deleting the target’s last outbound rule removes it automatically. You can also delete it from the Firewalls list yourself, where the dialog tells you what the removal will do.
Use the actions menu on any rule to edit it in the form, view or edit its YAML, or delete it. System rows — Default deny and System DNS — offer View YAML and Delete, since the platform keeps their contents in step with your rules.
A rule’s name, direction and target are fixed once created. Opening a rule for editing shows those fields greyed out, and the form says why: “Name, direction and target identify a rule and cannot be changed. Delete this rule and create a new one to move it.” To rename or retarget a rule, create a replacement and delete the original.
Deleting tells you what will change before you confirm — that a VM will accept all inbound traffic again because this was its last inbound rule, for example, or that a system DNS allowance goes with the outbound rule that needed it.
Saving the form rebuilds the policy from the fields on screen, and what you see is the whole rule: the port rows and the one source or destination are all of it. Labels and annotations already on the policy are carried over.
Both editors work from the version they fetched when you opened the rule, so a rule someone changed in the meantime is never silently overwritten. The form reports “This rule changed since you opened it — reload and reapply your edit”. The YAML editor offers a Load latest version button, which re-fetches the rule so you can redo your change on top of it.
The form covers one direction, one target, one peer and a list of ports — what the Firewalls
table can display accurately. A rule beyond that opens in the YAML editor instead: several
sources in one rule, several rule blocks, ipBlock exceptions, or named ports. The cluster
enforces those policies as usual, the list keeps showing them, and the YAML editor is where
you change them.
Because rules are additive, anything you can express as several simple rules is best written that way.
To confirm a rule is enforced, send traffic from a source that should be allowed and from one that should not, then check the policy behind it:
kubectl -n <namespace> get networkpolicy <rule-name> -o yaml
A rule that matches no VM is still created, and then has nothing to act on. The form tells you which case you are in while you are still filling it in, underneath the Target field:
| Message | Meaning |
|---|---|
| “Applies to 1 virtual machine.” | The rule will be enforced. |
| “Matches no virtual machine — this rule will have no effect until one exists.” | No VM of that name exists in the namespace yet. Check the name for a typo. |
| “This virtual machine cannot be targeted by a firewall rule: it was not created here, so it does not carry the label rules select on.” | See Which VMs can be targeted. |
This line covers Virtual Machine targets. For a VM pool, check the pool name as you type
it and confirm the policy afterwards with the kubectl command above.
A firewall rule selects VMs by the label fw.kubevirt-manager.io/vm-name, whose value is the
VM’s own name. The dashboard sets it on spec.template.metadata.labels, so the VM’s pod
carries it and a policy’s podSelector matches. A VM created another way — by kubectl, a
manifest, or an import — has no such label yet, and its Firewall switch reads
Unavailable.
Add the label to bring such a VM into scope:
kubectl -n <namespace> patch virtualmachine <vm-name> --type=merge \
-p '{"spec":{"template":{"metadata":{"labels":{"fw.kubevirt-manager.io/vm-name":"<vm-name>"}}}}}'
The value has to equal the VM’s name, since that is what a rule’s selector is built from. The label lands on the pod template, so restart the VM for its running pod to pick it up.
VM pools work the same way, with fw.kubevirt-manager.io/pool-name carrying the pool’s name.
For a pool the label belongs on spec.virtualMachineTemplate.spec.template.metadata.labels.