...

Source file src/cloud.google.com/go/auth/credentials/compute.go

Documentation: cloud.google.com/go/auth/credentials

     1  // Copyright 2023 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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  // computeTokenProvider creates a [cloud.google.com/go/auth.TokenProvider] that
    39  // uses the metadata service to retrieve tokens.
    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  // computeProvider fetches tokens from the google cloud metadata service.
    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