Daniel Walker
Daniel Walker

Reputation: 6772

Make containers inside network unroutable from the host

For a testing situation, I've created a docker-compose file which stands up two containers:

version: "3.8"

services:
  foo:
    ports:
      - 5000:5000/tcp
    networks:
      - default
    ...

  bar:
    networks:
      - default
    ...

networks:
  default:
    ipam:
      driver: internal
      config:
        - subnet: 172.100.0.0/16

For the purposes of my tests, I need bar to be unreachable from the host. Unfortunately, when I run docker-compose up, ip addr shows that my host is on that network at 172.100.0.1.

How do I change my YAML file to accomplish this?

Upvotes: 1

Views: 122

Answers (1)

larsks
larsks

Reputation: 312630

Caveat The address range you've selected (172.100.0.0/16) is a routeable address range that apparently belongs to charter communications. This means that attempts to reach addresses in that range -- if there's not a specific route to your containers -- will get routed via your default gateway and potentially to actual machines somewhere on the internet.


Anyway, to your question:

I don't believe this is going to be possible using only Docker. For a bridged network, Docker will (a) always create a host bridge and (b) always assign an ip address to that bridge, which means containers will always be routable from the host.

You can create containers that have no network connectivity by using the none network:

version: "3.8"

services:
  foo:
    network_mode: none
    image: docker.io/alpinelinux/darkhttpd

  bar:
    network_mode: none
    image: docker.io/alpinelinux/darkhttpd

And then manually wire them up to a bridge using ip commands:

ip link add br-internal type bridge
ip link set br-internal up

foo_pid="$(docker inspect project_foo_1 --format '{{ .State.Pid }}')"
bar_pid="$(docker inspect project_bar_1 --format '{{ .State.Pid }}')"

ln -s /proc/$foo_pid/ns/net /run/netns/foo
ln -s /proc/$bar_pid/ns/net /run/netns/bar

ip link add foo-ext type veth peer name foo-int netns foo
ip -n foo addr add 172.100.0.10/26 dev foo-int
ip -n foo link set foo-int up
ip link set foo-ext up master br-internal

ip link add bar-ext type veth peer name bar-int netns bar
ip -n bar addr add 172.100.0.11/26 dev bar-int
ip -n bar link set bar-int up
ip link set bar-ext up master br-internal

Now we can ping bar from foo:

$ docker compose exec foo ping -c1 172.100.0.11
PING 172.100.0.11 (172.100.0.11): 56 data bytes
64 bytes from 172.100.0.11: seq=0 ttl=42 time=0.080 ms

--- 172.100.0.11 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.080/0.080/0.080 ms

And foo from bar:

$ docker compose exec bar ping -c1 172.100.0.10
PING 172.100.0.10 (172.100.0.10): 56 data bytes
64 bytes from 172.100.0.10: seq=0 ttl=42 time=0.047 ms

--- 172.100.0.10 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.047/0.047/0.047 ms

But our host doesn't have a route to either of these addresses:

$ ip route get 172.100.0.10
172.100.0.10 via 192.168.1.1 dev eth0 src 192.168.1.175 uid 1000
    cache

That shows that attempts to reach addresses on this network will get routed via our default gateway, rather than to the containers.

Upvotes: 2

Related Questions