chipmk / docker-mac-net-connect

Connect directly to Docker-for-Mac containers via IP address 🐳 💻
MIT License
402 stars 41 forks source link

Support for --internal network? #23

Open dkoshkin opened 1 year ago

dkoshkin commented 1 year ago

Just found this project and super excited, works great for the default or other non --internal docker networks.

$ docker run --rm --name nginx -d nginx
$ docker inspect nginx --format '{{.NetworkSettings.IPAddress}}'
172.17.0.2
$ curl -m 1 -I 172.17.0.2
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Wed, 08 Mar 2023 03:44:47 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 13 Dec 2022 15:53:53 GMT
Connection: keep-alive
ETag: "6398a011-267"
Accept-Ranges: bytes

But it doesn't work if I use an --internal network

$ docker network create --internal internal
$ docker run --rm --name nginx-internal -d nginx --network internal
# note that NetworkSettings.IPAddress is empty
$ docker inspect nginx-internal --format '{{.NetworkSettings.Networks.internal.IPAddress}}'
$ curl -m 1 -I 172.28.0.2
curl: (28) Connection timed out after 1002 milliseconds

Was wondering if its even possible for this to work with an internal network?

gregnr commented 1 year ago

Hey @dkoshkin, thanks for reaching out. Without --internal, Docker creates a bridge network between the container and the host (Linux VM) to give it external access. Since adding --internal removes this bridge, you no longer get access to the Wireguard tunnel that lives on the Linux VM. (not entirely true - see below)

Curious what your use case is using --internal with this tool?

jimmidyson commented 1 year ago

We use it to simulate air-gapped (specifically no egress) networks in docker.

gregnr commented 1 year ago

Got it. Yeah this is a bit of an interesting case, as typically air-gap would exclude all networks, including your host (but of course, that makes dev/debugging hard).

The solution here would be to somehow create a connection only between the --internal container and the macOS host, without passing through the Linux host's network namespace. I'll have to think more about this one.

gregnr commented 1 year ago

Okay I did a deep dive on this today. This is what I discovered (for those curious):

How internal works

Solution

We need to respect the above isolation rules for internal networks while still giving access to the Wireguard VPN. I think the solution is to add 2 iptables rules to the Linux host:

Basically anytime a packet is headed to or from the chip0 (Wireguard) interface, accept it. Fyi, DOCKER-USER is a custom iptables chain created by Docker intended to be augmented by end users. See: https://docs.docker.com/network/iptables/

I've tested the above and it works. I think it is safe to add these rules as defaults (rather than some sort of opt-in), because this is more-or-less the default behaviour if you were to run Docker on a vanilla Linux host.