From 644acec2f7e3b144a423d0f0a6c900701abdc511 Mon Sep 17 00:00:00 2001 From: Evan Krall Date: Fri, 24 Jan 2014 16:18:02 -0800 Subject: [PATCH] Create a -G option that specifies the group which unix sockets belong to. Docker-DCO-1.1-Signed-off-by: Evan Krall (github: EvanKrall) --- api/server.go | 46 ++++++++++++++++------ docker/docker.go | 2 + docs/sources/installation/ubuntulinux.rst | 7 +++- docs/sources/reference/commandline/cli.rst | 1 + 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/api/server.go b/api/server.go index 7868600314..8fc6b4f68b 100644 --- a/api/server.go +++ b/api/server.go @@ -1104,10 +1104,34 @@ func ServeFd(addr string, handle http.Handler) error { return nil } +func lookupGidByName(nameOrGid string) (int, error) { + groups, err := user.ParseGroupFilter(func(g *user.Group) bool { + return g.Name == nameOrGid || strconv.Itoa(g.Gid) == nameOrGid + }) + if err != nil { + return -1, err + } + if groups != nil && len(groups) > 0 { + return groups[0].Gid, nil + } + return -1, fmt.Errorf("Group %s not found", nameOrGid) +} + +func changeGroup(addr string, nameOrGid string) error { + gid, err := lookupGidByName(nameOrGid) + if err != nil { + return err + } + + utils.Debugf("%s group found. gid: %d", nameOrGid, gid) + return os.Chown(addr, 0, gid) +} + // ListenAndServe sets up the required http.Server and gets it listening for // each addr passed in and does protocol specific checking. -func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors bool, dockerVersion string) error { +func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors bool, dockerVersion string, socketGroup string) error { r, err := createRouter(eng, logging, enableCors, dockerVersion) + if err != nil { return err } @@ -1138,16 +1162,14 @@ func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors return err } - groups, err := user.ParseGroupFilter(func(g *user.Group) bool { - return g.Name == "docker" - }) - if err != nil { - return err - } - if len(groups) > 0 { - utils.Debugf("docker group found. gid: %d", groups[0].Gid) - if err := os.Chown(addr, 0, groups[0].Gid); err != nil { - return err + if socketGroup != "" { + if err := changeGroup(addr, socketGroup); err != nil { + if socketGroup == "docker" { + // if the user hasn't explicitly specified the group ownership, don't fail on errors. + utils.Debugf("Warning: could not chgrp %s to docker: %s", addr, err.Error()) + } else { + return err + } } } default: @@ -1175,7 +1197,7 @@ func ServeApi(job *engine.Job) engine.Status { protoAddrParts := strings.SplitN(protoAddr, "://", 2) go func() { log.Printf("Listening for HTTP on %s (%s)\n", protoAddrParts[0], protoAddrParts[1]) - chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version")) + chErrors <- ListenAndServe(protoAddrParts[0], protoAddrParts[1], job.Eng, job.GetenvBool("Logging"), job.GetenvBool("EnableCors"), job.Getenv("Version"), job.Getenv("SocketGroup")) }() } diff --git a/docker/docker.go b/docker/docker.go index c18a32f7cf..2aa10dbe54 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -32,6 +32,7 @@ func main() { bridgeIp = flag.String([]string{"#bip", "-bip"}, "", "Use this CIDR notation address for the network bridge's IP, not compatible with -b") pidfile = flag.String([]string{"p", "-pidfile"}, "/var/run/docker.pid", "Path to use for daemon PID file") flRoot = flag.String([]string{"g", "-graph"}, "/var/lib/docker", "Path to use as the root of the docker runtime") + flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode; use '' (the empty string) to disable setting of a group") flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API") flDns = opts.NewListOpts(opts.ValidateIp4Address) flEnableIptables = flag.Bool([]string{"#iptables", "-iptables"}, true, "Disable docker's addition of iptables rules") @@ -138,6 +139,7 @@ func main() { job.SetenvBool("Logging", true) job.SetenvBool("EnableCors", *flEnableCors) job.Setenv("Version", dockerversion.VERSION) + job.Setenv("SocketGroup", *flSocketGroup) if err := job.Run(); err != nil { log.Fatal(err) } diff --git a/docs/sources/installation/ubuntulinux.rst b/docs/sources/installation/ubuntulinux.rst index 4d986a417f..416d56765e 100644 --- a/docs/sources/installation/ubuntulinux.rst +++ b/docs/sources/installation/ubuntulinux.rst @@ -182,9 +182,12 @@ daemon will make the ownership of the Unix socket read/writable by the *docker* group when the daemon starts. The ``docker`` daemon must always run as the root user, but if you run the ``docker`` client as a user in the *docker* group then you don't need to add ``sudo`` to all the -client commands. +client commands. As of 0.9.0, you can specify that a group other than ``docker`` +should own the Unix socket with the ``-G`` option. + +.. warning:: The *docker* group (or the group specified with ``-G``) is + root-equivalent. -.. warning:: The *docker* group is root-equivalent. **Example:** diff --git a/docs/sources/reference/commandline/cli.rst b/docs/sources/reference/commandline/cli.rst index ccb5314fac..c7ce421d88 100644 --- a/docs/sources/reference/commandline/cli.rst +++ b/docs/sources/reference/commandline/cli.rst @@ -71,6 +71,7 @@ Commands Usage of docker: -D, --debug=false: Enable debug mode -H, --host=[]: Multiple tcp://host:port or unix://path/to/socket to bind in daemon mode, single connection otherwise. systemd socket activation can be used with fd://[socketfd]. + -G, --group="docker": Group to assign the unix socket specified by -H when running in daemon mode; use '' (the empty string) to disable setting of a group --api-enable-cors=false: Enable CORS headers in the remote API -b, --bridge="": Attach containers to a pre-existing network bridge; use 'none' to disable container networking --bip="": Use this CIDR notation address for the network bridge's IP, not compatible with -b