Prechádzať zdrojové kódy

Implemented support to run as a different user (through the -u flag)

Andrea Luzzardi 12 rokov pred
rodič
commit
6de3e8a22d
4 zmenil súbory, kde vykonal 174 pridanie a 14 odobranie
  1. 5 2
      container.go
  2. 116 0
      container_test.go
  3. 4 3
      dockerd/dockerd.go
  4. 49 9
      sysinit.go

+ 5 - 2
container.go

@@ -49,6 +49,7 @@ type Container struct {
 
 type Config struct {
 	Hostname  string
+	User      string
 	Ram       int64
 	Tty       bool // Attach standard streams to a tty, including stdin if it is not closed.
 	OpenStdin bool // Open stdin
@@ -270,10 +271,12 @@ func (container *Container) Start() error {
 		"-f", container.lxcConfigPath,
 		"--",
 		"/sbin/init",
-		container.Path,
 	}
+	if container.Config.User != "" {
+		params = append(params, "-u", container.Config.User)
+	}
+	params = append(params, "--", container.Path)
 	params = append(params, container.Args...)
-
 	container.cmd = exec.Command("/usr/bin/lxc-start", params...)
 
 	var err error

+ 116 - 0
container_test.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"strings"
 	"testing"
 	"time"
 )
@@ -186,6 +187,121 @@ func TestExitCode(t *testing.T) {
 	}
 }
 
+func TestUser(t *testing.T) {
+	docker, err := newTestDocker()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Default user must be root
+	container, err := docker.Create(
+		"user_default",
+		"id",
+		[]string{},
+		[]string{"/var/lib/docker/images/ubuntu"},
+		&Config{},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer docker.Destroy(container)
+	output, err := container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
+		t.Error(string(output))
+	}
+
+	// Set a username
+	container, err = docker.Create(
+		"user_root",
+		"id",
+		[]string{},
+		[]string{"/var/lib/docker/images/ubuntu"},
+		&Config{
+			User: "root",
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer docker.Destroy(container)
+	output, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
+		t.Error(string(output))
+	}
+
+	// Set a UID
+	container, err = docker.Create(
+		"user_uid0",
+		"id",
+		[]string{},
+		[]string{"/var/lib/docker/images/ubuntu"},
+		&Config{
+			User: "0",
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer docker.Destroy(container)
+	output, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(string(output), "uid=0(root) gid=0(root)") {
+		t.Error(string(output))
+	}
+
+	// Set a different user by uid
+	container, err = docker.Create(
+		"user_uid1",
+		"id",
+		[]string{},
+		[]string{"/var/lib/docker/images/ubuntu"},
+		&Config{
+			User: "1",
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer docker.Destroy(container)
+	output, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
+		t.Error(string(output))
+	}
+
+	// Set a different user by username
+	container, err = docker.Create(
+		"user_daemon",
+		"id",
+		[]string{},
+		[]string{"/var/lib/docker/images/ubuntu"},
+		&Config{
+			User: "daemon",
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer docker.Destroy(container)
+	output, err = container.Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") {
+		t.Error(string(output))
+	}
+}
+
 func TestMultipleContainers(t *testing.T) {
 	docker, err := newTestDocker()
 	if err != nil {

+ 4 - 3
dockerd/dockerd.go

@@ -611,10 +611,10 @@ func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string
 	return errors.New("No such container: " + cmd.Arg(0))
 }
 
-func (srv *Server) CreateContainer(img *image.Image, tty bool, openStdin bool, comment string, cmd string, args ...string) (*docker.Container, error) {
+func (srv *Server) CreateContainer(img *image.Image, user string, tty bool, openStdin bool, comment string, cmd string, args ...string) (*docker.Container, error) {
 	id := future.RandomId()[:8]
 	container, err := srv.containers.Create(id, cmd, args, img.Layers,
-		&docker.Config{Hostname: id, Tty: tty, OpenStdin: openStdin})
+		&docker.Config{Hostname: id, User: user, Tty: tty, OpenStdin: openStdin})
 	if err != nil {
 		return nil, err
 	}
@@ -680,6 +680,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 	fl_attach := cmd.Bool("a", false, "Attach stdin and stdout")
 	fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
 	fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
+	fl_user := cmd.String("u", "0", "Username or UID")
 	fl_comment := cmd.String("c", "", "Comment")
 	if err := cmd.Parse(args); err != nil {
 		return nil
@@ -706,7 +707,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
 		return errors.New("No such image: " + name)
 	}
 	// Create new container
-	container, err := srv.CreateContainer(img, *fl_tty, *fl_stdin, *fl_comment, cmdline[0], cmdline[1:]...)
+	container, err := srv.CreateContainer(img, *fl_user, *fl_tty, *fl_stdin, *fl_comment, cmdline[0], cmdline[1:]...)
 	if err != nil {
 		return errors.New("Error creating container: " + err.Error())
 	}

+ 49 - 9
sysinit.go

@@ -1,13 +1,58 @@
 package docker
 
 import (
+	"flag"
 	"fmt"
 	"log"
 	"os"
 	"os/exec"
+	"os/user"
+	"strconv"
 	"syscall"
 )
 
+// Takes care of dropping privileges to the desired user
+func changeUser(u string) {
+	if u == "" {
+		return
+	}
+	userent, err := user.LookupId(u)
+	if err != nil {
+		userent, err = user.Lookup(u)
+	}
+	if err != nil {
+		log.Fatalf("Unable to find user %v: %v", u, err)
+	}
+
+	uid, err := strconv.Atoi(userent.Uid)
+	if err != nil {
+		log.Fatalf("Invalid uid: %v", userent.Uid)
+	}
+	gid, err := strconv.Atoi(userent.Gid)
+	if err != nil {
+		log.Fatalf("Invalid gid: %v", userent.Gid)
+	}
+
+	if err := syscall.Setgid(gid); err != nil {
+		log.Fatalf("setgid failed: %v", err)
+	}
+	if err := syscall.Setuid(uid); err != nil {
+		log.Fatalf("setuid failed: %v", err)
+	}
+}
+
+func executeProgram(name string, args []string) {
+	path, err := exec.LookPath(name)
+	if err != nil {
+		log.Printf("Unable to locate %v", name)
+		os.Exit(127)
+	}
+
+	if err := syscall.Exec(path, args, os.Environ()); err != nil {
+		panic(err)
+	}
+}
+
 // Sys Init code
 // This code is run INSIDE the container and is responsible for setting
 // up the environment before running the actual process
@@ -16,14 +61,9 @@ func SysInit() {
 		fmt.Println("You should not invoke docker-init manually")
 		os.Exit(1)
 	}
+	var u = flag.String("u", "", "username or uid")
 
-	path, err := exec.LookPath(os.Args[1])
-	if err != nil {
-		log.Printf("Unable to locate %v", os.Args[1])
-		os.Exit(127)
-	}
-
-	if err := syscall.Exec(path, os.Args[1:], os.Environ()); err != nil {
-		panic(err)
-	}
+	flag.Parse()
+	changeUser(*u)
+	executeProgram(flag.Arg(0), flag.Args())
 }