From fa92effc4bfa1bc66e95cf7647f7f17a60055f1d Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 2 Oct 2018 14:25:26 +0900 Subject: [PATCH] dockerfile: add support for RUN --mount=type=ssh * Needs to be compiled with `dfrunmount dfssh` * Implemented options: * `type`(required): needs to be `ssh` * `target`(optional): the socket path in the container * `id`(optional): id Test script: #!/bin/bash set -exu -o pipefail REF=localhost:5000/dfssh:latest ssh-add -l sudo buildctl build --frontend=dockerfile.v0 --local context=. --local dockerfile=frontend/dockerfile/cmd/dockerfile-frontend \ --frontend-opt "build-arg:BUILDTAGS=dfrunmount dfssh" \ --exporter=image --exporter-opt name=$REF --exporter-opt push=true mkdir -p /tmp/foo cd /tmp/foo cat << EOF > Dockerfile # syntax=$REF FROM alpine RUN apk add --no-cache openssh-client RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan gitlab.com >> ~/.ssh/known_hosts RUN --mount=type=ssh ssh git@gitlab.com # "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here EOF sudo buildctl build --ssh default=$SSH_AUTH_SOCK --progress=plain --frontend=dockerfile.v0 --local context=. --local dockerfile=. Signed-off-by: Akihiro Suda --- client/llb/exec.go | 6 +++++ .../dockerfile2llb/convert_nossh.go | 13 +++++++++ .../dockerfile2llb/convert_runmount.go | 8 ++++++ .../dockerfile/dockerfile2llb/convert_ssh.go | 27 +++++++++++++++++++ .../dockerfile/instructions/commands_nossh.go | 7 +++++ .../instructions/commands_runmount.go | 7 +++++ .../dockerfile/instructions/commands_ssh.go | 7 +++++ hack/test | 1 + 8 files changed, 76 insertions(+) create mode 100644 frontend/dockerfile/dockerfile2llb/convert_nossh.go create mode 100644 frontend/dockerfile/dockerfile2llb/convert_ssh.go create mode 100644 frontend/dockerfile/instructions/commands_nossh.go create mode 100644 frontend/dockerfile/instructions/commands_ssh.go diff --git a/client/llb/exec.go b/client/llb/exec.go index 42dd4ffa0..a216aab48 100644 --- a/client/llb/exec.go +++ b/client/llb/exec.go @@ -496,6 +496,12 @@ func SSHID(id string) SSHOption { }) } +func SSHSocketTarget(target string) SSHOption { + return sshOptionFunc(func(si *SSHInfo) { + si.Target = target + }) +} + func SSHSocketOpt(target string, uid, gid, mode int) SSHOption { return sshOptionFunc(func(si *SSHInfo) { si.Target = target diff --git a/frontend/dockerfile/dockerfile2llb/convert_nossh.go b/frontend/dockerfile/dockerfile2llb/convert_nossh.go new file mode 100644 index 000000000..8b8afdc38 --- /dev/null +++ b/frontend/dockerfile/dockerfile2llb/convert_nossh.go @@ -0,0 +1,13 @@ +// +build dfrunmount,!dfssh + +package dockerfile2llb + +import ( + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/frontend/dockerfile/instructions" + "github.com/pkg/errors" +) + +func dispatchSSH(m *instructions.Mount) (llb.RunOption, error) { + return nil, errors.Errorf("ssh mounts not allowed") +} diff --git a/frontend/dockerfile/dockerfile2llb/convert_runmount.go b/frontend/dockerfile/dockerfile2llb/convert_runmount.go index e42c8614e..a06ab9a7c 100644 --- a/frontend/dockerfile/dockerfile2llb/convert_runmount.go +++ b/frontend/dockerfile/dockerfile2llb/convert_runmount.go @@ -65,6 +65,14 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []* out = append(out, secret) continue } + if mount.Type == instructions.MountTypeSSH { + ssh, err := dispatchSSH(mount) + if err != nil { + return nil, err + } + out = append(out, ssh) + continue + } if mount.ReadOnly { mountOpts = append(mountOpts, llb.Readonly) } diff --git a/frontend/dockerfile/dockerfile2llb/convert_ssh.go b/frontend/dockerfile/dockerfile2llb/convert_ssh.go new file mode 100644 index 000000000..b651ad660 --- /dev/null +++ b/frontend/dockerfile/dockerfile2llb/convert_ssh.go @@ -0,0 +1,27 @@ +// +build dfssh dfextall + +package dockerfile2llb + +import ( + "github.com/moby/buildkit/client/llb" + "github.com/moby/buildkit/frontend/dockerfile/instructions" + "github.com/pkg/errors" +) + +func dispatchSSH(m *instructions.Mount) (llb.RunOption, error) { + if m.Source != "" { + return nil, errors.Errorf("ssh does not support source") + } + opts := []llb.SSHOption{llb.SSHID(m.CacheID)} + + if m.Target != "" { + // TODO(AkihiroSuda): support specifying permission bits + opts = append(opts, llb.SSHSocketTarget(m.Target)) + } + + if !m.Required { + opts = append(opts, llb.SSHOptional) + } + + return llb.AddSSHSocket(opts...), nil +} diff --git a/frontend/dockerfile/instructions/commands_nossh.go b/frontend/dockerfile/instructions/commands_nossh.go new file mode 100644 index 000000000..de8095845 --- /dev/null +++ b/frontend/dockerfile/instructions/commands_nossh.go @@ -0,0 +1,7 @@ +// +build !dfssh,!dfextall + +package instructions + +func isSSHMountsSupported() bool { + return false +} diff --git a/frontend/dockerfile/instructions/commands_runmount.go b/frontend/dockerfile/instructions/commands_runmount.go index 8cccb76ae..1c33ceed8 100644 --- a/frontend/dockerfile/instructions/commands_runmount.go +++ b/frontend/dockerfile/instructions/commands_runmount.go @@ -14,12 +14,14 @@ const MountTypeBind = "bind" const MountTypeCache = "cache" const MountTypeTmpfs = "tmpfs" const MountTypeSecret = "secret" +const MountTypeSSH = "ssh" var allowedMountTypes = map[string]struct{}{ MountTypeBind: {}, MountTypeCache: {}, MountTypeTmpfs: {}, MountTypeSecret: {}, + MountTypeSSH: {}, } const MountSharingShared = "shared" @@ -47,6 +49,11 @@ func isValidMountType(s string) bool { return false } } + if s == "ssh" { + if !isSSHMountsSupported() { + return false + } + } _, ok := allowedMountTypes[s] return ok } diff --git a/frontend/dockerfile/instructions/commands_ssh.go b/frontend/dockerfile/instructions/commands_ssh.go new file mode 100644 index 000000000..8e591d3e3 --- /dev/null +++ b/frontend/dockerfile/instructions/commands_ssh.go @@ -0,0 +1,7 @@ +// +build dfssh dfextall + +package instructions + +func isSSHMountsSupported() bool { + return true +} diff --git a/hack/test b/hack/test index 3456b4691..55ccf9d39 100755 --- a/hack/test +++ b/hack/test @@ -16,4 +16,5 @@ docker run --rm $iid go build ./frontend/dockerfile/cmd/dockerfile-frontend docker run --rm $iid go build -tags dfrunmount ./frontend/dockerfile/cmd/dockerfile-frontend docker run --rm $iid go build -tags "dfrunmount dfsecrets" ./frontend/dockerfile/cmd/dockerfile-frontend +docker run --rm $iid go build -tags "dfrunmount dfssh" ./frontend/dockerfile/cmd/dockerfile-frontend docker run --rm $iid go build -tags dfextall ./frontend/dockerfile/cmd/dockerfile-frontend