-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathauth.go
More file actions
109 lines (94 loc) · 2.8 KB
/
auth.go
File metadata and controls
109 lines (94 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package explore
import (
"context"
"fmt"
"log"
"strings"
"time"
"chainguard.dev/sdk/sts"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/jonjohnsonjr/dagdotdev/internal/chainguard"
"golang.org/x/time/rate"
"google.golang.org/api/idtoken"
)
func NewChainguardIdentityAuth(identity, issuer, audience string) authn.Keychain {
log.Printf("NewChainguardIdentityAuth(%q, %q, %q)", identity, issuer, audience)
return &keychain{
id: identity,
iss: issuer,
aud: audience,
sometimes: rate.Sometimes{Interval: 30 * time.Minute},
}
}
// NewChainguardIdentityAuthFromURL parses a URL of the form uidp@cgr.dev?iss=issuer.enforce.dev
func NewChainguardIdentityAuthFromURL(raw string) (authn.Keychain, error) {
id, err := chainguard.ParseIdentity(raw)
if err != nil {
return nil, err
}
return NewChainguardIdentityAuth(id.ID, id.Issuer, id.Audience), nil
}
func NewChainguardMultiKeychain(raw string, defaultIssuer string, defaultAudience string) (authn.Keychain, error) {
var ks []authn.Keychain
for _, s := range strings.Split(raw, ",") {
if strings.HasPrefix(s, "chainguard://") {
k, err := NewChainguardIdentityAuthFromURL(s)
if err != nil {
return nil, fmt.Errorf("parsing %q: %w", s, err)
}
ks = append(ks, k)
} else {
// Not URL format, fallback to basic identity format.
ks = append(ks, NewChainguardIdentityAuth(s, defaultIssuer, defaultAudience))
}
}
return authn.NewMultiKeychain(ks...), nil
}
type keychain struct {
id, iss, aud string
sometimes rate.Sometimes
cgtok string
cgerr error
}
func (k *keychain) Resolve(res authn.Resource) (authn.Authenticator, error) {
return k.ResolveContext(context.Background(), res)
}
func (k *keychain) ResolveContext(ctx context.Context, res authn.Resource) (authn.Authenticator, error) {
log.Printf("chainguard.Keychain.Resolve(%q)", res.String())
if k.id == "" {
log.Printf("k.id is empty")
return authn.Anonymous, nil
}
if res.RegistryStr() != k.aud {
log.Printf("%q != %q", res.RegistryStr(), k.aud)
return authn.Anonymous, nil
}
k.sometimes.Do(func() {
log.Printf("chainguard.Keychain.sometimes.Do()")
k.cgerr = nil
ts, err := idtoken.NewTokenSource(ctx, k.iss)
if err != nil {
k.cgerr = fmt.Errorf("creating token source: %w", err)
return
}
tok, err := ts.Token()
if err != nil {
k.cgerr = fmt.Errorf("getting token: %w", err)
return
}
ctok, err := sts.Exchange(ctx, k.iss, k.aud, tok.AccessToken, sts.WithIdentity(k.id))
if err != nil {
k.cgerr = fmt.Errorf("exchanging token: %w", err)
}
k.cgtok = ctok
})
if k.cgerr != nil {
log.Printf("chainguard.Keychain.Resolve = %v", k.cgerr)
return nil, k.cgerr
}
log.Printf("chainguard.Keychain.Resolve | len: %d", len(k.cgtok))
return &authn.Basic{
Username: "_token",
Password: k.cgtok,
}, nil
}