Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sterner warnings and deprecation notice for unauthenticated tcp access #41285

Merged
merged 1 commit into from
Sep 25, 2020

Conversation

cpuguy83
Copy link
Member

@cpuguy83 cpuguy83 commented Jul 28, 2020

People keep doing this and getting pwned because they accidentally left
it exposed to the internet.

The warning about doing this has been there forever.
This introduces a sleep after warning.
To disable the extra sleep users must explicitly specify --tls=false
or --tlsverify=false

Warning also specifies this sleep will be removed in the next release
where the flag will be required if running unauthenticated.

@AkihiroSuda
Copy link
Member

Needs deprecation period?

@AkihiroSuda
Copy link
Member

Past discussion: #37299 #36357

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this is bad, but we need to look at how to deal with this (see my comment)

Comment on lines 64 to 65
err := d.StartWithError("--host", "tcp://127.0.0.1:0")
assert.Assert(t, err != nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've especially seen the "localhost" / 127.0.0.1 case being in use quite frequently (on Desktop). Should we follow the same rules as for "insecure registries", and

  • have an exception for 127.0.0.0/8
  • add a flag to allow the range to be customised?

I know all are bad, and insecure (containers can access, depending on their network settings, so can compromise the host) but also concerned that there's many "valid" (between big brackets) use-cases

@justincormack @tonistiigi @tiborvass any suggestions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we follow the same rules as for "insecure registries",

Exposing the API socket to other processes is more critical than "insecure registries".
I don't think the same rule should apply here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on Desktop

Do you mean Docker for Mac/Win? Or Linux desktop?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exposing the API socket to other processes is more critical than "insecure registries". I don't think the same rule should apply here.

Yeah, so perhaps some explicit "I know what I'm doing" flag (as proposed in #37299)

Do you mean Docker for Mac/Win? Or Linux desktop?

At least Docker Desktop for Windows (some of that may be because (IIRC) in the past it didn't support named pipes, and defaulted to enabling the API on tcp as well)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can keep localhost (what about ipv6?) for now and phase it out later?

Another approach, we could generate TLS certs at a particular location for localhost and have the docker client automatically look for these certs.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Linux, allowing localhost doesn't seem meaningful. If we are not sure about Windows, we can keep localhost on Windows for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another approach, we could generate TLS certs at a particular location for localhost and have the docker client automatically look for these certs.

Is it just like docker:dind image does? https://github.com/docker-library/docker/blob/master/19.03/dind/dockerd-entrypoint.sh#L21-L90

@@ -599,7 +599,7 @@ func loadListeners(cli *DaemonCli, serverConfig *apiserver.Config) ([]string, er

// It's a bad idea to bind to TCP without tlsverify.
if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) {
logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting --tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]")
return nil, errors.New("Binding to IP address without --tlsverify is no longer supported")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have a deprecation process.

Disabling directly will cause some users to be unable to use it normally after the upgrade. (maybe they are not ready yet. of course, it is possible that most of these users use the default configuration unix domain socket)

And we have not notified when it will be officially disabled IIRC.

@tonistiigi
Copy link
Member

Plenty of valid reasons to do run raw tcp, even on 0.0.0.0. Eg. if you are on a VM, container, local isolated compute cluster etc. I'm in favor of adding --allow-insecure-connections (or less verbose). Not setting that flag will show the deprecation warning and after deprecation period is over start failing on startup.

@cpuguy83
Copy link
Member Author

I don't see the point of deprecation for this.
People are already ignoring the warning plus we have a stable release in 19.03 that people can fall back to.

I'm fine with adding a flag to allow this case through. The more verbose the better 😄 --yes-i-really-want-to-give-root-access-to-anyone-on-the-network 😂

@tianon
Copy link
Member

tianon commented Jul 31, 2020

I agree with the sentiments already shared -- I use this in quite a few environments where it's not the best solution, but the security tradeoff is acceptable, so I'd definitely be sad if it were completely gone, but I'm perfectly happy with an explicit flag to enable it (even if said flag is really verbose like the proposed --yes-i-really-want-to-give-root-access-to-anyone-on-the-network 😄).

(I definitely don't want to see something like --privileged where the "let me be insecure" flag is very short and doesn't really tell the user much about what they're opening up.)

@jglick
Copy link

jglick commented Aug 1, 2020

IIUC this would block image updates for idioms like jenkinsci/kubernetes-plugin#581. Could probably be adapted to use a Unix-domain socket via volume mount.

@thaJeztah thaJeztah added this to the 20.03.0 milestone Aug 13, 2020
@olljanat
Copy link
Contributor

IMO, best option would be automatically generated certificates and enabled TLS verify for TCP connections. Most people are too lazy to study how to generate certificates but most probably they are able copy certificate files to client if there instructions about it.

And for those who really don't care about security there can be that super long and desribe switch available.

@cpuguy83
Copy link
Member Author

I have updated this as follows:

Add flag --allow-unauthenticated-machine-root-access-to-network which needs to be specified for each -H that is unauthenticated tcp.

Without this flag the daemon will sleep 30s for each unauthenticated -H.

I have special cased localhost (both v4 and v6 should be handled) to not sleep in this case... not sure if that's the best decision but 🤷‍♂️.

Warnings are a bit more stern, including claiming that the flag will be required in the next release instead of having a sleep.

@cpuguy83
Copy link
Member Author

Looks like 2 tests need an update.
Will push this soon.

@cpuguy83 cpuguy83 force-pushed the no_more_pwns branch 2 times, most recently from 78dfdad to 688181d Compare September 17, 2020 00:03
@cpuguy83
Copy link
Member Author

Updated to fix tests.
Had to add a special case for host addresses specified as a hostname (e.g. "localhost") since -H supports this and it is trying to skip the sleeps for loopback addresses.

@thaJeztah
Copy link
Member

Discussing with @tonistiigi @tiborvass @cpuguy83

  • for this PR:
    • don't print warning if user has set --tls=false and/or --tlsverify=false
    • update messages to mention that TLS will be enable by default in a future release
  • future release; enable both --tls and --tlsverify by default: if a user didn't specify options, the daemon will fail to start as no certs are provided
  • add options to explicitly disable tls / tlfverify: --disable-tls, --disable-tls-verify (name can be discussed)

We'll need to update https://github.com/docker/cli/blob/master/docs/deprecated.md to mention "deprecation" of unprotected TCP access.

@cpuguy83 cpuguy83 force-pushed the no_more_pwns branch 2 times, most recently from 7cafe7d to 0790a51 Compare September 18, 2020 20:15
@cpuguy83
Copy link
Member Author

Updated to have this work with --tls=false or --tlsverify=false

@cpuguy83 cpuguy83 changed the title Do not listen on TCP address if w/o TLS verify Sterner warnings and deprecation notice for unauthenticated tcp access Sep 18, 2020
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just some quick comments/questions (didn't do a full review on my computer)

}

if conf.TLSVerify == nil && conf.TLS != nil {
conf.TLSVerify = conf.TLS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a change in behavior, correct? (automatically enable verify)

If so, I'm ok with that change, but we'll probably need to mention that explicitly in changelogs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is what we discussed on the PR review call.

cmd/dockerd/options.go Show resolved Hide resolved
cmd/dockerd/daemon.go Show resolved Hide resolved
@thaJeztah
Copy link
Member

@cpuguy83 two tests are failing;

=== Failed
=== FAIL: cmd/dockerd TestLoadDaemonCliConfigWithTLSVerify (0.00s)
    daemon_test.go:115: assertion failed: 0x40009cd540 (loadedConfig.TLS *bool) != true (true bool)

=== FAIL: cmd/dockerd TestLoadDaemonCliConfigWithExplicitTLSVerifyFalse (0.00s)
    daemon_test.go:128: invalid Comparison: 0x4000a02c80 (*bool)

@cpuguy83 cpuguy83 force-pushed the no_more_pwns branch 2 times, most recently from 60b0aa2 to 9d9dc1c Compare September 24, 2020 18:33
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if green 👍

@thaJeztah
Copy link
Member

Arf.. one more test failure @cpuguy83

=== RUN   TestAuthZPluginTLS
--- FAIL: TestAuthZPluginTLS (1.67s)
    authz_plugin_test.go:132: assertion failed: error is not nil: error during connect: Get https://localhost:4271/v1.41/version: http: server gave HTTP response to HTTPS client

@cpuguy83
Copy link
Member Author

cpuguy83 commented Sep 24, 2020

🤔 Doesn't fail locally.

Wrong branch.

People keep doing this and getting pwned because they accidentally left
it exposed to the internet.

The warning about doing this has been there forever.
This introduces a sleep after warning.
To disable the extra sleep users must explicitly specify `--tls=false`
or `--tlsverify=false`

Warning also specifies this sleep will be removed in the next release
where the flag will be required if running unauthenticated.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants