1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Add warning if REST API is accessible through an insecure connection

The remote API allows full privilege escalation and is equivalent to
having root access on the host. Because of this, the API should never
be accessible through an insecure connection (TCP without TLS, or TCP
without TLS  verification).

Although a warning is already logged on startup if the daemon uses an
insecure configuration, this warning is not very visible (unless someone
decides to read the logs).

This patch attempts to make insecure configuration more visible by sending
back warnings through the API (which will be printed when using `docker info`).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2018-08-21 14:06:06 +02:00
parent 2629fe9326
commit 547b993e07
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
2 changed files with 51 additions and 0 deletions

View file

@ -68,6 +68,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
Isolation: daemon.defaultIsolation,
}
daemon.fillAPIInfo(v)
// Retrieve platform specific info
daemon.fillPlatformInfo(v, sysInfo)
daemon.fillDriverInfo(v)
@ -171,6 +172,32 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf
v.SecurityOptions = securityOptions
}
func (daemon *Daemon) fillAPIInfo(v *types.Info) {
const warn string = `
Access to the remote API is equivalent to root access on the host. Refer
to the 'Docker daemon attack surface' section in the documentation for
more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface`
cfg := daemon.configStore
for _, host := range cfg.Hosts {
// cnf.Hosts is normalized during startup, so should always have a scheme/proto
h := strings.SplitN(host, "://", 2)
proto := h[0]
addr := h[1]
if proto != "tcp" {
continue
}
if !cfg.TLS {
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on http://%s without encryption.%s", addr, warn))
continue
}
if !cfg.TLSVerify {
v.Warnings = append(v.Warnings, fmt.Sprintf("WARNING: API is accessible on https://%s without TLS client verification.%s", addr, warn))
continue
}
}
}
func hostName() string {
hostname := ""
if hn, err := os.Hostname(); err != nil {

View file

@ -5,6 +5,7 @@ import (
"fmt"
"testing"
"github.com/docker/docker/internal/test/daemon"
"github.com/docker/docker/internal/test/request"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
@ -40,3 +41,26 @@ func TestInfoAPI(t *testing.T) {
assert.Check(t, is.Contains(out, linePrefix))
}
}
func TestInfoAPIWarnings(t *testing.T) {
d := daemon.New(t)
client, err := d.NewClient()
assert.NilError(t, err)
d.StartWithBusybox(t, "--iptables=false", "-H=0.0.0.0:23756", "-H=unix://"+d.Sock())
defer d.Stop(t)
info, err := client.Info(context.Background())
assert.NilError(t, err)
stringsToCheck := []string{
"Access to the remote API is equivalent to root access",
"http://0.0.0.0:23756",
}
out := fmt.Sprintf("%+v", info)
for _, linePrefix := range stringsToCheck {
assert.Check(t, is.Contains(out, linePrefix))
}
}