Skip to content

Commit

Permalink
simplify rootless
Browse files Browse the repository at this point in the history
Signed-off-by: Akihiro Suda <[email protected]>
  • Loading branch information
AkihiroSuda committed Oct 16, 2018
1 parent 8db1def commit 048130d
Show file tree
Hide file tree
Showing 41 changed files with 36 additions and 4,319 deletions.
5 changes: 3 additions & 2 deletions docs/rootless.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Rootless mode (Experimental)

Requirements:
- runc `ecd55a4135e0a26de884ce436442914f945b1e76` (May 30, 2018) or later
- runc `a00bf0190895aa465a5fbed0268888e2c8ddfe85` (Oct 15, 2018) or later
- Some distros such as Debian (excluding Ubuntu) and Arch Linux require `echo 1 > /proc/sys/kernel/unprivileged_userns_clone`
- `newuidmap` and `newgidmap` need to be installed on the host. These commands are provided by the `uidmap` package.
- `/etc/subuid` and `/etc/subgid` should contain >= 65536 sub-IDs. e.g. `penguin:231072:65536`.
Expand Down Expand Up @@ -45,6 +45,7 @@ unshared# buildkitd
* `overlayfs` snapshotter is not supported except Ubuntu-flavored kernel: http://kernel.ubuntu.com/git/ubuntu/ubuntu-artful.git/commit/fs/overlayfs?h=Ubuntu-4.13.0-25.29&id=0a414bdc3d01f3b61ed86cfe3ce8b63a9240eba7
* containerd worker is not supported ( pending PR: https://github.com/containerd/containerd/pull/2006 )
* Network namespace is not used at the moment.
* Cgroups is disabled.

### Terminal 2:

Expand All @@ -61,7 +62,7 @@ $ docker run --name buildkitd -d --privileged -p 1234:1234 buildkit-rootless --
```

`docker run` requires `--privileged` but the BuildKit daemon is executed as a normal user.
See [`moby/moby#36597`](https://github.com/moby/moby/issues/36597, [`kubernetes/community#1934`](https://github.com/kubernetes/community/pull/1934) and [Jess's blog](https://blog.jessfraz.com/post/building-container-images-securely-on-kubernetes/) for the ongoing work to remove this requirement
See [`docker/cli#1347`](https://github.com/docker/cli/pull/1347) for the ongoing work to remove this requirement

```
$ docker exec buildkitd id
Expand Down
2 changes: 1 addition & 1 deletion examples/buildkit0/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
var opt buildOpt
flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker")
flag.StringVar(&opt.containerd, "containerd", "v1.2.0-rc.1", "containerd version")
flag.StringVar(&opt.runc, "runc", "dd56ece8236d6d9e5bed4ea0c31fe53c7b873ff4", "runc version")
flag.StringVar(&opt.runc, "runc", "a00bf0190895aa465a5fbed0268888e2c8ddfe85", "runc version")
flag.Parse()

bk := buildkit(opt)
Expand Down
2 changes: 1 addition & 1 deletion examples/buildkit1/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
var opt buildOpt
flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker")
flag.StringVar(&opt.containerd, "containerd", "v1.2.0-rc.1", "containerd version")
flag.StringVar(&opt.runc, "runc", "dd56ece8236d6d9e5bed4ea0c31fe53c7b873ff4", "runc version")
flag.StringVar(&opt.runc, "runc", "a00bf0190895aa465a5fbed0268888e2c8ddfe85", "runc version")
flag.Parse()

bk := buildkit(opt)
Expand Down
2 changes: 1 addition & 1 deletion examples/buildkit2/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
var opt buildOpt
flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker")
flag.StringVar(&opt.containerd, "containerd", "v1.2.0-rc.1", "containerd version")
flag.StringVar(&opt.runc, "runc", "dd56ece8236d6d9e5bed4ea0c31fe53c7b873ff4", "runc version")
flag.StringVar(&opt.runc, "runc", "a00bf0190895aa465a5fbed0268888e2c8ddfe85", "runc version")
flag.Parse()

bk := buildkit(opt)
Expand Down
2 changes: 1 addition & 1 deletion examples/buildkit3/buildkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func main() {
var opt buildOpt
flag.BoolVar(&opt.withContainerd, "with-containerd", true, "enable containerd worker")
flag.StringVar(&opt.containerd, "containerd", "v1.2.0-rc.1", "containerd version")
flag.StringVar(&opt.runc, "runc", "dd56ece8236d6d9e5bed4ea0c31fe53c7b873ff4", "runc version")
flag.StringVar(&opt.runc, "runc", "a00bf0190895aa465a5fbed0268888e2c8ddfe85", "runc version")
flag.StringVar(&opt.buildkit, "buildkit", "master", "buildkit version")
flag.Parse()

Expand Down
4 changes: 0 additions & 4 deletions frontend/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1604,10 +1604,6 @@ RUN ["ls"]
}

func testUser(t *testing.T, sb integration.Sandbox) {
if sb.Rootless() {
t.Skip("only for rootful worker, due to lack of support for additional gids (https://github.com/opencontainers/runc/issues/1835)")
}

f := getFrontend(t, sb)

dockerfile := []byte(`
Expand Down
2 changes: 1 addition & 1 deletion hack/dockerfiles/test.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG RUNC_VERSION=00dc70017d222b178a002ed30e9321b12647af2d
ARG RUNC_VERSION=a00bf0190895aa465a5fbed0268888e2c8ddfe85
ARG CONTAINERD_VERSION=v1.2.0-rc.1
# containerd v1.0 for integration tests
ARG CONTAINERD10_VERSION=v1.0.3
Expand Down
2 changes: 1 addition & 1 deletion hack/dockerfiles/test.buildkit.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax = tonistiigi/dockerfile:runmount20180925

ARG RUNC_VERSION=00dc70017d222b178a002ed30e9321b12647af2d
ARG RUNC_VERSION=a00bf0190895aa465a5fbed0268888e2c8ddfe85
ARG CONTAINERD_VERSION=v1.2.0-rc.1
# containerd v1.0 for integration tests
ARG CONTAINERD10_VERSION=v1.0.3
Expand Down
113 changes: 20 additions & 93 deletions util/rootless/specconv/specconv_linux.go
Original file line number Diff line number Diff line change
@@ -1,113 +1,40 @@
package specconv

import (
"os"
"sort"
"strings"

"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/user"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)

// ToRootless converts spec to be compatible with "rootless" runc.
// * Adds userns (Note: since we are already in userns, ideally we should not need to do this. runc-side issue is tracked at https://github.com/opencontainers/runc/issues/1837)
// * Fix up mount flags (same as above)
// * Replace /sys with bind-mount (FIXME: we don't need to do this if netns is unshared)
// * Remove /sys mount
// * Remove cgroups
//
// See docs/rootless.md for the supported runc revision.
func ToRootless(spec *specs.Spec) error {
if !system.RunningInUserNS() {
return errors.New("needs to be in user namespace")
}
uidMap, err := user.CurrentProcessUIDMap()
if err != nil && !os.IsNotExist(err) {
return err
}
gidMap, err := user.CurrentProcessUIDMap()
if err != nil && !os.IsNotExist(err) {
return err
}
return toRootless(spec, uidMap, gidMap)
}

// toRootless was forked from github.com/opencontainers/runc/libcontainer/specconv
func toRootless(spec *specs.Spec, uidMap, gidMap []user.IDMap) error {
if err := configureUserNS(spec, uidMap, gidMap); err != nil {
return err
}
if err := configureMounts(spec); err != nil {
return err
}

// Remove cgroup settings.
spec.Linux.Resources = nil
spec.Linux.CgroupsPath = ""
return nil
}

// configureUserNS add suserns and the current ID map to the spec.
// Since we are already in userns, ideally we should not need to add userns.
// However, currently rootless runc always requires userns to be added.
// https://github.com/opencontainers/runc/issues/1837
func configureUserNS(spec *specs.Spec, uidMap, gidMap []user.IDMap) error {
spec.Linux.Namespaces = append(spec.Linux.Namespaces, specs.LinuxNamespace{
Type: specs.UserNamespace,
})

sort.Slice(uidMap, func(i, j int) bool { return uidMap[i].ID < uidMap[j].ID })
uNextContainerID := int64(0)
for _, u := range uidMap {
spec.Linux.UIDMappings = append(spec.Linux.UIDMappings,
specs.LinuxIDMapping{
HostID: uint32(u.ID),
ContainerID: uint32(uNextContainerID),
Size: uint32(u.Count),
})
uNextContainerID += int64(u.Count)
}
sort.Slice(gidMap, func(i, j int) bool { return gidMap[i].ID < gidMap[j].ID })
gNextContainerID := int64(0)
for _, g := range gidMap {
spec.Linux.GIDMappings = append(spec.Linux.GIDMappings,
specs.LinuxIDMapping{
HostID: uint32(g.ID),
ContainerID: uint32(gNextContainerID),
Size: uint32(g.Count),
})
gNextContainerID += int64(g.Count)
}
return nil
}

func configureMounts(spec *specs.Spec) error {
// Remove /sys mount because we can't mount /sys when the daemon netns
// is not unshared from the host.
//
// Instead, we could bind-mount /sys from the host, however, `rbind, ro`
// does not make /sys/fs/cgroup read-only (and we can't bind-mount /sys
// without rbind)
//
// PR for making /sys/fs/cgroup read-only is proposed, but it is very
// complicated: https://github.com/opencontainers/runc/pull/1869
//
// For buildkit usecase, we suppose we don't need to provide /sys to
// containers and remove /sys mount as a workaround.
var mounts []specs.Mount
for _, mount := range spec.Mounts {
// Ignore all mounts that are under /sys, because we add /sys later.
if strings.HasPrefix(mount.Destination, "/sys") {
continue
}

// Remove all gid= and uid= mappings.
// Since we are already in userns, ideally we should not need to do this.
// https://github.com/opencontainers/runc/issues/1837
var options []string
for _, option := range mount.Options {
if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
options = append(options, option)
}
}
mount.Options = options
mounts = append(mounts, mount)
}

// Add the sysfs mount as an rbind, because we can't mount /sys unless we have netns.
// TODO: keep original /sys mount when we have netns.
mounts = append(mounts, specs.Mount{
Source: "/sys",
Destination: "/sys",
Type: "none",
Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
})
spec.Mounts = mounts

// Remove cgroups so as to avoid `container_linux.go:337: starting container process caused "process_linux.go:280: applying cgroup configuration for process caused \"mkdir /sys/fs/cgroup/cpuset/buildkit: permission denied\""`
spec.Linux.Resources = nil
spec.Linux.CgroupsPath = ""
return nil
}
42 changes: 0 additions & 42 deletions util/rootless/specconv/specconv_linux_test.go

This file was deleted.

5 changes: 1 addition & 4 deletions vendor.conf
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ github.com/gogo/googleapis b23578765ee54ff6bceff57f397d833bf4ca6869
github.com/golang/protobuf v1.1.0
github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc 00dc70017d222b178a002ed30e9321b12647af2d
github.com/opencontainers/runc a00bf0190895aa465a5fbed0268888e2c8ddfe85
github.com/Microsoft/go-winio v0.4.11
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
Expand Down Expand Up @@ -67,6 +67,3 @@ github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1c
# used by dockerfile tests
gotest.tools v2.1.0
github.com/google/go-cmp v0.2.0

# used by rootless spec conv test
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0

This file was deleted.

Loading

0 comments on commit 048130d

Please sign in to comment.