Where
The page documenting that Docker Engine (28/29) protects unpublished
container addresses via raw/PREROUTING DROP rules
(https://docs.docker.com/engine/network/packet-filtering-firewalls/ /
port-publishing behaviour).
What's missing
The docs correctly explain the protection and that raw is evaluated before
nat and DOCKER-USER. What they don't mention is a now-common interaction:
When a Kubernetes CNI (e.g. Cilium) translates Service VIPs to backend
container addresses in its own datapath before netfilter, packets arrive
at raw/PREROUTING already addressed to the unpublished container. Docker's
protection then legitimately drops them — before any DOCKER-USER
allowance can apply. Operators reasonably expect DOCKER-USER to be the
boundary for such flows; here it is never reached.
Suggested addition
A short note on the protection page: if another datapath (a CNI, or any
pre-netfilter DNAT) delivers traffic already addressed to an unpublished
container, that traffic is subject to the raw protection and cannot be
re-permitted in DOCKER-USER; the exception must be expressed in raw.
This is intended behaviour, but surprising and currently undocumented.
I can open a docs PR with the note if you'd like.
Reproduction + diagnostic + full field report:
https://github.com/Verbano-stack/k3s-cilium-docker-raw-boundary
https://verbano.tech/en/engineering/k3s-cilium-docker-compose-clusterip-timeouts/
Where
The page documenting that Docker Engine (28/29) protects unpublished
container addresses via
raw/PREROUTINGDROP rules(https://docs.docker.com/engine/network/packet-filtering-firewalls/ /
port-publishing behaviour).
What's missing
The docs correctly explain the protection and that
rawis evaluated beforenatandDOCKER-USER. What they don't mention is a now-common interaction:When a Kubernetes CNI (e.g. Cilium) translates Service VIPs to backend
container addresses in its own datapath before netfilter, packets arrive
at
raw/PREROUTINGalready addressed to the unpublished container. Docker'sprotection then legitimately drops them — before any
DOCKER-USERallowance can apply. Operators reasonably expect
DOCKER-USERto be theboundary for such flows; here it is never reached.
Suggested addition
A short note on the protection page: if another datapath (a CNI, or any
pre-netfilter DNAT) delivers traffic already addressed to an unpublished
container, that traffic is subject to the
rawprotection and cannot bere-permitted in
DOCKER-USER; the exception must be expressed inraw.This is intended behaviour, but surprising and currently undocumented.
I can open a docs PR with the note if you'd like.
Reproduction + diagnostic + full field report:
https://github.com/Verbano-stack/k3s-cilium-docker-raw-boundary
https://verbano.tech/en/engineering/k3s-cilium-docker-compose-clusterip-timeouts/