Implemented support to run as a different user (through the -u flag)
This commit is contained in:
parent
ec21a2d364
commit
6de3e8a22d
|
@ -49,6 +49,7 @@ type Container struct {
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Hostname string
|
Hostname string
|
||||||
|
User string
|
||||||
Ram int64
|
Ram int64
|
||||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||||
OpenStdin bool // Open stdin
|
OpenStdin bool // Open stdin
|
||||||
|
@ -270,10 +271,12 @@ func (container *Container) Start() error {
|
||||||
"-f", container.lxcConfigPath,
|
"-f", container.lxcConfigPath,
|
||||||
"--",
|
"--",
|
||||||
"/sbin/init",
|
"/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...)
|
params = append(params, container.Args...)
|
||||||
|
|
||||||
container.cmd = exec.Command("/usr/bin/lxc-start", params...)
|
container.cmd = exec.Command("/usr/bin/lxc-start", params...)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"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) {
|
func TestMultipleContainers(t *testing.T) {
|
||||||
docker, err := newTestDocker()
|
docker, err := newTestDocker()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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))
|
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]
|
id := future.RandomId()[:8]
|
||||||
container, err := srv.containers.Create(id, cmd, args, img.Layers,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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_attach := cmd.Bool("a", false, "Attach stdin and stdout")
|
||||||
fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
|
fl_stdin := cmd.Bool("i", false, "Keep stdin open even if not attached")
|
||||||
fl_tty := cmd.Bool("t", false, "Allocate a pseudo-tty")
|
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")
|
fl_comment := cmd.String("c", "", "Comment")
|
||||||
if err := cmd.Parse(args); err != nil {
|
if err := cmd.Parse(args); err != nil {
|
||||||
return 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)
|
return errors.New("No such image: " + name)
|
||||||
}
|
}
|
||||||
// Create new container
|
// 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 {
|
if err != nil {
|
||||||
return errors.New("Error creating container: " + err.Error())
|
return errors.New("Error creating container: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
58
sysinit.go
58
sysinit.go
|
@ -1,13 +1,58 @@
|
||||||
package docker
|
package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/user"
|
||||||
|
"strconv"
|
||||||
"syscall"
|
"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
|
// Sys Init code
|
||||||
// This code is run INSIDE the container and is responsible for setting
|
// This code is run INSIDE the container and is responsible for setting
|
||||||
// up the environment before running the actual process
|
// up the environment before running the actual process
|
||||||
|
@ -16,14 +61,9 @@ func SysInit() {
|
||||||
fmt.Println("You should not invoke docker-init manually")
|
fmt.Println("You should not invoke docker-init manually")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
var u = flag.String("u", "", "username or uid")
|
||||||
|
|
||||||
path, err := exec.LookPath(os.Args[1])
|
flag.Parse()
|
||||||
if err != nil {
|
changeUser(*u)
|
||||||
log.Printf("Unable to locate %v", os.Args[1])
|
executeProgram(flag.Arg(0), flag.Args())
|
||||||
os.Exit(127)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syscall.Exec(path, os.Args[1:], os.Environ()); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue