Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow running without securityContext.procMount=Unmasked (BuildKit v0.4) #221

Merged
merged 4 commits into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
21 changes: 7 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
ARG RUNC_VERSION=9f9c96235cc97674e935002fc3d78361b696a69e
FROM golang:1.10-alpine AS gobuild-base
FROM golang:1.11-alpine AS gobuild-base
RUN apk add --no-cache \
bash \
build-base \
Expand All @@ -9,13 +8,6 @@ RUN apk add --no-cache \
linux-headers \
make

FROM gobuild-base AS runc
ARG RUNC_VERSION
RUN git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
&& cd "$GOPATH/src/github.com/opencontainers/runc" \
&& make static BUILDTAGS="seccomp" EXTRA_FLAGS="-buildmode pie" EXTRA_LDFLAGS="-extldflags \\\"-fno-PIC -static\\\"" \
&& mv runc /usr/bin/runc

FROM gobuild-base AS img
WORKDIR /go/src/github.com/genuinetools/img
COPY . .
Expand Down Expand Up @@ -43,18 +35,19 @@ FROM alpine:3.8 AS base
MAINTAINER Jessica Frazelle <jess@linux.com>
RUN apk add --no-cache git
COPY --from=img /usr/bin/img /usr/bin/img
COPY --from=runc /usr/bin/runc /usr/bin/runc
COPY --from=idmap /usr/bin/newuidmap /usr/bin/newuidmap
COPY --from=idmap /usr/bin/newgidmap /usr/bin/newgidmap
RUN chmod u+s /usr/bin/newuidmap /usr/bin/newgidmap \
&& adduser -D -u 1000 user \
&& mkdir -p /run/user/1000 \
&& chown -R user /run/user/1000 /home/user \
&& echo user:100000:65536 | tee /etc/subuid | tee /etc/subgid
# As of v3.8.1, Alpine does not set SUID bit on the busybox version of /bin/su.
# However, future version may set SUID bit on /bin/su.
# We lock the root account so as to disable su completely.
RUN passwd -l root
# In previous version of `alpine:3.8`, the root was not locked and su-able
# without any password when SUID bit is set on `/bin/su`.
#
# As of 3/15/2019, the root is locked by default, but we expliciltly lock the
# root just in case.
RUN passwd -l root || true

FROM base AS debug
RUN apk add --no-cache bash strace
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ include basic.mk
prebuild: runc

RUNCBUILDDIR=$(BUILDDIR)/src/github.com/opencontainers/runc
RUNCCOMMIT=7cb3cde1f49eae53fb8fff5012c0750a64eb928b
$(RUNCBUILDDIR):
git clone --depth 1 https://github.com/opencontainers/runc.git "$@"
git clone https://github.com/opencontainers/runc.git "$@"
( cd "$@" ; git checkout $(RUNCCOMMIT) )

$(RUNCBUILDDIR)/runc: $(RUNCBUILDDIR)
GOPATH=$(BUILDDIR) $(MAKE) -C "$(RUNCBUILDDIR)" static BUILDTAGS="seccomp apparmor"
Expand Down
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,32 @@ $ sudo emerge -a app-emulation/img

#### Running with Docker

