Skip to content

Commit 347b5c5

Browse files
committed
go.mod: experimental integration of gomodjail (library sandbox)
https://github.com/AkihiroSuda/gomodjail gomodjail imposes syscall restrictions on a specific set of Go modules (excepts ones that use unsafe pointers, reflections, etc.), so as to mitigate their potential vulnerabilities and supply chain attack vectors. Usage: ``` gomodjail run --go-mod=./go.mod -- nerdctl run hello-world ``` or ``` gomodjail pack --go-mod=./go.mod /usr/local/bin/nerdctl ./nerdctl.gomodjail run hello-world ``` Hint: use `git diff --word-diff` for reviewing the changes in this commit Signed-off-by: Akihiro Suda <[email protected]>
1 parent 3f7a7a8 commit 347b5c5

File tree

7 files changed

+97
-31
lines changed

7 files changed

+97
-31
lines changed

.github/workflows/test.yml

+21-3
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ jobs:
214214
test-integration-rootless:
215215
needs: build-dependencies
216216
timeout-minutes: 40
217-
name: "${{ matrix.target }} | ${{ matrix.containerd }} | ${{ matrix.rootlesskit }} | ${{ matrix.ubuntu }}"
217+
name: "${{ matrix.target }} | ${{ matrix.containerd }} | ${{ matrix.rootlesskit }} | ${{ matrix.ubuntu }} || ${{ matrix.nerdctl }}"
218218
runs-on: "${{ matrix.runner }}"
219219
strategy:
220220
fail-fast: false
@@ -226,30 +226,47 @@ jobs:
226226
target: rootless
227227
runner: "ubuntu-22.04"
228228
arch: amd64
229+
nerdctl: ""
230+
comment: ""
229231
- ubuntu: 24.04
230232
containerd: v2.0.4
231233
rootlesskit: v2.3.4
232234
target: rootless
233235
arch: amd64
234236
runner: "ubuntu-24.04"
237+
nerdctl: ""
238+
comment: ""
235239
- ubuntu: 24.04
236240
containerd: v2.0.4
237241
rootlesskit: v2.3.4
238242
target: rootless
239243
arch: arm64
240244
runner: "ubuntu-24.04-arm"
245+
nerdctl: ""
246+
comment: ""
241247
- ubuntu: 24.04
242248
containerd: v2.0.4
243249
rootlesskit: v2.3.4
244250
target: rootless-port-slirp4netns
245251
arch: amd64
246252
runner: "ubuntu-24.04"
253+
nerdctl: ""
254+
comment: ""
255+
- ubuntu: 24.04
256+
containerd: v2.0.3
257+
rootlesskit: v2.3.4
258+
target: rootless
259+
arch: arm64
260+
runner: "ubuntu-24.04"
261+
nerdctl: "nerdctl.gomodjail"
262+
comment: "Flaky, not a blocker for merging PRs"
247263
env:
248264
CONTAINERD_VERSION: "${{ matrix.containerd }}"
249265
ARCH: "${{ matrix.arch }}"
250266
UBUNTU_VERSION: "${{ matrix.ubuntu }}"
251267
ROOTLESSKIT_VERSION: "${{ matrix.rootlesskit }}"
252268
TEST_TARGET: "test-integration-${{ matrix.target }}"
269+
NERDCTL: "${{ matrix.nerdctl }}"
253270
steps:
254271
- name: "Set up AppArmor"
255272
if: matrix.ubuntu == '24.04'
@@ -296,9 +313,10 @@ jobs:
296313
fi
297314
echo "WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622}" >> "$GITHUB_ENV"
298315
- name: "Test (network driver=slirp4netns, port driver=builtin)"
299-
run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=false
316+
run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} -e NERDCTL=${NERDCTL} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=false
300317
- name: "Test (network driver=slirp4netns, port driver=builtin) (flaky)"
301-
run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=true
318+
if: matrix.nerdctl != 'nerdctl.gomodjail'
319+
run: docker run -t --rm --privileged -e WORKAROUND_ISSUE_622=${WORKAROUND_ISSUE_622} -e NERDCTL=${NERDCTL} ${TEST_TARGET} /test-integration-rootless.sh ./hack/test-integration.sh -test.only-flaky=true
302320

