docker / for-mac

Bug reports for Docker Desktop for Mac
https://www.docker.com/products/docker#/mac
2.43k stars 118 forks source link

Docker not blocked by macOS firewall #729

Open oleborup opened 8 years ago

oleborup commented 8 years ago

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

  1. Enable macOS firewall
  2. Run nginx mapping to port 8080: docker run --rm -p 8080:80 -v /tmp:/usr/share/nginx/html:ro nginx
  3. Try to connect from other machine on same network using curl: curl http://<ip-of-mac-running-nginx>:8080
ijc commented 7 years ago

@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.

iBobik commented 7 years ago

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.

djs55 commented 7 years ago

(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:

screen shot 2017-01-10 at 10 41 38

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?

atombender commented 6 years ago

@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?

atombender commented 6 years ago

Ah, found it: Drag /Applications/Docker.app/Contents/Resources/bin/vpnkit into the list.

atombender commented 6 years ago

This issue has been open for 1 year and 7 months. Can it please get some attention?

YRM64 commented 6 years ago

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:

1) Open System apreferences 2) Click on Security or Security and Privacy icon 3) Click on the Firewall Tab 4) Click the lock icon in the Preference Pane, then Enter an Administrative Name and Password 5) Select the Firewall's Option Button 6) 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).

atombender commented 6 years ago

@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.

SRautila commented 6 years ago

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"
pjialin commented 6 years ago

@SRautila Thanks for your answer, It's a great solution.

docker-robott commented 5 years ago

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

atombender commented 5 years ago

/remove-lifecycle stale

docker-robott commented 5 years ago

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

orymate commented 5 years ago

/remove-lifecycle stale This is a security issue.

docker-robott commented 5 years ago

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

atombender commented 5 years ago

/remove-lifecycle stale

thaJeztah commented 5 years ago

/lifecycle frozen

thaJeztah commented 5 years ago

@djs55 was there any progress to report on this?

bolt-juri-gavshin commented 4 years ago

Is there a way to force local Kubernetes to bind only to 127.0.0.1?

bolt-juri-gavshin commented 4 years ago

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).

vsisl commented 10 months ago

What is the status of this? I find this to be quite a serious security issue.

Creative-Difficulty commented 1 week ago

@atombender