Skip to content

Commit ba60c89

Browse files
committed
Use a privilegeFunc fall-back pattern on push/pull
Signed-off-by: Alano Terblanche <[email protected]>
1 parent 578ccf6 commit ba60c89

File tree

12 files changed

+311
-64
lines changed

12 files changed

+311
-64
lines changed

cli/command/image/push.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import (
1414
"github.com/docker/cli/cli"
1515
"github.com/docker/cli/cli/command"
1616
"github.com/docker/cli/cli/command/completion"
17+
"github.com/docker/cli/cli/config/configfile"
1718
"github.com/docker/cli/cli/streams"
1819
"github.com/docker/cli/internal/jsonstream"
1920
"github.com/docker/cli/internal/tui"
2021
"github.com/docker/docker/api/types/auxprogress"
2122
"github.com/docker/docker/api/types/image"
2223
registrytypes "github.com/docker/docker/api/types/registry"
24+
c "github.com/docker/docker/client"
2325
"github.com/docker/docker/registry"
2426
"github.com/morikuni/aec"
2527
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -111,18 +113,20 @@ To push the complete multi-platform image, remove the --platform flag.
111113

112114
// Resolve the Auth config relevant for this server
113115
authConfig := command.ResolveAuthConfig(dockerCli.ConfigFile(), repoInfo.Index)
114-
encodedAuth, err := registrytypes.EncodeAuthConfig(authConfig)
115-
if err != nil {
116-
return err
117-
}
118-
var requestPrivilege registrytypes.RequestAuthConfig
116+
117+
hostname := command.GetRegistryHostname(repoInfo.Index)
118+
119+
privilegeFuncs := make([]registrytypes.RequestAuthConfig, 0)
120+
121+
privilegeFuncs = append(privilegeFuncs, configfile.RegistryAuthPrivilegeFunc(dockerCli.ConfigFile(), hostname))
119122
if dockerCli.In().IsTerminal() {
120-
requestPrivilege = command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
123+
privilegeFuncs = append(privilegeFuncs, command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push"))
121124
}
125+
122126
options := image.PushOptions{
123127
All: opts.all,
124-
RegistryAuth: encodedAuth,
125-
PrivilegeFunc: requestPrivilege,
128+
RegistryAuth: "something", // we already pass all configs from privilegeFuncs
129+
PrivilegeFunc: c.ChainPrivilegeFuncs(privilegeFuncs...),
126130
Platform: platform,
127131
}
128132

cli/command/image/trust.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import (
88

99
"github.com/distribution/reference"
1010
"github.com/docker/cli/cli/command"
11+
"github.com/docker/cli/cli/config/configfile"
1112
"github.com/docker/cli/cli/streams"
1213
"github.com/docker/cli/cli/trust"
1314
"github.com/docker/cli/internal/jsonstream"
1415
"github.com/docker/docker/api/types/image"
1516
registrytypes "github.com/docker/docker/api/types/registry"
17+
c "github.com/docker/docker/client"
1618
"github.com/docker/docker/registry"
1719
"github.com/opencontainers/go-digest"
1820
"github.com/pkg/errors"
@@ -145,17 +147,17 @@ func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth)
145147

146148
// imagePullPrivileged pulls the image and displays it to the output
147149
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, opts pullOptions) error {
148-
encodedAuth, err := registrytypes.EncodeAuthConfig(*imgRefAndAuth.AuthConfig())
149-
if err != nil {
150-
return err
151-
}
152-
var requestPrivilege registrytypes.RequestAuthConfig
150+
hostname := command.GetRegistryHostname(imgRefAndAuth.RepoInfo().Index)
151+
152+
privilegeFuncs := make([]registrytypes.RequestAuthConfig, 0)
153+
privilegeFuncs = append(privilegeFuncs, configfile.RegistryAuthPrivilegeFunc(cli.ConfigFile(), hostname))
153154
if cli.In().IsTerminal() {
154-
requestPrivilege = command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
155+
privilegeFuncs = append(privilegeFuncs, command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull"))
155156
}
157+
156158
responseBody, err := cli.Client().ImagePull(ctx, reference.FamiliarString(imgRefAndAuth.Reference()), image.PullOptions{
157-
RegistryAuth: encodedAuth,
158-
PrivilegeFunc: requestPrivilege,
159+
RegistryAuth: "", // we already have credentials resolved by privilegeFuncs
160+
PrivilegeFunc: c.ChainPrivilegeFuncs(privilegeFuncs...),
159161
All: opts.all,
160162
Platform: opts.platform,
161163
})

cli/command/registry.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ func RegistryAuthenticationPrivilegedFunc(cli Cli, index *registrytypes.IndexInf
6060
}
6161
}
6262

63+
func GetRegistryHostname(index *registrytypes.IndexInfo) string {
64+
configKey := index.Name
65+
if index.Official {
66+
configKey = authConfigKey
67+
}
68+
return configKey
69+
}
70+
6371
// ResolveAuthConfig returns auth-config for the given registry from the
6472
// credential-store. It returns an empty AuthConfig if no credentials were
6573
// found.

cli/config/configfile/file.go

Lines changed: 90 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package configfile
22

33
import (
4+
"context"
45
"encoding/base64"
56
"encoding/json"
67
"fmt"
@@ -12,6 +13,7 @@ import (
1213
"github.com/docker/cli/cli/config/credentials"
1314
"github.com/docker/cli/cli/config/memorystore"
1415
"github.com/docker/cli/cli/config/types"
16+
"github.com/docker/docker/api/types/registry"
1517
"github.com/pkg/errors"
1618
"github.com/sirupsen/logrus"
1719
)
@@ -301,20 +303,9 @@ func (configFile *ConfigFile) GetCredentialsStore(registryHostname string) crede
301303
return store
302304
}
303305

304-
authConfig, err := parseEnvConfig(envConfig)
305-
if err != nil {
306-
_, _ = fmt.Fprintln(os.Stderr, "Failed to create credential store from DOCKER_AUTH_CONFIG: ", err)
307-
return store
308-
}
309-
310-
// use DOCKER_AUTH_CONFIG if set
311-
// it uses the native or file store as a fallback to fetch and store credentials
312-
envStore, err := memorystore.New(
313-
memorystore.WithAuthConfig(authConfig),
314-
memorystore.WithFallbackStore(store),
315-
)
306+
envStore, err := getEnvStore(envConfig, store)
316307
if err != nil {
317-
_, _ = fmt.Fprintln(os.Stderr, "Failed to create credential store from DOCKER_AUTH_CONFIG: ", err)
308+
_, _ = fmt.Fprintln(os.Stderr, err)
318309
return store
319310
}
320311

@@ -360,6 +351,92 @@ func (configFile *ConfigFile) GetAuthConfig(registryHostname string) (types.Auth
360351
return configFile.GetCredentialsStore(registryHostname).Get(registryHostname)
361352
}
362353

354+
func getEnvStore(envConfig string, fallbackStore credentials.Store) (credentials.Store, error) {
355+
authConfig, err := parseEnvConfig(envConfig)
356+
if err != nil {
357+
return nil, fmt.Errorf("failed to create credential store from %s: %w", DockerEnvConfigKey, err)
358+
}
359+
360+
// use DOCKER_AUTH_CONFIG if set
361+
// it uses the native or file store as a fallback to fetch and store credentials
362+
envStore, err := memorystore.New(
363+
memorystore.WithAuthConfig(authConfig),
364+
memorystore.WithFallbackStore(fallbackStore),
365+
)
366+
if err != nil {
367+
return nil, fmt.Errorf("failed to create credential store from %s: %w", DockerEnvConfigKey, err)
368+
}
369+
return envStore, nil
370+
}
371+
372+
func getEncodedAuth(store credentials.Store, registryHostname string) (string, error) {
373+
c, err := store.Get(registryHostname)
374+
if err != nil {
375+
return "", err
376+
}
377+
return registry.EncodeAuthConfig(registry.AuthConfig(c))
378+
}
379+
380+
func envRequestAuthConfig(registryHostname string) registry.RequestAuthConfig {
381+
return func(ctx context.Context) (string, error) {
382+
fmt.Fprintln(os.Stdout, "Trying env")
383+
384+
envConfig := os.Getenv(DockerEnvConfigKey)
385+
if envConfig == "" {
386+
return "", fmt.Errorf("%s not defined", DockerEnvConfigKey)
387+
}
388+
389+
envStore, err := getEnvStore(envConfig, nil)
390+
if err != nil {
391+
return "", err
392+
}
393+
return getEncodedAuth(envStore, registryHostname)
394+
}
395+
}
396+
397+
func nativeRequestAuthConfig(configFile *ConfigFile, registryHostname string) registry.RequestAuthConfig {
398+
return func(ctx context.Context) (string, error) {
399+
fmt.Fprintln(os.Stdout, "Trying native")
400+
helper := getConfiguredCredentialStore(configFile, registryHostname)
401+
if helper == "" {
402+
return "", errors.New("native credential helper not supported")
403+
}
404+
store := newNativeStore(configFile, helper)
405+
return getEncodedAuth(store, registryHostname)
406+
}
407+
}
408+
409+
func fileRequestAuthConfig(configFile *ConfigFile, registryHostname string) registry.RequestAuthConfig {
410+
return func(ctx context.Context) (string, error) {
411+
fmt.Fprintln(os.Stdout, "Trying file")
412+
store := credentials.NewFileStore(configFile)
413+
return getEncodedAuth(store, registryHostname)
414+
}
415+
}
416+
417+
// RegistryAuthPrivilegeFunc returns an ordered slice of [registry.RequestAuthConfig]
418+
//
419+
// The order of precedence for resolving credentials are as follows:
420+
// - Credentials stored in the environment through DOCKER_AUTH_CONFIG
421+
// - Native credentials through the credential-helper
422+
// - Filestore credentials stored in `~/.docker/config.json`
423+
func RegistryAuthPrivilegeFunc(configFile *ConfigFile, registryHostname string) registry.RequestAuthConfig {
424+
sourceFuncs := []registry.RequestAuthConfig{
425+
envRequestAuthConfig(registryHostname),
426+
nativeRequestAuthConfig(configFile, registryHostname),
427+
fileRequestAuthConfig(configFile, registryHostname),
428+
}
429+
return func(ctx context.Context) (string, error) {
430+
fmt.Fprintln(os.Stdout, "try funcs")
431+
for _, f := range sourceFuncs {
432+
if cred, err := f(ctx); err == nil && cred != "" {
433+
return cred, nil
434+
}
435+
}
436+
return "", nil
437+
}
438+
}
439+
363440
// getConfiguredCredentialStore returns the credential helper configured for the
364441
// given registry, the default credsStore, or the empty string if neither are
365442
// configured.

vendor/github.com/docker/docker/api/swagger.yaml

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/docker/docker/client/auth.go

Lines changed: 83 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/docker/docker/client/image_create.go

Lines changed: 39 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)