...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package credentials
16
17 import (
18 "context"
19 "encoding/json"
20 "errors"
21 "fmt"
22 "net/url"
23 "strings"
24 "time"
25
26 "cloud.google.com/go/auth"
27 "cloud.google.com/go/compute/metadata"
28 )
29
30 var (
31 computeTokenMetadata = map[string]interface{}{
32 "auth.google.tokenSource": "compute-metadata",
33 "auth.google.serviceAccount": "default",
34 }
35 computeTokenURI = "instance/service-accounts/default/token"
36 )
37
38
39
40 func computeTokenProvider(earlyExpiry time.Duration, scope ...string) auth.TokenProvider {
41 return auth.NewCachedTokenProvider(computeProvider{scopes: scope}, &auth.CachedTokenProviderOptions{
42 ExpireEarly: earlyExpiry,
43 })
44 }
45
46
47 type computeProvider struct {
48 scopes []string
49 }
50
51 type metadataTokenResp struct {
52 AccessToken string `json:"access_token"`
53 ExpiresInSec int `json:"expires_in"`
54 TokenType string `json:"token_type"`
55 }
56
57 func (cs computeProvider) Token(ctx context.Context) (*auth.Token, error) {
58 tokenURI, err := url.Parse(computeTokenURI)
59 if err != nil {
60 return nil, err
61 }
62 if len(cs.scopes) > 0 {
63 v := url.Values{}
64 v.Set("scopes", strings.Join(cs.scopes, ","))
65 tokenURI.RawQuery = v.Encode()
66 }
67 tokenJSON, err := metadata.Get(tokenURI.String())
68 if err != nil {
69 return nil, err
70 }
71 var res metadataTokenResp
72 if err := json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res); err != nil {
73 return nil, fmt.Errorf("credentials: invalid token JSON from metadata: %w", err)
74 }
75 if res.ExpiresInSec == 0 || res.AccessToken == "" {
76 return nil, errors.New("credentials: incomplete token received from metadata")
77 }
78 return &auth.Token{
79 Value: res.AccessToken,
80 Type: res.TokenType,
81 Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
82 Metadata: computeTokenMetadata,
83 }, nil
84
85 }
86
View as plain text