I found a solution: As a post-installation task (after
lxd init), the LXD interface must be explicitly assigned to a firewalld zone, most simply zone “trusted” for a network of trusted containers (or another zone that allows DHCP and DNS). This is required if LXD is running in a CentOS libvirt based VM or a corresponding libvirt root host. I have not yet tested how it works in a standard CentOS 8 host.
The same applies to Fedora, version 31.
firewall-cmd --add-interface=lxdbr0 --zone=trusted --permanent
When booting the host and firewalld is initialized, the LXD interface does not yet exist. And firewalld obviously now blocks all traffic to unknown interfaces. This is probably a change from CentOS 7 to CentOS 8 (or libvirt versions). Fortunately the manual assignment is preserved during a reboot.
In the long term, LXD should implement a similar solution to the libvirt project. There, a separate firewalld zone “libvirt” is created during installation (if firewalld is detected) and each virtual bridge is assigned to this zone by default. There is also a parameter to assign a virtual bridge to a preferred firewalld zone (“zone=” in tag <bridge … />), So we need a parameter like "bridge.firewalld.zone= … ". Unfortunately I have no idea about go and can’t contribute a patch myself.