303321
build:
304322
timeout-minutes: 5

Dockerfile

+26-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ ARG CONTAINERD_FUSE_OVERLAYFS_VERSION=v2.1.2@BINARY
3939
ARG TINI_VERSION=v0.19.0@BINARY
4040
# Extra deps: Debug
4141
ARG BUILDG_VERSION=v0.4.1@BINARY
42+
# Extra deps: gomodjail
43+
# TODO: pin the deps
44+
ARG MAKESELF_VERSION=v2.5.0
45+
ARG GOMODJAIL_VERSION=main
4246

4347
# Test deps
4448
# Currently, the Docker Official Images and the test deps are not pinned by the hash
@@ -118,7 +122,8 @@ RUN xx-go --wrap && \
118122
xx-verify --static cmd/ipfs/ipfs && cp -a cmd/ipfs/ipfs /out/${TARGETARCH}
119123

120124
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS build-base
121-
RUN apk add --no-cache make git curl
125+
# tar: required by makeself (executed by `gomodjail unpack`)
126+
RUN apk add --no-cache make git curl tar
122127
RUN git config --global advice.detachedHead false
123128
ADD hack/git-checkout-tag-with-hash.sh /usr/local/bin/
124129

@@ -231,6 +236,24 @@ RUN ROOTLESSKIT_VERSION=${ROOTLESSKIT_VERSION/@BINARY}; \
231236
tar xzf "${fname}" -C /out/bin && \
232237
rm -f "${fname}" /out/bin/rootlesskit-docker-proxy && \
233238
echo "- RootlessKit: ${ROOTLESSKIT_VERSION}" >> /out/share/doc/nerdctl-full/README.md
239+
# makeself is needed by `gomodjail pack`.
240+
# TODO: remove dependency on makeself https://github.com/AkihiroSuda/gomodjail/issues/31
241+
ARG MAKESELF_VERSION
242+
RUN fname="makeself-${MAKESELF_VERSION/v}.run" && \
243+
curl -o "${fname}" -fsSL --proto '=https' --tlsv1.2 "https://github.com/megastep/makeself/releases/download/release-${MAKESELF_VERSION/v}/${fname}" && \
244+
grep "${fname}" "/SHA256SUMS.d/makeself-${MAKESELF_VERSION}" | sha256sum -c && \
245+
dirname="makeself-${MAKESELF_VERSION/v}" && \
246+
sh "${fname}" && \
247+
cp -a "${dirname}"/makeself-header.sh /usr/local/bin/ && \
248+
cp -a "${dirname}"/makeself.sh /usr/local/bin/makeself && \
249+
rm -rf "${fname}" "${dirname}"
250+
ARG GOMODJAIL_VERSION
251+
RUN git clone https://github.com/AkihiroSuda/gomodjail.git /go/src/github.com/AkihiroSuda/gomodjail && \
252+
cd /go/src/github.com/AkihiroSuda/gomodjail && \
253+
git checkout "${GOMODJAIL_VERSION}" && \
254+
make STATIC=1 && \
255+
cp -a _output/bin/gomodjail /out/bin/ && \
256+
echo "- gomodjail: ${GOMODJAIL_VERSION}" >> /out/share/doc/nerdctl-full/README.md
234257

