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
Collaborator

Signed-off-by: Akihiro Suda [email protected]

- 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 [email protected] | 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

Signed-off-by: Akihiro Suda <[email protected]>
@AkihiroSuda
Copy link
Collaborator Author

(probably this is too late for v18.09)

@AkihiroSuda
Copy link
Collaborator Author

@tonistiigi @tiborvass @ijc

…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 [email protected] | 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 <[email protected]>
@codecov-io
Copy link

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

Copy link
Collaborator

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM 😍

@tonistiigi
Copy link
Member

@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
Copy link
Collaborator

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
Copy link
Collaborator

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
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
Copy link
Member

thaJeztah commented Oct 6, 2018 via email

@tonistiigi
Copy link
Member

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
Copy link
Collaborator

@cpuguy83 @thaJeztah so are you okay with this?

Copy link
Collaborator

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Collaborator

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
@GordonTheTurtle GordonTheTurtle added this to the 19.03.0 milestone Oct 9, 2018
@AkihiroSuda
Copy link
Collaborator Author

Is this ready for 18.09?

@seemethere
Copy link
Contributor

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
Copy link
Member

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

@rmoriz
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
Copy link
Member

@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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants