This is my first time asking something on stackoverflow. For years I’ve been lurking but now I decided to finally register myself. Hence, I apologize if my question/information is not formatted nicely.
Current situation:
I’m slowly getting more and more familiar with Podman and I’m in the process of moving some of my containers over from docker (rootful) to podman (rootless). I’m using Podman 4.3.1 on Debian 11. I’ve managed to get some containers working and was able to externally connect to them. However, the container shows client/source ip ‘127.0.0.1’ instead of my real client’s IPv4. I was wondering whether something like the following is possible?
Ideal situation:
Assigning a specific IPv4 to the container (rootless). Using nftables/iptables to forward packets from the host’s network to the containers ipv4 (e.g. 192.168.1.12). Being able to see the real client’s IPv4 in the container to still be able use fail2ban etc.
As you may notice, I’m still very much in the process of learning how containerization works and specifically for networking. I don’t want to use the hosts network for my container for security reasons. If something is unclear tell me and I’ll try to better explain myself.
Thanks for taking your time to read this 🙂
2
Answers
When you’re running Podman as a non-root user, the virtual tap device that represents the container’s
eth0
interface can’t be attached directly to a bridge device. This means it’s not possible to use netfilter rules to direct traffic into the container; instead, Podman relies on a proxy process.There are some notes on this configuration here.
By default, Podman uses the
rootlessport
proxy, which replaces the source ip of the connection with an internal ip from the container namespace. You can, however, explicitly request Podman to useslirp4netns
as the port handler, which will preserve the source address at the expense of some performance.For example, if I start a container like this:
And then connect to this from somewhere:
I will see in the access log:
Where
10.0.2.100
is in fact the address of the container:But if I explicitly request
slirp4nets
as the port handler:Then in the access log I will see the actual source ip of the request:
In most cases, you don’t want to rely on the source ip address for authentication/authorization purposes, so the default behavior makes sense.
If you need the remote ip for logging purposes, the option presented here will work, or you can also look into running a front-end proxy in the global namespace that places the client ip into the
X-Forwarded-For
header and use that for your logs.Here is an alternative solution not mentioned in the nice
answer by @larsks.
Socket activation
When using socket activation of containers, the source IP is available to the container.
Support for socket activation is not yet wide-spread but for instance the container image docker.io/library/mariadb supports socket activation. The container image docker.io/library/nginx also supports socket activation (although in a non-standard way, as nginx uses its own environment variable instead of using the standard systemd environment variable
LISTEN_FDS
)I wrote a minimal demo of how to use run docker.io/library/nginx with Podman and socket activation:
https://github.com/eriksjolund/podman-nginx-socket-activation