235258
RUN echo "" >> /out/share/doc/nerdctl-full/README.md && \
236259
echo "## License" >> /out/share/doc/nerdctl-full/README.md && \
@@ -245,6 +268,8 @@ COPY . /go/src/github.com/containerd/nerdctl
245268
RUN { echo "# nerdctl (full distribution)"; echo "- nerdctl: $(cd /go/src/github.com/containerd/nerdctl && git describe --tags)"; cat /out/share/doc/nerdctl-full/README.md; } > /out/share/doc/nerdctl-full/README.md.new; mv /out/share/doc/nerdctl-full/README.md.new /out/share/doc/nerdctl-full/README.md
246269
WORKDIR /go/src/github.com/containerd/nerdctl
247270
RUN BINDIR=/out/bin make binaries install
271+
RUN /out/bin/gomodjail pack --go-mod=/go/src/github.com/containerd/nerdctl/go.mod /out/bin/nerdctl && \
272+
cp -a nerdctl.gomodjail /out/bin/
248273
COPY README.md /out/share/doc/nerdctl/
249274
COPY docs /out/share/doc/nerdctl/docs
250275
RUN (cd /out && find ! -type d | sort | xargs sha256sum > /tmp/SHA256SUMS ) && \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
4d2fa9d898be22c63bb3c6bb7cc3dc97237700dea6d6ad898dcbec0289df0bc4 makeself-2.5.0.run

Dockerfile.d/test-integration-rootless.sh

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# limitations under the License.
1616

1717
set -eux -o pipefail
18+
: "${NERDCTL:=}"
1819
if [[ "$(id -u)" = "0" ]]; then
1920
# Ensure securityfs is mounted for apparmor to work
2021
if ! mountpoint -q /sys/kernel/security; then
@@ -32,7 +33,7 @@ if [[ "$(id -u)" = "0" ]]; then
3233

3334
# Switch to the rootless user via SSH
3435
systemctl start ssh
35-
exec ssh -o StrictHostKeyChecking=no rootless@localhost "$0" "$@"
36+
exec ssh -o StrictHostKeyChecking=no rootless@localhost NERDCTL="$NERDCTL" "$0" "$@"
3637
else
3738
containerd-rootless-setuptool.sh install
3839
if grep -q "options use-vc" /etc/resolv.conf; then
@@ -63,5 +64,5 @@ EOF
6364
# Once ssh-ed, we lost the Dockerfile working dir, so, get back in the nerdctl checkout
6465
cd /go/src/github.com/containerd/nerdctl
6566
# We also lose the PATH (and SendEnv=PATH would require sshd config changes)
66-
exec env PATH="/usr/local/go/bin:$PATH" "$@"
67+
exec env PATH="/usr/local/go/bin:$PATH" NERDCTL="$NERDCTL" "$@"
6768
fi

go.mod

+23-18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//gomodjail:confined
12
module github.com/containerd/nerdctl/v2
23