This currently **does not work** without `--privileged`, to track the progress of making this work in a container without the `--privileged` flag see [upstream patches](#upstream-patches).
Docker image `r.j3ss.co/img` is configured to be executed as an unprivileged user with UID 1000 and it does not need `--privileged` since `img` v0.6.0.

```console
$ docker run --rm -it \
--name img \
--volume $(pwd):/home/user/src:ro \ # for the build context and dockerfile, can be read-only since we won't modify it
--workdir /home/user/src \ # set the builder working directory
--volume "${HOME}/.docker:/root/.docker:ro" \ # for credentials to push to docker hub or a registry
--privileged \
--security-opt seccomp=unconfined --security-opt apparmor=unconfined \ # required by runc
r.j3ss.co/img build -t user/myimage .
```

To enable PID namespace isolation (which disallows build containers to `kill(2)` the `img` process), you need to specify
`--privileged` so that build containers can mount `/proc` with unshared PID namespaces.
Note that even with `--privileged`, `img` works as an unprivileged user with UID 1000.

See [docker/cli patch](#upstream-patches) for how to allow mounting `/proc` without `--privileged`.

### Running with Kubernetes

Since `img` v0.6.0, you don't need to specify any `securityContext` for running `img` as a Kubernetes container.

However, to enable PID namespace isolation, you need to set `securityContext.procMount` to `Unmasked` (or simply set
`securityContext.privileged` to `true`).
`securityContext.procMount` is available since Kubernetes 1.12 with Docker 18.06/containerd 1.2/CRI-O 1.12.

## Usage

Make sure you have user namespace support enabled. On some distros (Debian and
Expand Down Expand Up @@ -608,4 +622,4 @@ be unprivileged.

A lot of this is based on the work of [moby/buildkit](https://github.com/moby/buildkit).
Thanks [@tonistiigi](https://github.com/tonistiigi) and
[@AkihiroSuda](https://github.com/AkihiroSuda)!
[@AkihiroSuda](https://github.com/AkihiroSuda)!
22 changes: 12 additions & 10 deletions client/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import (

// Pull retrieves an image from a remote registry.
func (c *Client) Pull(ctx context.Context, image string) (*ListedImage, error) {
sm, err := c.getSessionManager()
if err != nil {
return nil, err
}
// Parse the image name and tag.
named, err := reference.ParseNormalizedNamed(image)
if err != nil {
Expand Down Expand Up @@ -46,18 +50,17 @@ func (c *Client) Pull(ctx context.Context, image string) (*ListedImage, error) {

// Create the source for the pull.
srcOpt := containerimage.SourceOpt{
SessionManager: opt.SessionManager,
Snapshotter: opt.Snapshotter,
ContentStore: opt.ContentStore,
Applier: opt.Applier,
CacheAccessor: cm,
ImageStore: opt.ImageStore,
Snapshotter: opt.Snapshotter,
ContentStore: opt.ContentStore,
Applier: opt.Applier,
CacheAccessor: cm,
ImageStore: opt.ImageStore,
}
src, err := containerimage.NewSource(srcOpt)
if err != nil {
return nil, err
}
s, err := src.Resolve(ctx, identifier)
s, err := src.Resolve(ctx, identifier, sm)
if err != nil {
return nil, err
}
Expand All @@ -76,9 +79,8 @@ func (c *Client) Pull(ctx context.Context, image string) (*ListedImage, error) {
return nil, err
}
expOpt := imageexporter.Opt{
SessionManager: opt.SessionManager,
Images: opt.ImageStore,
ImageWriter: iw,
Images: opt.ImageStore,
ImageWriter: iw,
}
exp, err := imageexporter.New(expOpt)
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion client/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,9 @@ func (c *Client) Push(ctx context.Context, image string, insecure bool) error {
return fmt.Errorf("getting image %q failed: %v", image, err)
}

return push.Push(ctx, opt.SessionManager, opt.ContentStore, imgObj.Target.Digest, image, insecure, opt.ResolveOptionsFunc)
sm, err := c.getSessionManager()
if err != nil {
return err
}
return push.Push(ctx, sm, opt.ContentStore, imgObj.Target.Digest, image, insecure, opt.ResolveOptionsFunc)
}
28 changes: 21 additions & 7 deletions client/workeropt.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package client
import (
"context"
"fmt"
"os/exec"
"path/filepath"
"syscall"
"time"

"github.com/containerd/containerd/content/local"
Expand All @@ -17,6 +19,7 @@ import (
"github.com/genuinetools/img/types"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/executor"
executoroci "github.com/moby/buildkit/executor/oci"
"github.com/moby/buildkit/executor/runcexecutor"
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
"github.com/moby/buildkit/util/network"
Expand All @@ -31,10 +34,6 @@ import (

// createWorkerOpt creates a base.WorkerOpt to be used for a new worker.
func (c *Client) createWorkerOpt(withExecutor bool) (opt base.WorkerOpt, err error) {
sm, err := c.getSessionManager()
if err != nil {
return opt, err
}
// Create the metadata store.
md, err := metadata.NewStore(filepath.Join(c.root, "metadata.db"))
if err != nil {
Expand Down Expand Up @@ -65,8 +64,9 @@ func (c *Client) createWorkerOpt(withExecutor bool) (opt base.WorkerOpt, err err
var exe executor.Executor
if withExecutor {
exeOpt := runcexecutor.Opt{
Root: filepath.Join(c.root, "executor"),
Rootless: unprivileged,
Root: filepath.Join(c.root, "executor"),
Rootless: unprivileged,
ProcessMode: processMode(),
}
exe, err = runcexecutor.New(exeOpt, network.Default())
if err != nil {
Expand Down Expand Up @@ -121,7 +121,6 @@ func (c *Client) createWorkerOpt(withExecutor bool) (opt base.WorkerOpt, err err
opt = base.WorkerOpt{
ID: id,
Labels: xlabels,
SessionManager: sm,
MetadataStore: md,
Executor: exe,
Snapshotter: containerdsnapshot.NewSnapshotter(mdb.Snapshotter(c.backend), contentStore, md, "buildkit", gc),
Expand All @@ -135,3 +134,18 @@ func (c *Client) createWorkerOpt(withExecutor bool) (opt base.WorkerOpt, err err

return opt, err
}

func processMode() executoroci.ProcessMode {
mountArgs := []string{"-t", "proc", "none", "/proc"}
cmd := exec.Command("mount", mountArgs...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Pdeathsig: syscall.SIGKILL,
Cloneflags: syscall.CLONE_NEWPID,
Unshareflags: syscall.CLONE_NEWNS,
}
if b, err := cmd.CombinedOutput(); err != nil {
logrus.Warnf("Process sandbox is not available, consider unmasking procfs: %v", string(b))
return executoroci.NoProcessSandbox
}
return executoroci.ProcessSandbox
}
12 changes: 11 additions & 1 deletion contrib/e2e-dockerfiles-build-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ build_and_push(){

echo "[In Container] Building ${REPO_URL}/${base}:${suite} for context ${build_dir}"
# Do the same but in a docker container.
docker run --rm --name img --volume $(pwd):/home/user/src:ro --workdir /home/user/src --privileged r.j3ss.co/img build -t ${REPO_URL}/${base}:${suite} ${build_dir}
name=${REPO_URL}-${base}-${suite}
set +e
docker run --name $name --volume $(pwd):/home/user/src:ro --workdir /home/user/src --privileged r.j3ss.co/img build --no-console -t ${REPO_URL}/${base}:${suite} ${build_dir} > /dev/null 2>&1
status=$?
set -e
if [[ $status != 0 ]]; then
docker logs $name
docker rm -f $name
exit $status
fi
docker rm -f $name

# on successful build, push the image
echo " --- "
Expand Down
48 changes: 19 additions & 29 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,41 @@ module github.com/genuinetools/img
replace github.com/hashicorp/go-immutable-radix => github.com/tonistiigi/go-immutable-radix v0.0.0-20170803185627-826af9ccf0fe

require (
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/Microsoft/hcsshim v0.7.4 // indirect
github.com/containerd/cgroups v0.0.0-20180917172123-5017d4e9a9cf // indirect
github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1
github.com/containerd/containerd v0.0.0-20180925133938-3bc4ba271e1c
github.com/containerd/cri v1.11.1 // indirect
github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260 // indirect
github.com/containerd/containerd v1.3.0-0.20190212172151-f5b0fa220df8
github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd // indirect
github.com/coreos/go-systemd v0.0.0-20180828140353-eee3db372b31 // indirect
github.com/coreos/go-systemd v0.0.0-20181031085051-9002847aa142
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/cyphar/filepath-securejoin v0.2.2
github.com/docker/cli v0.0.0-20180920165730-54c19e67f69c
github.com/docker/distribution v0.0.0-20180920194744-16128bbac47f
github.com/docker/docker v0.0.0-20180924202107-a9c061deec0f
github.com/docker/docker-ce v17.12.1-ce-rc2+incompatible // indirect
github.com/docker/cli v0.0.0-20190131223713-234462756460
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible
github.com/docker/docker v0.7.3-0.20190315021241-05e7d000f2fc
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-events v0.0.0-20170721190031-9461782956ad // indirect
github.com/docker/go-units v0.3.3
github.com/docker/libnetwork v0.0.0-20171208192558-822e5b59d346 // indirect
github.com/genuinetools/pkg v0.0.0-20180910213200-1c141f661797
github.com/genuinetools/reg v0.16.0
github.com/godbus/dbus v4.1.0+incompatible // indirect
github.com/godbus/dbus v4.1.0+incompatible
github.com/gogo/googleapis v1.1.0 // indirect
github.com/google/shlex v0.0.0-20150127133951-6f45313302b9 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/golang/protobuf v1.2.0
github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c // indirect
github.com/mitchellh/hashstructure v1.0.0 // indirect
github.com/moby/buildkit v0.3.2
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/moby/buildkit v0.4.0
github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc2.0.20181113215238-10d38b660a77
github.com/opencontainers/runtime-spec v1.0.1 // indirect
github.com/opencontainers/runtime-spec v1.0.1
github.com/opencontainers/selinux v1.0.0
github.com/opentracing-contrib/go-stdlib v0.0.0-20180702182724-07a764486eb1 // indirect
github.com/opentracing/opentracing-go v1.0.2 // indirect
github.com/pkg/errors v0.8.0
github.com/pkg/errors v0.8.1
github.com/seccomp/libseccomp-golang v0.9.0
github.com/sirupsen/logrus v1.0.6
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect
github.com/tonistiigi/fsutil v0.0.0-20181011223333-2862f6bc5ac9 // indirect
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/vishvananda/netlink v1.0.0 // indirect
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5
github.com/vishvananda/netlink v1.0.0
go.etcd.io/bbolt v1.3.1-etcd.8
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f
golang.org/x/sys v0.0.0-20180925112736-b09afc3d579e
google.golang.org/grpc v1.15.0
)
Loading