mirror of
https://gitea.com/Lydanne/buildx.git
synced 2025-07-09 21:17:09 +08:00
vendor: update buildkit to v0.8
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
94
vendor/github.com/moby/buildkit/session/auth/auth.go
generated
vendored
94
vendor/github.com/moby/buildkit/session/auth/auth.go
generated
vendored
@ -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
|
||||
@ -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
|
||||
}
|
||||
|
1946
vendor/github.com/moby/buildkit/session/auth/auth.pb.go
generated
vendored
1946
vendor/github.com/moby/buildkit/session/auth/auth.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
37
vendor/github.com/moby/buildkit/session/auth/auth.proto
generated
vendored
37
vendor/github.com/moby/buildkit/session/auth/auth.proto
generated
vendored
@ -6,9 +6,11 @@ option go_package = "auth";
|
||||
|
||||
service Auth{
|
||||
rpc Credentials(CredentialsRequest) returns (CredentialsResponse);
|
||||
rpc FetchToken(FetchTokenRequest) returns (FetchTokenResponse);
|
||||
rpc GetTokenAuthority(GetTokenAuthorityRequest) returns (GetTokenAuthorityResponse);
|
||||
rpc VerifyTokenAuthority(VerifyTokenAuthorityRequest) returns (VerifyTokenAuthorityResponse);
|
||||
}
|
||||
|
||||
|
||||
message CredentialsRequest {
|
||||
string Host = 1;
|
||||
}
|
||||
@ -17,3 +19,36 @@ message CredentialsResponse {
|
||||
string Username = 1;
|
||||
string Secret = 2;
|
||||
}
|
||||
|
||||
message FetchTokenRequest {
|
||||
string ClientID = 1;
|
||||
string Host = 2;
|
||||
string Realm = 3;
|
||||
string Service = 4;
|
||||
repeated string Scopes = 5;
|
||||
}
|
||||
|
||||
message FetchTokenResponse {
|
||||
string Token = 1;
|
||||
int64 ExpiresIn = 2; // seconds
|
||||
int64 IssuedAt = 3; // timestamp
|
||||
}
|
||||
|
||||
message GetTokenAuthorityRequest {
|
||||
string Host = 1;
|
||||
bytes Salt = 2;
|
||||
}
|
||||
|
||||
message GetTokenAuthorityResponse {
|
||||
bytes PublicKey = 1;
|
||||
}
|
||||
|
||||
message VerifyTokenAuthorityRequest {
|
||||
string Host = 1;
|
||||
bytes Payload = 2;
|
||||
bytes Salt = 3;
|
||||
}
|
||||
|
||||
message VerifyTokenAuthorityResponse {
|
||||
bytes Signed = 1;
|
||||
}
|
||||
|
179
vendor/github.com/moby/buildkit/session/auth/authprovider/authprovider.go
generated
vendored
179
vendor/github.com/moby/buildkit/session/auth/authprovider/authprovider.go
generated
vendored
@ -2,24 +2,46 @@ package authprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
authutil "github.com/containerd/containerd/remotes/docker/auth"
|
||||
remoteserrors "github.com/containerd/containerd/remotes/errors"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/docker/cli/cli/config/configfile"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/session/auth"
|
||||
"github.com/moby/buildkit/util/progress/progresswriter"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/nacl/sign"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func NewDockerAuthProvider(stderr io.Writer) session.Attachable {
|
||||
return &authProvider{
|
||||
config: config.LoadDefaultConfigFile(stderr),
|
||||
config: config.LoadDefaultConfigFile(stderr),
|
||||
seeds: &tokenSeeds{dir: config.Dir()},
|
||||
loggerCache: map[string]struct{}{},
|
||||
}
|
||||
}
|
||||
|
||||
type authProvider struct {
|
||||
config *configfile.ConfigFile
|
||||
config *configfile.ConfigFile
|
||||
seeds *tokenSeeds
|
||||
logger progresswriter.Logger
|
||||
loggerCache map[string]struct{}
|
||||
|
||||
// The need for this mutex is not well understood.
|
||||
// Without it, the docker cli on OS X hangs when
|
||||
@ -28,17 +50,80 @@ type authProvider struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (ap *authProvider) SetLogger(l progresswriter.Logger) {
|
||||
ap.mu.Lock()
|
||||
ap.logger = l
|
||||
ap.mu.Unlock()
|
||||
}
|
||||
|
||||
func (ap *authProvider) Register(server *grpc.Server) {
|
||||
auth.RegisterAuthServer(server, ap)
|
||||
}
|
||||
|
||||
func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
|
||||
func (ap *authProvider) FetchToken(ctx context.Context, req *auth.FetchTokenRequest) (rr *auth.FetchTokenResponse, err error) {
|
||||
creds, err := ap.credentials(req.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
to := authutil.TokenOptions{
|
||||
Realm: req.Realm,
|
||||
Service: req.Service,
|
||||
Scopes: req.Scopes,
|
||||
Username: creds.Username,
|
||||
Secret: creds.Secret,
|
||||
}
|
||||
|
||||
if creds.Secret != "" {
|
||||
done := func(progresswriter.SubLogger) error {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
err = errors.Wrap(err, "failed to fetch oauth token")
|
||||
}()
|
||||
ap.mu.Lock()
|
||||
name := fmt.Sprintf("[auth] %v token for %s", strings.Join(trimScopePrefix(req.Scopes), " "), req.Host)
|
||||
if _, ok := ap.loggerCache[name]; !ok {
|
||||
progresswriter.Wrap(name, ap.logger, done)
|
||||
}
|
||||
ap.mu.Unlock()
|
||||
// try GET first because Docker Hub does not support POST
|
||||
// switch once support has landed
|
||||
resp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to)
|
||||
if err != nil {
|
||||
var errStatus remoteserrors.ErrUnexpectedStatus
|
||||
if errors.As(err, &errStatus) {
|
||||
// retry with POST request
|
||||
// As of September 2017, GCR is known to return 404.
|
||||
// As of February 2018, JFrog Artifactory is known to return 401.
|
||||
if (errStatus.StatusCode == 405 && to.Username != "") || errStatus.StatusCode == 404 || errStatus.StatusCode == 401 {
|
||||
resp, err := authutil.FetchTokenWithOAuth(ctx, http.DefaultClient, nil, "buildkit-client", to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toTokenResponse(resp.AccessToken, resp.IssuedAt, resp.ExpiresIn), nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return toTokenResponse(resp.Token, resp.IssuedAt, resp.ExpiresIn), nil
|
||||
}
|
||||
// do request anonymously
|
||||
resp, err := authutil.FetchToken(ctx, http.DefaultClient, nil, to)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to fetch anonymous token")
|
||||
}
|
||||
return toTokenResponse(resp.Token, resp.IssuedAt, resp.ExpiresIn), nil
|
||||
}
|
||||
|
||||
func (ap *authProvider) credentials(host string) (*auth.CredentialsResponse, error) {
|
||||
ap.mu.Lock()
|
||||
defer ap.mu.Unlock()
|
||||
if req.Host == "registry-1.docker.io" {
|
||||
req.Host = "https://index.docker.io/v1/"
|
||||
if host == "registry-1.docker.io" {
|
||||
host = "https://index.docker.io/v1/"
|
||||
}
|
||||
ac, err := ap.config.GetAuthConfig(req.Host)
|
||||
ac, err := ap.config.GetAuthConfig(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -51,3 +136,85 @@ func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRe
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (ap *authProvider) Credentials(ctx context.Context, req *auth.CredentialsRequest) (*auth.CredentialsResponse, error) {
|
||||
resp, err := ap.credentials(req.Host)
|
||||
if err != nil || resp.Secret != "" {
|
||||
ap.mu.Lock()
|
||||
defer ap.mu.Unlock()
|
||||
_, ok := ap.loggerCache[req.Host]
|
||||
ap.loggerCache[req.Host] = struct{}{}
|
||||
if !ok {
|
||||
return resp, progresswriter.Wrap(fmt.Sprintf("[auth] sharing credentials for %s", req.Host), ap.logger, func(progresswriter.SubLogger) error {
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (ap *authProvider) GetTokenAuthority(ctx context.Context, req *auth.GetTokenAuthorityRequest) (*auth.GetTokenAuthorityResponse, error) {
|
||||
key, err := ap.getAuthorityKey(req.Host, req.Salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &auth.GetTokenAuthorityResponse{PublicKey: key[32:]}, nil
|
||||
}
|
||||
|
||||
func (ap *authProvider) VerifyTokenAuthority(ctx context.Context, req *auth.VerifyTokenAuthorityRequest) (*auth.VerifyTokenAuthorityResponse, error) {
|
||||
key, err := ap.getAuthorityKey(req.Host, req.Salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv := new([64]byte)
|
||||
copy((*priv)[:], key)
|
||||
|
||||
return &auth.VerifyTokenAuthorityResponse{Signed: sign.Sign(nil, req.Payload, priv)}, nil
|
||||
}
|
||||
|
||||
func (ap *authProvider) getAuthorityKey(host string, salt []byte) (ed25519.PrivateKey, error) {
|
||||
if v, err := strconv.ParseBool(os.Getenv("BUILDKIT_NO_CLIENT_TOKEN")); err == nil && v {
|
||||
return nil, status.Errorf(codes.Unavailable, "client side tokens disabled")
|
||||
}
|
||||
|
||||
creds, err := ap.credentials(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seed, err := ap.seeds.getSeed(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mac := hmac.New(sha256.New, salt)
|
||||
if creds.Secret != "" {
|
||||
mac.Write(seed)
|
||||
enc := json.NewEncoder(mac)
|
||||
enc.Encode(creds)
|
||||
}
|
||||
|
||||
sum := mac.Sum(nil)
|
||||
|
||||
return ed25519.NewKeyFromSeed(sum[:ed25519.SeedSize]), nil
|
||||
}
|
||||
|
||||
func toTokenResponse(token string, issuedAt time.Time, expires int) *auth.FetchTokenResponse {
|
||||
resp := &auth.FetchTokenResponse{
|
||||
Token: token,
|
||||
ExpiresIn: int64(expires),
|
||||
}
|
||||
if !issuedAt.IsZero() {
|
||||
resp.IssuedAt = issuedAt.Unix()
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func trimScopePrefix(scopes []string) []string {
|
||||
out := make([]string, len(scopes))
|
||||
for i, s := range scopes {
|
||||
out[i] = strings.TrimPrefix(s, "repository:")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
84
vendor/github.com/moby/buildkit/session/auth/authprovider/tokenseed.go
generated
vendored
Normal file
84
vendor/github.com/moby/buildkit/session/auth/authprovider/tokenseed.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
package authprovider
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/gofrs/flock"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type tokenSeeds struct {
|
||||
mu sync.Mutex
|
||||
dir string
|
||||
m map[string]seed
|
||||
}
|
||||
|
||||
type seed struct {
|
||||
Seed []byte
|
||||
}
|
||||
|
||||
func (ts *tokenSeeds) getSeed(host string) ([]byte, error) {
|
||||
ts.mu.Lock()
|
||||
defer ts.mu.Unlock()
|
||||
|
||||
if err := os.MkdirAll(ts.dir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ts.m == nil {
|
||||
ts.m = map[string]seed{}
|
||||
}
|
||||
|
||||
l := flock.New(filepath.Join(ts.dir, ".token_seed.lock"))
|
||||
if err := l.Lock(); err != nil {
|
||||
if !errors.Is(err, syscall.EROFS) && errors.Is(err, syscall.EPERM) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
defer l.Unlock()
|
||||
}
|
||||
|
||||
fp := filepath.Join(ts.dir, ".token_seed")
|
||||
|
||||
// we include client side randomness to avoid chosen plaintext attack from the daemon side
|
||||
dt, err := ioutil.ReadFile(fp)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) && !errors.Is(err, syscall.ENOTDIR) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := json.Unmarshal(dt, &ts.m); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse %s", fp)
|
||||
}
|
||||
}
|
||||
v, ok := ts.m[host]
|
||||
if !ok {
|
||||
v = seed{Seed: newSeed()}
|
||||
}
|
||||
|
||||
ts.m[host] = v
|
||||
|
||||
dt, err = json.MarshalIndent(ts.m, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(fp, dt, 0600); err != nil {
|
||||
if !errors.Is(err, syscall.EROFS) && !errors.Is(err, syscall.EPERM) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return v.Seed, nil
|
||||
}
|
||||
|
||||
func newSeed() []byte {
|
||||
b := make([]byte, 16)
|
||||
rand.Read(b)
|
||||
return b
|
||||
}
|
Reference in New Issue
Block a user