34
go 1.23.0
@@ -9,52 +10,52 @@ require (
910
github.com/compose-spec/compose-go/v2 v2.4.9
1011
github.com/containerd/accelerated-container-image v1.3.0
1112
github.com/containerd/cgroups/v3 v3.0.5
12-
github.com/containerd/console v1.0.4
13+
github.com/containerd/console v1.0.4 //gomodjail:unconfined
1314
github.com/containerd/containerd/api v1.8.0
14-
github.com/containerd/containerd/v2 v2.0.4
15-
github.com/containerd/continuity v0.4.5
15+
github.com/containerd/containerd/v2 v2.0.4 //gomodjail:unconfined
16+
github.com/containerd/continuity v0.4.5 //gomodjail:unconfined
1617
github.com/containerd/errdefs v1.0.0
17-
github.com/containerd/fifo v1.1.0
18+
github.com/containerd/fifo v1.1.0 //gomodjail:unconfined
1819
github.com/containerd/go-cni v1.1.12
1920
github.com/containerd/imgcrypt/v2 v2.0.1
2021
github.com/containerd/log v0.1.0
2122
github.com/containerd/nerdctl/mod/tigron v0.0.0
2223
github.com/containerd/nydus-snapshotter v0.15.0
23-
github.com/containerd/platforms v1.0.0-rc.1
24+
github.com/containerd/platforms v1.0.0-rc.1 //gomodjail:unconfined
2425
github.com/containerd/stargz-snapshotter v0.16.3
2526
github.com/containerd/stargz-snapshotter/estargz v0.16.3
2627
github.com/containerd/stargz-snapshotter/ipfs v0.16.3
2728
github.com/containerd/typeurl/v2 v2.2.3
28-
github.com/containernetworking/cni v1.2.3
29+
github.com/containernetworking/cni v1.2.3 //gomodjail:unconfined
2930
github.com/containernetworking/plugins v1.6.2
3031
github.com/coreos/go-iptables v0.8.0
3132
github.com/coreos/go-systemd/v22 v22.5.0
3233
github.com/cyphar/filepath-securejoin v0.4.1
3334
github.com/distribution/reference v0.6.0
3435
github.com/docker/cli v28.0.2+incompatible
35-
github.com/docker/docker v28.0.2+incompatible
36+
github.com/docker/docker v28.0.2+incompatible //gomodjail:unconfined
3637
github.com/docker/go-connections v0.5.0
3738
github.com/docker/go-units v0.5.0
38-
github.com/fahedouch/go-logrotate v0.2.1
39-
github.com/fatih/color v1.18.0
39+
github.com/fahedouch/go-logrotate v0.2.1 //gomodjail:unconfined
40+
github.com/fatih/color v1.18.0 //gomodjail:unconfined
4041
github.com/fluent/fluent-logger-golang v1.9.0
4142
github.com/fsnotify/fsnotify v1.8.0
4243
github.com/go-viper/mapstructure/v2 v2.2.1
4344
github.com/ipfs/go-cid v0.5.0
4445
github.com/klauspost/compress v1.18.0
45-
github.com/mattn/go-isatty v0.0.20
46+
github.com/mattn/go-isatty v0.0.20 //gomodjail:unconfined
4647
github.com/moby/sys/mount v0.3.4
4748
github.com/moby/sys/signal v0.7.1
48-
github.com/moby/sys/userns v0.1.0
49-
github.com/moby/term v0.5.2
50-
github.com/muesli/cancelreader v0.2.2
49+
github.com/moby/sys/userns v0.1.0 //gomodjail:unconfined
50+
github.com/moby/term v0.5.2 //gomodjail:unconfined
51+
github.com/muesli/cancelreader v0.2.2 //gomodjail:unconfined
5152
github.com/opencontainers/go-digest v1.0.0
5253
github.com/opencontainers/image-spec v1.1.1
5354
github.com/opencontainers/runtime-spec v1.2.1
5455
github.com/pelletier/go-toml/v2 v2.2.3
55-
github.com/rootless-containers/bypass4netns v0.4.2
56-
github.com/rootless-containers/rootlesskit/v2 v2.3.4
57-
github.com/spf13/cobra v1.9.1
56+
github.com/rootless-containers/bypass4netns v0.4.2 //gomodjail:unconfined
57+
github.com/rootless-containers/rootlesskit/v2 v2.3.4 //gomodjail:unconfined
58+
github.com/spf13/cobra v1.9.1 //gomodjail:unconfined
5859
github.com/spf13/pflag v1.0.6
5960
github.com/vishvananda/netlink v1.3.0
6061
github.com/vishvananda/netns v0.0.5
@@ -63,8 +64,8 @@ require (
6364
golang.org/x/crypto v0.36.0
6465
golang.org/x/net v0.37.0
6566
golang.org/x/sync v0.12.0
66-
golang.org/x/sys v0.31.0
67-
golang.org/x/term v0.30.0
67+
golang.org/x/sys v0.31.0 //gomodjail:unconfined
68+
golang.org/x/term v0.30.0 //gomodjail:unconfined
6869
golang.org/x/text v0.23.0
6970
gopkg.in/yaml.v3 v3.0.1
7071
gotest.tools/v3 v3.5.2
@@ -105,6 +106,7 @@ require (
105106
github.com/moby/sys/mountinfo v0.7.2 // indirect
106107
github.com/moby/sys/sequential v0.6.0 // indirect
107108
github.com/moby/sys/symlink v0.3.0 // indirect
109+
//gomodjail:unconfined
108110
github.com/moby/sys/user v0.3.0 // indirect
109111
github.com/mr-tron/base58 v1.2.0 // indirect
110112
github.com/multiformats/go-base32 v0.1.0 // indirect
@@ -118,6 +120,7 @@ require (
118120
github.com/philhofer/fwd v1.1.3-0.20240612014219-fbbf4953d986 // indirect
119121
github.com/pkg/errors v0.9.1 // indirect
120122
github.com/sasha-s/go-deadlock v0.3.5 // indirect
123+
//gomodjail:unconfined
121124
github.com/sirupsen/logrus v1.9.3 // indirect
122125
github.com/smallstep/pkcs7 v0.1.1 // indirect
123126
github.com/spaolacci/murmur3 v1.1.0 // indirect
@@ -135,7 +138,9 @@ require (
135138
go.opentelemetry.io/otel/trace v1.31.0 // indirect
136139
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
137140
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
141+
//gomodjail:unconfined
138142
google.golang.org/grpc v1.69.4 // indirect
143+
//gomodjail:unconfined
139144
google.golang.org/protobuf v1.36.2 // indirect
140145
lukechampine.com/blake3 v1.3.0 // indirect
141146
)

pkg/testutil/nerdtest/command.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,28 @@ func newNerdCommand(conf test.Config, t *testing.T) *nerdCommand {
5757
trgt := getTarget()
5858
switch trgt {
5959
case targetNerdctl:
60-
binary, err = exec.LookPath(trgt)
60+
nerdctl := trgt
61+
if env := os.Getenv("NERDCTL"); env != "" {
62+
nerdctl = env
63+
}
64+
binary, err = exec.LookPath(nerdctl)
6165
if err != nil {
62-
t.Fatalf("unable to find binary %q: %v", trgt, err)
66+
t.Fatalf("unable to find binary %q: %v", nerdctl, err)
6367
}
6468
// Set the default namespace if we do not have something already
6569
if conf.Read(Namespace) == "" {
6670
conf.Write(Namespace, defaultNamespace)
6771
}
6872
case targetDocker:
69-
binary, err = exec.LookPath(trgt)
73+
docker := trgt
74+
if env := os.Getenv("DOCKER"); env != "" {
75+
docker = env
76+
}
77+
binary, err = exec.LookPath(docker)
7078
if err != nil {
71-
t.Fatalf("unable to find binary %q: %v", trgt, err)
79+
t.Fatalf("unable to find binary %q: %v", docker, err)
7280
}
73-
if err = exec.Command("docker", "compose", "version").Run(); err != nil {
81+
if err = exec.Command(binary, "compose", "version").Run(); err != nil {
7482
t.Fatalf("docker does not support compose: %v", err)
7583
}
7684
default:

pkg/testutil/testutil.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -793,13 +793,21 @@ func newBase(t *testing.T, ns string, ipv6Compatible bool, kubernetesCompatible
793793
var err error
794794
switch base.Target {
795795
case Nerdctl:
796-
base.Binary, err = exec.LookPath("nerdctl")
796+
nerdctl := "nerdctl"
797+
if env := os.Getenv("NERDCTL"); env != "" {
798+
nerdctl = env
799+
}
800+
base.Binary, err = exec.LookPath(nerdctl)
797801
if err != nil {
798802
t.Fatal(err)
799803
}
800804
base.Args = []string{"--namespace=" + ns}
801805
case Docker:
802-
base.Binary, err = exec.LookPath("docker")
806+
docker := "docker"
807+
if env := os.Getenv("DOCKER"); env != "" {
808+
docker = env
809+
}
810+
base.Binary, err = exec.LookPath(docker)
803811
if err != nil {
804812
t.Fatal(err)
805813
}

0 commit comments

Comments
 (0)