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

build: add SSH agent socket forwarder (`docker build --ssh $SSHMOUNTID=$SSH_AUTH_SOCK`) #1419

Merged
merged 2 commits into from Oct 9, 2018

Conversation

@AkihiroSuda
Copy link
Member

AkihiroSuda commented Oct 5, 2018

Signed-off-by: Akihiro Suda suda.akihiro@lab.ntt.co.jp

- What I did

This commit adds SSH agent socket forwarder (docker build --ssh $SSHMOUNTID=$SSH_AUTH_SOCK) .

Unlike docker build --secret, docker build --ssh allows the build container to use SSH keys with passphrases.

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ docker build --ssh default=$SSH_AUTH_SOCK ...

This feature requires the daemon with CapExecMountSSH build capability (moby/moby#37973) .

Currently, the official Dockerfile frontend does not provide the syntax for using the SSH forwarder.

However, the experimental RUN --mount=type=ssh syntax can be enabled by using
the Dockerfile frontend image built with the BUILDTAGS="dfrunmount dfssh", via the # syntax = "shebang".

The Dockerfile for the Dockerfile frontend is available at https://github.com/moby/buildkit/tree/master/frontend/dockerfile/cmd/dockerfile-frontend .
A pre-built image is also available as tonistiigi/dockerfile:ssh20181002 .

An example Dockerfile with RUN --mount=type=ssh:

# syntax = tonistiigi/dockerfile:ssh20181002
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 | tee /hello
# "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here

More info available at moby/buildkit#608, moby/buildkit#655

- How I did it

See above

- How to verify it

See above

- Description for the changelog

build: add SSH agent socket forwarder (docker build --ssh $SSHMOUNTID=$SSH_AUTH_SOCK)

- A picture of a cute animal (not mandatory but encouraged)

penguin

bump up buildkit
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
@AkihiroSuda

This comment has been minimized.

Copy link
Member Author

AkihiroSuda commented Oct 5, 2018

(probably this is too late for v18.09)

@AkihiroSuda

This comment has been minimized.

Copy link
Member Author

AkihiroSuda commented Oct 5, 2018

build: add SSH agent socket forwarder (`docker build --ssh $SSHMOUNTI…
…D=$SSH_AUTH_SOCK`)

Unlike `docker build --secret`, `docker build --ssh` allows the build container to
use SSH keys with passphrases.

  $ eval $(ssh-agent)
  $ ssh-add ~/.ssh/id_rsa
  (Input your passphrase here)
  $ docker build --ssh default=$SSH_AUTH_SOCK ...

This feature requires the daemon with `CapExecMountSSH` build capability (moby/moby#37973) .

Currently, the official Dockerfile frontend does not provide the syntax for using the SSH forwarder.

However, the experimental `RUN --mount=type=ssh` syntax can be enabled by using
the Dockerfile frontend image built with the `BUILDTAGS="dfrunmount dfssh"`, via the `# syntax =` "shebang".

The Dockerfile for the Dockerfile frontend is available at  github.com/moby/buildkit/frontend/dockerfile/cmd/dockerfile-frontend)
The pre-built image is also available as `tonistiigi/dockerfile:ssh20181002` .

An example Dockerfile with `RUN --mount=type=ssh`:

  # syntax = tonistiigi/dockerfile:ssh20181002
  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 | tee /hello
  # "Welcome to GitLab, @GITLAB_USERNAME_ASSOCIATED_WITH_SSHKEY" should be printed here

More info available at moby/buildkit#608, moby/buildkit#655

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

@AkihiroSuda AkihiroSuda force-pushed the AkihiroSuda:dfssh branch from acb992d to db7399a Oct 5, 2018

@codecov-io

This comment has been minimized.

Copy link

codecov-io commented Oct 5, 2018

Codecov Report

Merging #1419 into master will decrease coverage by 0.05%.
The diff coverage is 8.69%.

@@            Coverage Diff             @@
##           master    #1419      +/-   ##
==========================================
- Coverage   54.26%   54.21%   -0.06%     
==========================================
  Files         289      289              
  Lines       19331    19353      +22     
==========================================
+ Hits        10490    10492       +2     
- Misses       8165     8185      +20     
  Partials      676      676
@vdemeester
Copy link
Member

vdemeester left a comment

SGTM 😍

@tonistiigi

This comment has been minimized.

Copy link
Member

tonistiigi commented Oct 5, 2018

@AkihiroSuda @tiborvass @vdemeester Are we sure about this syntax. I don't have better ideas but didn't give it that much thought when I added this in buildctl. The default constant seems weird but don't really have a way around that.

Btw. docker build --ssh default=$SSH_AUTH_SOCK is the same as docker build --ssh default.

@tiborvass

This comment has been minimized.

Copy link
Contributor

tiborvass commented Oct 5, 2018

For the record, the easiest way is to do docker build --ssh default without even specifying the auth socket. Tested it with tonistiigi/dockerfile:ssh20181005 which has support for required as so: RUN --mount=type=ssh,required ...

LGTM

@tiborvass

This comment has been minimized.

Copy link
Contributor

tiborvass commented Oct 5, 2018

@tonistiigi I think the word default is fine. For those wondering why we need a word at all: the rationale is that we should enable security-minded people who want to specify different keys for different projects/endpoints. Those can be differentiated via IDs for RUN --mount.

RUN --mount=type=ssh,id=myrepo1 ssh ...
RUN --mount=type=ssh,id=myrepo2 ssh ...

A CI could do docker build --ssh myrepo1=/path/to/myrepo1-readonly.pem --ssh myrepo2=/path/to/myrepo2-readonly.pem ... while a user using an SSH agent would simply have to do: docker build --ssh myrepo1 --ssh myrepo2 ...

In order to allow that granularity, we need a default ID... and I'm fine with default.

@cpuguy83

This comment has been minimized.

Copy link
Collaborator

cpuguy83 commented Oct 6, 2018

I would call this something like "forward-ssh" or "ssh-agent".
Other than that, I wonder if there's some magic we can do with the flag parser to have the flag value be optional and rather treat it like a bool flag that can potentially have a string value.

@thaJeztah

This comment has been minimized.

Copy link
Member

thaJeztah commented Oct 6, 2018

@tonistiigi

This comment has been minimized.

Copy link
Member

tonistiigi commented Oct 7, 2018

Note that this syntax allows direct keys as well, and that should be the preferred way to use in CI (with special deploy keys). So this is not only for forwarding the pre-created ssh agent socket.

@tiborvass

This comment has been minimized.

Copy link
Contributor

tiborvass commented Oct 8, 2018

@cpuguy83 @thaJeztah so are you okay with this?

@cpuguy83
Copy link
Collaborator

cpuguy83 left a comment

Spoke with @tiborvass on this at length.
In short, here's what's happening:

--ssh default is really --ssh default=${SSH_AUTH_SOCK}.
This could just as easily be --ssh default=/path/to/private.key.

What happens here is buildkit (in the client) determines if the value is a socket or a regular file and creates an agent accordingly. The buildkit daemon can later send a request for the agent with the requested key.
The container will then get an SSH_AUTH_SOCK environment variable and the socket mounted inside.

I still think the flag name could be a bit more descriptive --forward-ssh or --ssh-key, but tbh --ssh works as well and I can't think of another use for the flag.

As for magic, in the CLI flag... if it's even possible to do it, we can add it later without breaking anything.

LGTM

@tiborvass

This comment has been minimized.

Copy link
Contributor

tiborvass commented Oct 9, 2018

Thanks @cpuguy83 ! Just to clarify, the magic referred to is to be able to parse --ssh alone without argument to mean the same thing as --ssh default. It would be a bit too magical and could be prone to error cases. Agree that for now we can keep it simple.

@tiborvass tiborvass merged commit ab50c2f into docker:master Oct 9, 2018

8 of 9 checks passed

codecov/patch 8.69% of diff hit (target 50%)
Details
ci/circleci: cross Your tests passed on CircleCI!
Details
ci/circleci: lint Your tests passed on CircleCI!
Details
ci/circleci: shellcheck Your tests passed on CircleCI!
Details
ci/circleci: test Your tests passed on CircleCI!
Details
ci/circleci: validate Your tests passed on CircleCI!
Details
codecov/project 54.21% (-0.06%) compared to 608b663
Details
continuous-integration/jenkins/pr-head This commit looks good
Details
dco-signed All commits are signed

@GordonTheTurtle GordonTheTurtle added this to the 19.03.0 milestone Oct 9, 2018

@AkihiroSuda

This comment has been minimized.

Copy link
Member Author

AkihiroSuda commented Oct 10, 2018

Is this ready for 18.09?

@seemethere

This comment has been minimized.

Copy link
Member

seemethere commented Oct 10, 2018

Feature complete date for 18.09 was back in September so this most likely will not make the GA for 18.09.0

@thaJeztah

This comment has been minimized.

Copy link
Member

thaJeztah commented Oct 10, 2018

Added docs/revisit; we could use some documentation about this feature

@rmoriz

This comment has been minimized.

Copy link

rmoriz commented Dec 21, 2018

The ssh socket is owned and accessibly by root only, e.g.

# syntax=docker/dockerfile:1.0.0-experimental
FROM alpine
RUN apk add --no-cache openssh-client \
   && adduser -h /example -S example example

USER example
RUN --mount=type=ssh ssh-add -l
#8 [3/3] RUN --mount=type=ssh ssh-add -l
#8       digest: sha256:b08486fd10670778bf8ca6bdc0f5950c74035d5c7f458ad24c381b7652ce1dd2
#8         name: "[3/3] RUN --mount=type=ssh ssh-add -l"
#8      started: 2018-12-21 17:24:51.397207862 +0000 UTC
#8 2.410 Error connecting to agent: Permission denied
#8    completed: 2018-12-21 17:24:54.266487196 +0000 UTC
#8     duration: 2.869279334s
#8        error: "executor failed running [/bin/sh -c ssh-add -l]: exit code: 2"

(Docker version 18.09.0, build 4d60db4)

@thaJeztah

This comment has been minimized.

Copy link
Member

thaJeztah commented Dec 23, 2018

@rmoriz could you open an issue for that in the buildkit repository? https://github.com/moby/buildkit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.