Docker not blocked by macOS firewall
Expected behavior
When mapping a container port to a host port it is expected that external access to the port is blocked by the macOS firewall, if enabled, and it is expected that the user should be prompted to allow docker to open the port in the firewall.
Actual behavior
Mapped ports are accessible externally even if the firewall is enabled. Only enabling "Block all incoming connections" will prevent access, but not an option is cases where some ports needs to be accessible.
Information
Docker for Mac: version: 1.12.1-beta26.1 (12c3e63) OS X: version 10.12 (build: 16A323) logs: /tmp/5EEDAAC2-A4C2-4562-86DF-C033FDB4739C/20160930-104203.tar.gz [OK] docker-cli [OK] virtualization kern.hv_support [OK] menubar [OK] moby-syslog [OK] dns [OK] disk [OK] system [OK] app [OK] osxfs [OK] virtualization VT-X [OK] db [OK] slirp [OK] logs [OK] env [OK] vmnetd [OK] moby-console [OK] moby [OK] driver.amd64-linux
Steps to reproduce the behavior
- Enable macOS firewall
- Run nginx mapping to port 8080:
docker run --rm -p 8080:80 -v /tmp:/usr/share/nginx/html:ro nginx - Try to connect from other machine on same network using curl:
curl http://<ip-of-mac-running-nginx>:8080
@oleborup thanks for the report and sorry for the tardiness of the response. I can confirm your observations and also that this behaviour is independent of the state of the "Automatically allow signed software to receive incoming connections".
I'm going to escalate this to an internal ticket.
How is it going?
It is potential security issue because developers travels around public WiFis and they usually does not know all their containers are accessible to their neighbours.
(sorry for the confused update -- I got mixed up between this ticket and an almost-identical internal duplicate.)
In the System Preferences -> Firewall -> Firewall options I see a checkbox:
Automatically allow downloaded signed software to receive incoming connections
This is checked by default on my system and is what -- I believe -- lets docker run -p 8080 work silently.
I believe there is a caching effect too -- I had to uncheck the box, then remove com.docker.slirp from the application list and then restart Docker.app. Then when I run docker run -p 8080 it pops up a dialog box asking me to allow or deny incoming connections to com.docker.slirp and then remembers it here:

