Rootless bridge: preserve source IPs via pesto/pasta#28478
Conversation
|
[NON-BLOCKING] Packit jobs failed. @containers/packit-build please check. Everyone else, feel free to ignore. |
1 similar comment
|
[NON-BLOCKING] Packit jobs failed. @containers/packit-build please check. Everyone else, feel free to ignore. |
6fc22c5 to
662445d
Compare
292a7b8 to
9fc6f49
Compare
68bbedb to
f511d44
Compare
|
[NON-BLOCKING] Packit jobs failed. @containers/packit-build please check. Everyone else, feel free to ignore. |
8e04f4b to
50b1e6c
Compare
TODO: vendor container-libs Signed-off-by: Jan Rodák <hony.com@seznam.cz>
Add rootless_port_forwarder="pasta" option that uses pesto to update pasta's forwarding table via UNIX socket, preserving source IPs that rootlessport's userspace proxy masks. HostIP is stripped from port mappings in the netavark wrapper when pasta forwarding is active because pesto handles host-side binding while pasta's splice changes the destination IP that netavark DNAT expects. Pesto binds both 0.0.0.0 and [::] for dual-stack support. Fixes: https://redhat.atlassian.net/browse/RUN-2214 Fixes: containers#8193 Fixes: https://redhat.atlassian.net/browse/RUN-3587 Signed-off-by: Jan Rodák <hony.com@seznam.cz>
Signed-off-by: Jan Rodák <hony.com@seznam.cz>
Signed-off-by: Jan Rodák <hony.com@seznam.cz>
|
|
||
| Any other options will be passed through to netavark without validation. This can be useful to pass arguments to netavark plugins. | ||
|
|
||
| For rootless bridge networks, port forwarding uses `rootlessport` by default. Setting `rootless_port_forwarder="pasta"` in the `[network]` section of **[containers.conf(5)](https://github.com/containers/container-libs/blob/main/common/docs/containers.conf.5.md)** switches to pasta's kernel-level forwarding (via `pesto`), which preserves the original client source IP address inside the container. |
There was a problem hiding this comment.
which should ensure to document the exact pasta behavior is still experimental and subject to change
| if r.config.Network.RootlessPortForwarder == "pasta" { | ||
| err = r.setupRootlessPortMappingViaPesto(ctr) | ||
| } else { | ||
| err = r.setupRootlessPortMappingViaRLK(ctr, ctrNS, netStatus) |
There was a problem hiding this comment.
I would have the switch case over r.config.Network.RootlessPortForwarder here and error on invalid value instead of the main containers.conf validation in common, see my other comment there
| // leak write end to conmon. Pasta forwarding mode does not use | ||
| // rootlessport, so no pipe is needed. | ||
| if rootless.IsRootless() && len(ctr.config.PortMappings) > 0 && | ||
| ctr.runtime.config.Network.RootlessPortForwarder != "pasta" { |
There was a problem hiding this comment.
having these branched to be == "rootlessport" would seem more logic to readers.
Also overall it would be helpful to define both strings as content and use them consistently then to avoid typos and allow code readers easily check of where they are referenced
|
|
||
| // sendMessageToAddr sends a message to the given tcp address (host:port). | ||
| // | ||
| //nolint:unused,nolintlint // only called from linux-only test files, unused on freebsd |
There was a problem hiding this comment.
well then put them into the file where they are used instead of this no lint thing
| } | ||
| } | ||
|
|
||
| It("podman run bridge network preserves source IP", func() { |
There was a problem hiding this comment.
I am not sure about all of these tests
for source ip we have podman networking: port with --userns=keep-id for rootless or --uidmap=* for rootful system test
And in general we have a ton of other networking tests already, I rather not duplicate a bunch of slightly different cases.
If we want to test this then we likely want to create a loop over selected existing network tests that run twice with both rootlessport/pasta
| // (source == bridge gateway) is gone. | ||
| // | ||
| // The exact mapped address is a pasta implementation detail. | ||
| Expect(output).ToNot(MatchRegexp(`connect to .* from .*` + subnetPrefix)) |
There was a problem hiding this comment.
that does not seem to match this though..., it is the exact inverse from the other case below...
Require passta version:
This requires the
pestobinary, available sincepasst-0^20260507.g1afd4ed.Local Passt Setup + testing
TODO:
Add
rootless_port_forwarder="pasta"option incontainers.confthat switches rootless bridge port forwarding fromrootlessporttopasta, preserving source IPs. The default remainsrootlessport.Problem
When running rootless containers on a bridge network (
podman run -p 8080:80 --network mynet), the oldrootlessportuserspace TCP/UDP proxy destroyed source IP information. Every connection appeared to come from127.0.0.1inside the container, regardless of the actual client IP.Solution
Pesto is a client tool for
passtathat dynamically updates port forwarding rules via a UNIX domain socket. Instead of proxying traffic in userspace (which loses source IPs), pesto configurespastato forward at the kernel level using splice (localhost) or TAP (external traffic), preserving the original source IP.How it works
pastainstance runs in the rootless network namespace with a control socket (-c pasta.sock)pesto --addregisters ports in pasta's forwarding tablepesto --deleteremoves the container's ports, then netavark tears down bridge/DNATKey implementation details:
convertNetOpts): whenrootless_port_forwarder="pasta"is active, HostIP is stripped from port mappings before passing to netavark. Pesto handles host-side address binding; netavark's DNAT rules inside the rootless netns must not restrict on destination address since pasta's splice delivers traffic with a different destination than the user-specified HostIP0.0.0.0and[::]so IPv6 networks work out of the boxrootless_port_forwarderin[network]section ofcontainers.confselects betweenrootlessport(default) andpastaCurrent limitations
-p 127.0.0.1:8080:80and-p 127.0.0.2:8080:80on separate containers) does not work in pasta mode because HostIP stripping causes conflicting DNAT rules. This requires destination mapping support in pesto.Fixes: https://redhat.atlassian.net/browse/RUN-2214
Fixes: #8193
Fixes: https://redhat.atlassian.net/browse/RUN-3587
Depends on:
passt >= passt-0^20260507.g1afd4edDepends on: containers/container-libs#755
Depends on: #27828
Depends on: #28451
Checklist
Ensure you have completed the following checklist for your pull request to be reviewed:
commits. (
git commit -s). (If needed, usegit commit -s --amend). The author email must matchthe sign-off email address. See CONTRIBUTING.md
for more information.
Fixes: #00000in commit message (if applicable)make validatepr(format/lint checks)Noneif no user-facing changes)Does this PR introduce a user-facing change?