Skip to content

Commit a175773

Browse files
committed
Expose SSH authorization using client session
Signed-off-by: Tonis Tiigi <[email protected]>
1 parent d13de2e commit a175773

8 files changed

Lines changed: 683 additions & 16 deletions

File tree

builder/dockerfile/builder.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package dockerfile
22

33
import (
44
"bytes"
5-
"errors"
65
"fmt"
76
"io"
87
"io/ioutil"
@@ -21,9 +20,10 @@ import (
2120
"github.com/docker/docker/builder"
2221
"github.com/docker/docker/builder/dockerfile/parser"
2322
"github.com/docker/docker/client/session"
23+
"github.com/docker/docker/client/session/ssh"
2424
"github.com/docker/docker/image"
2525
"github.com/docker/docker/pkg/stringid"
26-
perrors "github.com/pkg/errors"
26+
"github.com/pkg/errors"
2727
"golang.org/x/net/context"
2828
)
2929

@@ -72,6 +72,7 @@ type Builder struct {
7272
fsCache *FSCache
7373
sessionGetter SessionGetter
7474
auth AuthConfigProvider
75+
sshAuthSock string
7576

7677
dockerfile *parser.Node
7778
runConfig *container.Config // runconfig for cmd, run, entrypoint etc.
@@ -119,14 +120,14 @@ func NewBuildManager(b builder.Backend, sg SessionGetter) (*BuildManager, error)
119120

120121
tmpdir, err := ioutil.TempDir("", "fscache")
121122
if err != nil {
122-
return nil, perrors.Wrap(err, "failed to create tmp directory")
123+
return nil, errors.Wrap(err, "failed to create tmp directory")
123124
}
124125

125126
fsCache, err := NewFSCache(FSCacheOpt{
126127
Backend: &tmpCacheBackend{tmpdir},
127128
})
128129
if err != nil {
129-
return nil, perrors.Wrap(err, "failed to create fscache")
130+
return nil, errors.Wrap(err, "failed to create fscache")
130131
}
131132
bm.fsCache = fsCache
132133
fsCache.RegisterTransport(ClientSessionTransportName, NewClientSessionTransport())
@@ -292,7 +293,7 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
292293
defer cancel()
293294
_, caller, err := b.sessionGetter.GetSession(ctx, b.options.SessionId)
294295
if err != nil {
295-
return "", perrors.Wrapf(err, "failed to get session for %s", b.options.SessionId)
296+
return "", errors.Wrapf(err, "failed to get session for %s", b.options.SessionId)
296297
}
297298

298299
if b.options.RemoteContext == "client-session" {
@@ -310,6 +311,18 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
310311
}
311312

312313
b.auth = NewAuthConfigProvider(b.options.AuthConfigs, caller)
314+
sshProvider, err := ssh.NewSSHAuthProvider("_main", caller)
315+
if err != nil && errors.Cause(err) != ssh.ErrNotSupported {
316+
return "", err
317+
}
318+
// TODO: lazy create
319+
sock, release, err := sshProvider.CreateListenSocket()
320+
if err != nil {
321+
return "", err
322+
}
323+
defer release()
324+
b.sshAuthSock = sock
325+
313326
logrus.Debugf("sync-time: %v", time.Since(st))
314327
} else {
315328
b.auth = NewAuthConfigProvider(b.options.AuthConfigs, nil)
@@ -326,7 +339,7 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
326339
total := len(b.dockerfile.Children)
327340
for _, n := range b.dockerfile.Children {
328341
if err := b.checkDispatch(n, false); err != nil {
329-
return "", perrors.Wrapf(err, "Dockerfile parse error line %d", n.StartLine)
342+
return "", errors.Wrapf(err, "Dockerfile parse error line %d", n.StartLine)
330343
}
331344
}
332345

@@ -367,7 +380,7 @@ func (b *Builder) build(stdout io.Writer, stderr io.Writer, out io.Writer) (stri
367380
}
368381
b.image, err = b.docker.SquashImage(b.image, fromID)
369382
if err != nil {
370-
return "", perrors.Wrap(err, "error squashing image")
383+
return "", errors.Wrap(err, "error squashing image")
371384
}
372385
}
373386

@@ -459,7 +472,7 @@ type tmpCacheBackend struct {
459472
func (tcb *tmpCacheBackend) Get(id string) (string, error) {
460473
d := filepath.Join(tcb.root, id)
461474
if err := os.MkdirAll(d, 0700); err != nil {
462-
return "", perrors.Wrapf(err, "failed to create tmp dir for %s", d)
475+
return "", errors.Wrapf(err, "failed to create tmp dir for %s", d)
463476
}
464477
return d, nil
465478
}

builder/dockerfile/internals.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/docker/docker/api/types"
2424
"github.com/docker/docker/api/types/backend"
2525
"github.com/docker/docker/api/types/container"
26+
"github.com/docker/docker/api/types/mount"
2627
"github.com/docker/docker/api/types/strslice"
2728
"github.com/docker/docker/builder"
2829
"github.com/docker/docker/builder/dockerfile/parser"
@@ -539,8 +540,21 @@ func (b *Builder) create() (string, error) {
539540
ExtraHosts: b.options.ExtraHosts,
540541
}
541542

543+
sockPath := "/run/.ssh_auth_sock"
544+
545+
if b.sshAuthSock != "" {
546+
m := mount.Mount{
547+
Type: mount.TypeBind,
548+
Source: b.sshAuthSock,
549+
Target: sockPath,
550+
}
551+
hostConfig.Mounts = []mount.Mount{m}
552+
}
553+
542554
config := *b.runConfig
543555

556+
b.runConfig.Env = append(b.runConfig.Env, "SSH_AUTH_SOCK="+sockPath)
557+
544558
// Create the container
545559
c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
546560
Config: b.runConfig,

cli/command/image/build.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/docker/docker/client/session/authsession"
3535
"github.com/docker/docker/client/session/fssession"
3636
"github.com/docker/docker/client/session/grpctransport"
37+
"github.com/docker/docker/client/session/ssh"
3738
"github.com/docker/docker/opts"
3839
"github.com/docker/docker/pkg/archive"
3940
"github.com/docker/docker/pkg/fileutils"
@@ -79,6 +80,7 @@ type buildOptions struct {
7980
networkMode string
8081
squash bool
8182
stream bool
83+
enableSSH bool
8284
}
8385

8486
// NewBuildCommand creates a new `docker build` command
@@ -131,6 +133,8 @@ func NewBuildCommand(dockerCli *command.DockerCli) *cobra.Command {
131133
flags.SetAnnotation("network", "version", []string{"1.25"})
132134
flags.Var(&options.extraHosts, "add-host", "Add a custom host-to-IP mapping (host:ip)")
133135

136+
flags.BoolVar(&options.enableSSH, "ssh", false, "Expose ssh-agent to the builder")
137+
134138
command.AddTrustVerificationFlags(flags)
135139

136140
flags.BoolVar(&options.squash, "squash", false, "Squash newly built layers into a single new layer")
@@ -443,11 +447,21 @@ func runBuild(dockerCli *command.DockerCli, options buildOptions) error {
443447
var authConfigs map[string]types.AuthConfig
444448
if grpcSession == nil {
445449
authConfigs, _ = dockerCli.GetAllCredentials()
450+
if options.enableSSH {
451+
return errors.Errorf("SSH can't be enabled in this daemon")
452+
}
446453
} else {
447454
authHandler := authsession.NewAuthconfigHandler("_main", &authCfgProvider{dockerCli}, func(registry string) {
448455
progressOutput.WriteProgress(progress.Progress{Action: "Authenticating to " + registry, LastUpdate: true})
449456
})
450457
grpcSession.Allow(authHandler)
458+
if options.enableSSH {
459+
sshHandler, err := ssh.NewSSHHandler("_main", ssh.SSHOpt{})
460+
if err != nil {
461+
return err
462+
}
463+
grpcSession.Allow(sshHandler)
464+
}
451465
}
452466

453467
if grpcSession != nil {

client/session/ssh/generate.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package ssh
2+
3+
//go:generate protoc --gogoslick_out=. wire.proto

0 commit comments

Comments
 (0)