I have just setup an IncusOS server (version: 202608021451), which, to my understanding, includes nftables for firewall rules.
Now, according to Stéphane it should be possible by now to create ACLs within a bridge network that isolate instances against each other (since the referenced PR has been merged by now), but my attempts to do so fail in weird ways.
Here’s what I did:
Preparations
# I created a public-only ACL
$ incus network acl show remote:public-only
name: public-only
description: ""
egress:
- action: allow
state: enabled
- action: allow
destination: 172.17.1.0/24
state: enabled
- action: reject
destination: 10.0.0.0/8
state: enabled
- action: reject
destination: 192.168.0.0/16
state: enabled
- action: reject
destination: 172.16.0.0/12
state: enabled
ingress:
- action: allow
state: enabled
config: {}
used_by: []
project: default
# I have a bridge network called incusbr0, that is attached to the default profile
$ incus network show remote:incusbr0
config:
ipv4.address: 10.90.234.1/24
ipv4.dhcp: "true"
ipv4.nat: "true"
ipv6.address: fd42:1ad5:80a0:c467::1/64
ipv6.nat: "true"
security.acls.default.egress.action: allow
security.acls.default.ingress.action: reject
description: Local network bridge (NAT)
name: incusbr0
type: bridge
used_by:
- /1.0/profiles/default
managed: true
status: Created
locations:
- none
project: default
# And here's the default profile
$ incus profile show remote:default
config: {}
description: Default Incus profile
devices:
eth0:
network: incusbr0
security.acls.default.egress.action: allow
security.acls.default.ingress.action: allow
type: nic
root:
path: /
pool: local
type: disk
name: default
used_by: []
project: default
Attempt 1 - network level
First, I tried to attach the ACL to the network itself:
# Attach ACL
$ incus network set remote:incusbr0 security.acls=public-only
# Create test instances
incus launch images:almalinux/10/default remote:alma-test1 --profile default
incus launch images:almalinux/10/default remote:alma-test2 --profile default
# Verify the network is used by those instances
$ incus network show remote:incusbr0
config:
ipv4.address: 10.90.234.1/24
ipv4.dhcp: "true"
ipv4.nat: "true"
ipv6.address: fd42:1ad5:80a0:c467::1/64
ipv6.nat: "true"
security.acls: public-only
security.acls.default.egress.action: allow
security.acls.default.ingress.action: reject
description: Local network bridge (NAT)
name: incusbr0
type: bridge
used_by:
- /1.0/instances/alma-test1
- /1.0/instances/alma-test2
managed: true
status: Created
locations:
- none
project: default
# Verify the ACL is used by the network
$ incus network acl show remote:public-only
name: public-only
description: ""
egress:
- action: allow
state: enabled
- action: allow
destination: 172.17.1.0/24
state: enabled
- action: reject
destination: 10.0.0.0/8
state: enabled
- action: reject
destination: 192.168.0.0/16
state: enabled
- action: reject
destination: 172.16.0.0/12
state: enabled
ingress:
- action: allow
state: enabled
config: {}
used_by:
- /1.0/networks/incusbr0
project: default
However, in this case, the ACL does not seem to have an effect whatsoever:
# Test if alma-test2 can be reached
$ incus exec remote:alma-test1 -- ping -c 3 10.90.234.92
PING 10.90.234.92 (10.90.234.92) 56(84) bytes of data.
64 bytes from 10.90.234.92: icmp_seq=1 ttl=64 time=0.071 ms
64 bytes from 10.90.234.92: icmp_seq=2 ttl=64 time=0.081 ms
64 bytes from 10.90.234.92: icmp_seq=3 ttl=64 time=0.083 ms
--- 10.90.234.92 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2088ms
rtt min/avg/max/mdev = 0.071/0.078/0.083/0.005 ms
# Test if outgoing traffic is possible (cloudflare IP)
$ incus exec remote:alma-test1 -- ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=58 time=1.43 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=58 time=1.65 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=58 time=1.53 ms
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 1.426/1.536/1.652/0.092 ms
So this doesn’t work. Next on to instance/profile NIC level ACLs
Attempt 2 - ACL on instance NIC level
# Remove the network level ACL
$ incus network set remote:incusbr0 security.acls=
# Overwrite the device configuration for the test instance (the rules are egress rules, so I'm only overwriting the one where I'm running the commands)
# Note: I changed this via IncusUI, because I wasn't sure what the command would be for this
$ incus config show remote:alma-test1
architecture: x86_64
config:
# [...]
devices:
eth0:
network: incusbr0
security.acls: public-only
type: nic
ephemeral: false
profiles:
- default
stateful: false
description: ""
Now, all egress traffic seems to be blocked (not just internal):
# Test if alma-test2 can be reached
$ incus exec remote:alma-test1 -- ping -c 3 10.90.234.92
PING 10.90.234.92 (10.90.234.92) 56(84) bytes of data.
--- 10.90.234.92 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2035ms
# Test if outgoing traffic is possible (cloudflare IP)
$ incus exec remote:alma-test1 -- ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2076ms
What’s weirder, outgoing traffic seems to be blocked for all instances (within the bridge network?), not just the one that has the ACL attached:
# Test if alma-test1 can be reached from alma-test2
$ incus exec remote:alma-test2 -- ping -c 3 10.90.234.6
PING 10.90.234.6 (10.90.234.6) 56(84) bytes of data.
64 bytes from 10.90.234.6: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from 10.90.234.6: icmp_seq=2 ttl=64 time=0.093 ms
64 bytes from 10.90.234.6: icmp_seq=3 ttl=64 time=0.097 ms
--- 10.90.234.6 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2045ms
rtt min/avg/max/mdev = 0.023/0.071/0.097/0.033 ms
# Test if outgoing traffic is possible (cloudflare IP)
$ incus exec remote:alma-test2 -- ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2051ms
Just to verify, I removed the ACL and tested connectivity again:
# alma-test1 after removing the ACL:
architecture: x86_64
config:
# [...]
devices:
eth0:
network: incusbr0
type: nic
ephemeral: false
profiles:
- default
stateful: false
description: ""
# Test if alma-test1 can be reached from alma-test1
$ incus exec remote:alma-test1 -- ping -c 3 10.90.234.92
PING 10.90.234.92 (10.90.234.92) 56(84) bytes of data.
64 bytes from 10.90.234.92: icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from 10.90.234.92: icmp_seq=2 ttl=64 time=0.084 ms
64 bytes from 10.90.234.92: icmp_seq=3 ttl=64 time=0.082 ms
--- 10.90.234.92 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2067ms
rtt min/avg/max/mdev = 0.019/0.061/0.084/0.030 ms
# Test if outgoing traffic is possible (cloudflare IP) from alma-test1
$ incus exec remote:alma-test1 -- ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=58 time=1.36 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=58 time=1.56 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=58 time=1.51 ms
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 1.360/1.478/1.562/0.086 ms
# Test if alma-test1 can be reached from alma-test2
$ incus exec remote:alma-test2 -- ping -c 3 10.90.234.6
PING 10.90.234.6 (10.90.234.6) 56(84) bytes of data.
64 bytes from 10.90.234.6: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from 10.90.234.6: icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from 10.90.234.6: icmp_seq=3 ttl=64 time=0.083 ms
--- 10.90.234.6 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2065ms
rtt min/avg/max/mdev = 0.023/0.063/0.083/0.028 ms
# Test if outgoing traffic is possible (cloudflare IP) from alma-test2
$ incus exec remote:alma-test2 -- ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=58 time=1.45 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=58 time=1.50 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=58 time=1.51 ms
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 1.449/1.486/1.511/0.026 ms
I must be missing something essential here, because this doesn’t make any sense to me.