My computer is hosting an application on port 1234 that should never be accessible from anything but my machine. However, my Docker container (which is running Apache) should be able to access this. Similarly, my Docker container is hosting a number of resources on various ports that should similarly be only accessible from my computer. Now, this is further complicated by the fact that my system uses a bridge for that specific network:
NETWORK ID NAME DRIVER SCOPE
4d4b5e752963 bridge bridge local
c387eb42698a project_default bridge local
6818c0eb94bf host host local
f7e4ed6c05a2 none null local
This bridge (annoyingly) always has a randomly generated ID that changes each time I restart my Docker Compose setup:
br-c387eb42698a Link encap:Ethernet HWaddr 02:42:29:95:fd:2c
inet addr:172.18.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:29ff:fe95:fd2c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:405753 errors:0 dropped:0 overruns:0 frame:0
TX packets:530699 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:85147217 (85.1 MB) TX bytes:75260996 (75.2 MB)
In short, I need the following:
- Any host on
br-c387eb42698a
(or whatever the network name is) to access port 1234 on my local machine (conveniently 172.18.0.1) - My machine to be able to access any port on any host on that subnet. (default)
- The world to never be able to access any port from the subnet or port 1234.
Ideally, a solution here would work in an IP-agnostic way such that it does not depend on the bridge being on the 172.18.0.0/24
subnet, nor would it break or allow data leaks if I'm connected to a network that happens to contain the 172.18.0.0/24
subnet.
The easiest thing I can think of would be to use the interface name and set up UFW rules around that, but I can't really do that as my interface is constantly changing.
How can I do this? While I'd prefer to do this in pure ufw
(or iptables
if necessary), I'm open to solutions that entail configuring Docker to always assign a persistent ID (or even custom name?) to the bridge interface.
This is not possible in vanilla UFW because of the fact that the interface name is in a constant state of unguessability. In order to set something like this up, a manually defined network should be created. In short, one can use the driver options of Docker's
bridge
in the compose config to create a custom network. This will look something like:From here, the bridge config can be added to each service in the compose file:
Then, upon next start of the Compose system, the new network will be created with the proper name:
From there, adding UFW rules to allow connection to port 1234 are trivial:
And suddenly, everything works perfectly!
To integrate the accepted answer, you can also use a docker command to create the network outside of docker-compose:
After that you can inspect the networks issuing
Now, in your compose files you can just re-route the default network or define any network you like remapping it to the already existing one
To extend the accepted answer further, when using Docker Swarm and deploying a stack, a
bridge
network is an invalid network type.You can expect an error similar to the following:
failed to create service [service_name]: Error response from daemon: The network [network_name] cannot be used with services. Only networks scoped to the swarm can be used, such as those created with the overlay driver.
To allow a container to communicate with the host from a swarm cluster:
overlay
networkThe service seems to be able to send messages to the the host via
172.17.0.1
and172.18.0.1