Repository: GitHub

The Podman managed machine is a virtual machine (VM) and is enabled and managed via the Podman command line interface (CLI). QEMU is used as the "hypervisor". On non-Linux hosts Podman requires a VM (or another remote host) in order to orchestrate containers and container images. The approach that Podman has taken is highly similar to that of the Docker Desktop approach which is described briefly described in Podman as a Replacement for Docker Desktop ( Red Hat The Source Article: Podman as a Replacement for Docker Desktop).

1. Rationale

By default the Podman managed machine is accessible from the host system, including for remote access via Secure Shell and Secure Copy (ssh and scp respectively). There are times when one may need (or wish) to enable similar connectivity from the VM (guest) to the host.

One such example is in restrictive environments such as corporation or government environments that require a proxy to access external resources beyond the trusted security enclave. In some environments the proxy infrastructure requires authentication. In a circumstance such as this it is not an option to store security credentials in a configuration file let alone embed them in some in some script. In this case the organization may have an inner source solution (e.g.; a proxy for a proxy) to handle the case of CLI (Command Line Interface) tools that are not authenticating proxy aware.

Another example may simply be that one is testing out a number of things in an immutable system such as Fedora CoreOS (FCOS) and simply wants to transfer the result of this work back to the host via Secure Copy (scp) from the guest back to the host.

Of course with host to guest SSH and this scp connectivity fully enabled "out of the box" with Podman transferring files out of the managed machine is possible without this.

2. How to Enable

All approaches have been tested on Podman 3.4.4 and Podman 4.1.0 and on Linux and MacOS.

The way we enable this is to modify the QEMU command line for the Podman managed machine. Before we can do this we must first create the Podman managed machine:

podman machine init

Once the Podman VM is created from podman machine init and prior to starting it we merely modify the managed machine JSON configuration file for the QEMU command line. We add a secondary NIC to the VM by appending the following QEMU options to the configuration file:

-device virtio-net-pci,netdev=net1 -netdev user,id=net1

We can easily make use of jq to do this:

jq \
    '.CmdLine += ["-device", "virtio-net-pci,netdev=net1", "-netdev", "user,id=net1"]' \
    ~/.config/containers/podman/machine/qemu/podman-machine-default.json > \
    ~/.config/containers/podman/machine/qemu/podman-machine-default.json.1
mv \
    ~/.config/containers/podman/machine/qemu/podman-machine-default.json.1 \
    ~/.config/containers/podman/machine/qemu/podman-machine-default.json

2.1. Validation

This is easily validated as such:

podman machine ssh ip address

Shows us the secondary NIC has been added and is on an entirely new private network: 10.0.2.0/24 and has received the IP 10.0.2.15 from QEMU:

3: enp0s4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic noprefixroute enp0s4
       valid_lft 86276sec preferred_lft 86276sec
    inet6 fec0::cb8a:cff7:4ca9:ab65/64 scope site dynamic noprefixroute
       valid_lft 86279sec preferred_lft 14279sec
    inet6 fe80::7e27:585d:5391:2a5e/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

And a new route has now been created as well:

podman machine ssh route -n

Yields:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.127.1   0.0.0.0         UG    100    0        0 enp0s1
0.0.0.0         10.0.2.2        0.0.0.0         UG    101    0        0 enp0s4
10.0.2.0        0.0.0.0         255.255.255.0   U     101    0        0 enp0s4
192.168.127.0   0.0.0.0         255.255.255.0   U     100    0        0 enp0s1

Take note of the default gateway of 10.0.2.2. This is the special IP that QEMU will accept connections from a VM to the host, provided that there is a service bound to the host port.

giphy

2.2. Testing

Now we test our connectivity.

2.2.1. Netcat

On the host we will wait for an inbound connection and provide a response back to the remote TCP client.

cat <<EOM | nc -lv -w 1 8080
HTTP/1.1 200 OK

Hello from $(hostname -f)
EOM

Here we bind netcat on port 8080 to all available host network interfaces, wait for a connection, provide a response back from an inline heredoc that also includes the FQDN of the host and then terminates the connection.

And from the Podman machine we will connect to port 8080 on the host:

podman machine ssh curl -iv http://10.0.2.2:8080

Which yields:

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
* no chunk, no close, no size. Assume close to signal end

<
Hello from mac-mini.n7.priv
* Closing connection 0
giphy

Excellent, now, we will further illustrate by spinning up a one line HTTP server listening on all host interfaces, bind it to port 8080 and fulfilling HTTP requests from the user home directory. On the host:

2.2.2. Simple HTTP Server

python3 -m http.server --directory ~ 8080

And from the Podman machine we will connect to port 8080 on the host:

podman machine ssh curl -iv http://10.0.2.2:8080

Which yields:

*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.9.13
Server: SimpleHTTP/0.6 Python/3.9.13
< Date: Wed, 08 Jun 2022 20:05:28 GMT
Date: Wed, 08 Jun 2022 20:05:28 GMT
< Content-type: text/html; charset=utf-8
Content-type: text/html; charset=utf-8
< Content-Length: 1509
Content-Length: 1509

<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Directory listing for /</title>
</head>
<body>
<h1>Directory listing for /</h1>
<hr>
<ul>
<li><a href=".cache/">.cache/</a></li>
<li><a href=".CFUserTextEncoding">.CFUserTextEncoding</a></li>
<li><a href=".config/">.config/</a></li>
<li><a href=".lesshst">.lesshst</a></li>
<li><a href=".local/">.local/</a></li>
<li><a href=".oh-my-zsh/">.oh-my-zsh/</a></li>
<li><a href=".p10k.zsh">.p10k.zsh</a></li>
<li><a href=".ssh/">.ssh/</a></li>
<li><a href=".Trash/">.Trash/</a></li>
<li><a href=".vim/">.vim/</a></li>
<li><a href=".viminfo">.viminfo</a></li>
<li><a href=".vimrc">.vimrc</a></li>
<li><a href=".vimrc.local">.vimrc.local</a></li>
<li><a href=".zcompdump">.zcompdump</a></li>
<li><a href=".zcompdump-mac-mini-5.8">.zcompdump-mac-mini-5.8</a></li>
<li><a href=".zsh/">.zsh/</a></li>
<li><a href=".zsh_history">.zsh_history</a></li>
<li><a href=".zsh_sessions/">.zsh_sessions/</a></li>
<li><a href=".zshrc">.zshrc</a></li>
<li><a href="Desktop/">Desktop/</a></li>
<li><a href="Documents/">Documents/</a></li>
<li><a href="Downloads/">Downloads/</a></li>
<li><a href="Library/">Library/</a></li>
<li><a href="Movies/">Movies/</a></li>
<li><a href="Music/">Music/</a></li>
<li><a href="Pictures/">Pictures/</a></li>
<li><a href="projects/">projects/</a></li>
<li><a href="Public/">Public/</a></li>
</ul>
<hr>
</body>
</html>
* Closing connection 0

3. Summary

We have shown how to enable Podman managed machine (virtual machine, VM) connectivity to the host itself with minimal effort. This approach can easily be extended to enabling integration from the guest to the host. There exists restrictive environments such that access to external Internet resources are constrained by using authenticating proxy servers must be used on the internal security enclave and that one desires to orchestrate a proxy for proxy. This is merely only one singular use case.

4. References