Skip to content

Commit 1b4bd20

Browse files
authored
Merge pull request #3233 from tonistiigi/imagetools-registrytoken
imagetools: support registrytoken auth in docker config
2 parents 52b5d08 + da426ec commit 1b4bd20

File tree

2 files changed

+110
-42
lines changed

2 files changed

+110
-42
lines changed

util/imagetools/auth.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package imagetools
2+
3+
import (
4+
"context"
5+
"encoding/base64"
6+
"encoding/json"
7+
"net/http"
8+
"sync"
9+
"time"
10+
11+
"github.com/containerd/containerd/v2/core/remotes/docker"
12+
"github.com/distribution/reference"
13+
"github.com/docker/cli/cli/config/types"
14+
)
15+
16+
type authConfig struct {
17+
mu sync.Mutex
18+
authConfigCache map[string]authConfigCacheEntry
19+
cfg Auth
20+
}
21+
22+
type authConfigCacheEntry struct {
23+
Created time.Time
24+
Auth types.AuthConfig
25+
}
26+
27+
func newAuthConfig(a Auth) *authConfig {
28+
return &authConfig{
29+
authConfigCache: map[string]authConfigCacheEntry{},
30+
cfg: a,
31+
}
32+
}
33+
34+
func (a *authConfig) credentials(host string) (string, string, error) {
35+
ac, err := a.authConfig(host)
36+
if err != nil {
37+
return "", "", err
38+
}
39+
if ac.IdentityToken != "" {
40+
return "", ac.IdentityToken, nil
41+
}
42+
return ac.Username, ac.Password, nil
43+
}
44+
45+
func (a *authConfig) authConfig(host string) (types.AuthConfig, error) {
46+
const defaultExpiration = 2 * time.Minute
47+
48+
if host == "registry-1.docker.io" {
49+
host = "https://index.docker.io/v1/"
50+
}
51+
a.mu.Lock()
52+
defer a.mu.Unlock()
53+
54+
if c, ok := a.authConfigCache[host]; ok && time.Since(c.Created) <= defaultExpiration {
55+
return c.Auth, nil
56+
}
57+
ac, err := a.cfg.GetAuthConfig(host)
58+
if err != nil {
59+
return types.AuthConfig{}, err
60+
}
61+
a.authConfigCache[host] = authConfigCacheEntry{
62+
Created: time.Now(),
63+
Auth: ac,
64+
}
65+
return ac, nil
66+
}
67+
68+
func RegistryAuthForRef(ref string, a Auth) (string, error) {
69+
if a == nil {
70+
return "", nil
71+
}
72+
r, err := parseRef(ref)
73+
if err != nil {
74+
return "", err
75+
}
76+
host := reference.Domain(r)
77+
if host == "docker.io" {
78+
host = "https://index.docker.io/v1/"
79+
}
80+
ac, err := a.GetAuthConfig(host)
81+
if err != nil {
82+
return "", err
83+
}
84+
buf, err := json.Marshal(ac)
85+
if err != nil {
86+
return "", err
87+
}
88+
return base64.URLEncoding.EncodeToString(buf), nil
89+
}
90+
91+
type withBearerAuthorizer struct {
92+
docker.Authorizer
93+
AuthConfig *authConfig
94+
}
95+
96+
func (a *withBearerAuthorizer) Authorize(ctx context.Context, req *http.Request) error {
97+
ac, err := a.AuthConfig.authConfig(req.Host)
98+
if err == nil && ac.RegistryToken != "" {
99+
req.Header.Set("Authorization", "Bearer "+ac.RegistryToken)
100+
return nil
101+
}
102+
return a.Authorizer.Authorize(ctx, req)
103+
}

util/imagetools/inspect.go

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package imagetools
33
import (
44
"bytes"
55
"context"
6-
"encoding/base64"
7-
"encoding/json"
86
"io"
97
"net/http"
108

@@ -36,8 +34,14 @@ type Resolver struct {
3634
}
3735

3836
func New(opt Opt) *Resolver {
37+
ac := newAuthConfig(opt.Auth)
38+
dockerAuth := docker.NewDockerAuthorizer(docker.WithAuthCreds(ac.credentials), docker.WithAuthClient(http.DefaultClient))
39+
auth := &withBearerAuthorizer{
40+
Authorizer: dockerAuth,
41+
AuthConfig: ac,
42+
}
3943
return &Resolver{
40-
auth: docker.NewDockerAuthorizer(docker.WithAuthCreds(toCredentialsFunc(opt.Auth)), docker.WithAuthClient(http.DefaultClient)),
44+
auth: auth,
4145
hosts: resolver.NewRegistryConfig(opt.RegistryConfig),
4246
buffer: contentutil.NewBuffer(),
4347
}
@@ -121,42 +125,3 @@ func parseRef(s string) (reference.Named, error) {
121125
ref = reference.TagNameOnly(ref)
122126
return ref, nil
123127
}
124-
125-
func toCredentialsFunc(a Auth) func(string) (string, string, error) {
126-
return func(host string) (string, string, error) {
127-
if host == "registry-1.docker.io" {
128-
host = "https://index.docker.io/v1/"
129-
}
130-
ac, err := a.GetAuthConfig(host)
131-
if err != nil {
132-
return "", "", err
133-
}
134-
if ac.IdentityToken != "" {
135-
return "", ac.IdentityToken, nil
136-
}
137-
return ac.Username, ac.Password, nil
138-
}
139-
}
140-
141-
func RegistryAuthForRef(ref string, a Auth) (string, error) {
142-
if a == nil {
143-
return "", nil
144-
}
145-
r, err := parseRef(ref)
146-
if err != nil {
147-
return "", err
148-
}
149-
host := reference.Domain(r)
150-
if host == "docker.io" {
151-
host = "https://index.docker.io/v1/"
152-
}
153-
ac, err := a.GetAuthConfig(host)
154-
if err != nil {
155-
return "", err
156-
}
157-
buf, err := json.Marshal(ac)
158-
if err != nil {
159-
return "", err
160-
}
161-
return base64.URLEncoding.EncodeToString(buf), nil
162-
}

0 commit comments

Comments
 (0)