It's probably associated the choice with the specific application binary + signature-- you would probably get asked again over an upgrade.
Personally I think this behaviour is not ideal -- once the user has authorised the application this is cached and is independent of the Wifi network, which as @iBobik points out may not be what you want. It appears to be standard on the Mac though. I authorised my com.docker.slirp and then switched to the guest network and there was no additional prompt.
However there is a partial work-around if you want to treat networks differently: you can restrict docker's ability to bind to external IP addresses via a database key (there is no UI yet-- the feature isn't really finished) e.g.
cd ~/Library/Containers/com.docker.docker/Data/database/com.docker.driver.amd64-linux
git reset --hard
echo "127.0.0.1,1.2.3.4" > allowed-bind-address
git add allowed-bind-address
git commit -m 'restrict bind addresses'
A log line will show it has taken effect, in syslog -k Sender Docker
Jan 10 10:51:43 Davids-MBP-2 Docker[20119] <Notice>: allowing binds to 1.2.3.4, 127.0.0.1
and then attempts to bind other addresses (NB 0.0.0.0 is the default) will fail:
docker run --rm -p 8080:80 -v /tmp:/usr/share/nginx/html:ro nginx
docker: Error response from daemon: driver failed programming external connectivity on endpoint gallant_goldwasser (5e1c04bf3a6a588e055a6c889f6e153b89710234f61b144afff20ef993f5f923): Error starting userland proxy: Bind for 0.0.0.0:8080 failed: permission denied.
I think we should at least add some notes about this to the networking section of the manual. Perhaps we should refine this feature into one which allows whitelisting of trusted networks?
@djs55: My Edge install doesn't have a binary named com.docker.slirp anywhere, and it's not in the firewall list. Which binary should one add?
Ah, found it: Drag /Applications/Docker.app/Contents/Resources/bin/vpnkit into the list.
This issue has been open for 1 year and 7 months. Can it please get some attention?
Alexander, I think what your addressing is an inherent design dilemma built into the MacOs firewall application. I don't want to refer to as a design 'flaw', however, it does pose a significant inconvenience for developers seeking to block certain ports that the docker/MacOs firewall allows through.
I don't think there's been an update to this issue since March 2016. If I'm wrong, I stand corrected. Perhaps djs55 can comment for us on the timeframe, and the amount of time it will take to come up with an acceptable solution. I've conducted a little research on the subject matter, and the following is what I ascertained. Developers feel free to jump in here if your research has taken you in a different direction.
First, you must have an OSX v. 10.5.1 or later version to configure the firewall to your own personal specification using the advanced settings feature. To allow certain protocols/applications through the MacOs firewall:
- Open System apreferences
- Click on Security or Security and Privacy icon
- Click on the Firewall Tab
- Click the lock icon in the Preference Pane, then Enter an Administrative Name and Password
- Select the Firewall's Option Button
- Click on Add Application (+) Button; to Remove an Application Listed, Remove Application using the (-) symbol What most developers don't realize is that apps signed by Apple and Ipfw automatically come through the firewall, this is a design element built into the MacOs firewall. Apps signed by Apple are deemed authorized, and are therefore allowed through. And, ipfw rules supersede any firewall rules. In other words, if ipfw blocks an incoming packet, the MacOs firewall ignores it.
Furthermore, the Mac firewall works with internet protocols utilized by apps TCP and UDP. Firewall settings don't affect for example, Apple Talk Connections. To reiterate, The firewall can't override ipfw rule setting technology. I suspect, but I could be wrong, this is a possible reason you aren't prompted to disclose whether you want to allow or disallow a certain application through the firewall. Perhaps djs55 can provide further comment on this particular issue.
One healthful/helpful piece of advice I can contribute to the discussion is to encourage developers to enable Stealth Mode which prevents the computer from responding to probing requests. Unexpected requests are ignored (such as ping).
@YRM64 The easiest workaround would be for DfM to stop binding to external interfaces. I'm not sure what kind of workflow other developers use, but to me there's no utility to binding external interfaces, since localhost is entirely sufficient for local development and testing. For any testing that requires incoming connections I use (and recommend) ngrok.
DfM could also easily work around the Automatically allow downloaded signed software to receive incoming connections setting by adding a custom firewall rule that overrides it.
For the user to manually configure the firewall setting just to achieve security is nonsensical, but it is also not future-proof. Case in point: Back in February I added /Applications/Docker.app/Contents/Resources/bin/vpnkit to the list of blocked apps. But in some subsequent DfM upgrade, they changed the binary to .../bin/com.docker.vpnkit, and so my rule got knocked out without me realizing it.
My workaround for this is to only expose the ports to 127.0.0.1 for local development.
E.g.
ports:
- "127.0.0.1:8000:8000"
@SRautila Thanks for your answer, It's a great solution.
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale comment.
Stale issues will be closed after an additional 30d of inactivity.
Prevent issues from auto-closing with an /lifecycle frozen comment.
If this issue is safe to close now please do so.
Send feedback to Docker Community Slack channels #docker-for-mac or #docker-for-windows. /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale comment.
Stale issues will be closed after an additional 30d of inactivity.
Prevent issues from auto-closing with an /lifecycle frozen comment.
If this issue is safe to close now please do so.
Send feedback to Docker Community Slack channels #docker-for-mac or #docker-for-windows. /lifecycle stale
/remove-lifecycle stale This is a security issue.
Issues go stale after 90d of inactivity.
Mark the issue as fresh with /remove-lifecycle stale comment.
Stale issues will be closed after an additional 30d of inactivity.
Prevent issues from auto-closing with an /lifecycle frozen comment.
If this issue is safe to close now please do so.
Send feedback to Docker Community Slack channels #docker-for-mac or #docker-for-windows. /lifecycle stale
/remove-lifecycle stale
/lifecycle frozen
@djs55 was there any progress to report on this?
Is there a way to force local Kubernetes to bind only to 127.0.0.1?
It could be a setting in Docker UI, to list IPs the Kubernetes (or the entire Docker) is allowed to bind to.
Yet another possibility is to start supporting loadBalancerIP in Service with type "LoadBalancer", this way one can create a LoadBalancer, that is bound to "127.0.0.1", for example. I think the latter option is more flexible. However, NodePort must also become unavailable on other inerfaces (otherwise services are still vulnerable).
What is the status of this? I find this to be quite a serious security issue.
@atombender
I think this is quite a serious security issue since most development setups on macOS with Docker publish all kinds of ports with little to no protections since normally there is no need to protect a local development setup, but if they would know that everyone in a public Wi-Fi can just easily access those ports, that is a completely different situation. That this issue has been open since 2016 with no work from the Docker team is quite shocking, to be honest and I hope I just miss something and in reality this is a smaller issue then I think it is.
Regardless of this, I would like to use one of the workarounds proposed in this issue by @SRautila and @atombender, but I can't make them work.
First I tried to adapt one of my docker-compose.yml files from:
ports:
- "80:80"
- "443:443"
to:
ports:
- "127.0.0.1:80:80"
- "127.0.0.1:443:443"
But when I restart it I get the following error:
Error response from daemon: Ports are not available: exposing port TCP 127.0.0.1:80 -> 127.0.0.1:0: failed to connect to /var/run/com.docker.vmnetd.sock: is vmnetd running?: dial unix /var/run/com.docker.vmnetd.sock: connect: no such file or directory
I also tried to block Docker in the Firewall settings from macOS, but every time I block Docker and save, the change is not saved.
After clicking "OK":
I also tried to set the default bridge to 127.0.0.1, but this also did not solve the issue.
Link to docs: https://docs.docker.com/engine/network/packet-filtering-firewalls/#default-bridge
So after a bit of research I found the following two solutions that work for me with macOS 15.4.1.
macOS pf (packet filter)
The first solution is to configure the macOS packet filter "pf" to block the ports opened by Docker, but allow access from localhost.
For that you need to edit the config file /etc/pf.conf
To block the ports 80 and 443 for example you need to add the following lines:
block return in proto tcp from any to any port 80
pass in inet proto tcp from 127.0.0.1 to any port 80 no state
block return in proto tcp from any to any port 443
pass in inet proto tcp from 127.0.0.1 to any port 443 no state
Then run the following commands to activate the config:
sudo pfctl -f /etc/pf.conf
sudo pfctl -E
It works the same with other ports. You can see a overview of the ports opened by Docker with the following command:
docker container ls --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}" -a
Warning: This config might reset after a reboot or after a macOS update. Since I found a better solution for myself I didn't search for a solution for that. I'm open to edit this post if someone provides more information.
Little snitch (proprietary firewall for macOS)
You can add the following rule to Little snitch to block all ports that Docker opened:
Afterwards you need to "Increase priority" for this rule.