Skip to content

Commit

Permalink
auth: fetch tokens from client side
Browse files Browse the repository at this point in the history
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
  • Loading branch information
tonistiigi committed Sep 15, 2020
1 parent a256307 commit 1f94445
Show file tree
Hide file tree
Showing 14 changed files with 3,041 additions and 149 deletions.
74 changes: 39 additions & 35 deletions cmd/buildctl/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"io"
"os"

"github.com/containerd/console"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/cmd/buildctl/build"
Expand All @@ -15,7 +14,7 @@ import (
"github.com/moby/buildkit/session/auth/authprovider"
"github.com/moby/buildkit/session/sshforward/sshprovider"
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/progress/progressui"
"github.com/moby/buildkit/util/progress/progresswriter"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -204,7 +203,6 @@ func buildAction(clicontext *cli.Context) error {
return err
}

ch := make(chan *client.SolveStatus)
eg, ctx := errgroup.WithContext(bccommon.CommandContext(clicontext))

solveOpt := client.SolveOpt{
Expand Down Expand Up @@ -246,53 +244,59 @@ func buildAction(clicontext *cli.Context) error {
}
}

eg.Go(func() error {
resp, err := c.Solve(ctx, def, solveOpt, ch)
if err != nil {
return err
}
for k, v := range resp.ExporterResponse {
logrus.Debugf("exporter response: %s=%s", k, v)
}
// not using shared context to not disrupt display but let is finish reporting errors
pw, err := progresswriter.NewPrinter(context.TODO(), os.Stderr, clicontext.String("progress"))
if err != nil {
return err
})
}

displayCh := ch
if traceEnc != nil {
displayCh = make(chan *client.SolveStatus)
traceCh := make(chan *client.SolveStatus)
pw = progresswriter.Tee(pw, traceCh)
eg.Go(func() error {
defer close(displayCh)
for s := range ch {
for s := range traceCh {
if err := traceEnc.Encode(s); err != nil {
logrus.Error(err)
return err
}
displayCh <- s
}
return nil
})
}
mw := progresswriter.NewMultiWriter(pw)

eg.Go(func() error {
var c console.Console
progressOpt := clicontext.String("progress")
var writers []progresswriter.Writer
for _, at := range attachable {
if s, ok := at.(interface {
SetLogger(progresswriter.Logger)
}); ok {
w := mw.WithPrefix("", false)
s.SetLogger(func(s *client.SolveStatus) {
w.Status() <- s
})
writers = append(writers, w)
}
}

switch progressOpt {
case "auto", "tty":
cf, err := console.ConsoleFromFile(os.Stderr)
if err != nil && progressOpt == "tty" {
return err
eg.Go(func() error {
defer func() {
for _, w := range writers {
close(w.Status())
}
c = cf
case "plain":
default:
return errors.Errorf("invalid progress value : %s", progressOpt)
}()
resp, err := c.Solve(ctx, def, solveOpt, progresswriter.ResetTime(mw.WithPrefix("", false)).Status())
if err != nil {
return err
}

// not using shared context to not disrupt display but let is finish reporting errors
return progressui.DisplaySolveStatus(context.TODO(), "", c, os.Stderr, displayCh)
for k, v := range resp.ExporterResponse {
logrus.Debugf("exporter response: %s=%s", k, v)
}
return err
})

err = eg.Wait()
eg.Go(func() error {
<-pw.Done()
return pw.Err()
})

return err
return eg.Wait()
}
94 changes: 94 additions & 0 deletions session/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@ package auth

import (
"context"
"crypto/subtle"
"math/rand"
"sync"

"github.com/moby/buildkit/session"
"github.com/moby/buildkit/util/grpcerrors"
"github.com/pkg/errors"
"golang.org/x/crypto/nacl/sign"
"google.golang.org/grpc/codes"
)

var salt []byte
var saltOnce sync.Once

// getSalt returns unique component per daemon restart to avoid persistent keys
func getSalt() []byte {
saltOnce.Do(func() {
salt = make([]byte, 32)
rand.Read(salt)
})
return salt
}

func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session, username, secret string, err error) {
return func(host string) (string, string, string, error) {
var sessionID, user, secret string
Expand All @@ -34,3 +51,80 @@ func CredentialsFunc(sm *session.Manager, g session.Group) func(string) (session
return sessionID, user, secret, nil
}
}

func FetchToken(req *FetchTokenRequest, sm *session.Manager, g session.Group) (resp *FetchTokenResponse, err error) {
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())

resp, err = client.FetchToken(ctx, req)
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return resp, nil
}

func VerifyTokenAuthority(host string, pubKey *[32]byte, sm *session.Manager, g session.Group) (sessionID string, ok bool, err error) {
var verified bool
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())

payload := make([]byte, 32)
rand.Read(payload)
resp, err := client.VerifyTokenAuthority(ctx, &VerifyTokenAuthorityRequest{
Host: host,
Salt: getSalt(),
Payload: payload,
})
if err != nil {
if grpcerrors.Code(err) == codes.Unimplemented {
return nil
}
return err
}
var dt []byte
dt, ok = sign.Open(nil, resp.Signed, pubKey)
if ok && subtle.ConstantTimeCompare(dt, payload) == 1 {
verified = true
}
sessionID = id
return nil
})
if err != nil {
return "", false, err
}
return sessionID, verified, nil
}

func GetTokenAuthority(host string, sm *session.Manager, g session.Group) (sessionID string, pubKey *[32]byte, err error) {
err = sm.Any(context.TODO(), g, func(ctx context.Context, id string, c session.Caller) error {
client := NewAuthClient(c.Conn())

resp, err := client.GetTokenAuthority(ctx, &GetTokenAuthorityRequest{
Host: host,
Salt: getSalt(),
})
if err != nil {
if grpcerrors.Code(err) == codes.Unimplemented || grpcerrors.Code(err) == codes.Unavailable {
return nil
}
return err
}
if len(resp.PublicKey) != 32 {
return errors.Errorf("invalid pubkey length %d", len(pubKey))
}

sessionID = id
pubKey = new([32]byte)
copy((*pubKey)[:], resp.PublicKey)
return nil
})
if err != nil {
return "", nil, err
}
return sessionID, pubKey, nil
}
Loading

0 comments on commit 1f94445

Please sign in to comment.