...
1
2
3
4
5
6
7 package creds
8
9 import (
10 "context"
11 "encoding/json"
12 "fmt"
13 "io/ioutil"
14 "net/http"
15 "os"
16
17 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
18 )
19
20
21 type GCPCredentialProvider struct {
22 httpClient *http.Client
23 }
24
25
26 func NewGCPCredentialProvider(httpClient *http.Client) GCPCredentialProvider {
27 return GCPCredentialProvider{httpClient}
28 }
29
30
31 func (p GCPCredentialProvider) GetCredentialsDoc(ctx context.Context) (bsoncore.Document, error) {
32 metadataHost := "metadata.google.internal"
33 if envhost := os.Getenv("GCE_METADATA_HOST"); envhost != "" {
34 metadataHost = envhost
35 }
36 url := fmt.Sprintf("http://%s/computeMetadata/v1/instance/service-accounts/default/token", metadataHost)
37 req, err := http.NewRequest(http.MethodGet, url, nil)
38 if err != nil {
39 return nil, fmt.Errorf("unable to retrieve GCP credentials: %w", err)
40 }
41 req.Header.Set("Metadata-Flavor", "Google")
42 resp, err := p.httpClient.Do(req.WithContext(ctx))
43 if err != nil {
44 return nil, fmt.Errorf("unable to retrieve GCP credentials: %w", err)
45 }
46 defer resp.Body.Close()
47 body, err := ioutil.ReadAll(resp.Body)
48 if err != nil {
49 return nil, fmt.Errorf("unable to retrieve GCP credentials: error reading response body: %w", err)
50 }
51 if resp.StatusCode != http.StatusOK {
52 return nil, fmt.Errorf(
53 "unable to retrieve GCP credentials: expected StatusCode 200, got StatusCode: %v. Response body: %s",
54 resp.StatusCode,
55 body)
56 }
57 var tokenResponse struct {
58 AccessToken string `json:"access_token"`
59 }
60
61 err = json.Unmarshal(body, &tokenResponse)
62 if err != nil {
63 return nil, fmt.Errorf(
64 "unable to retrieve GCP credentials: error reading body JSON: %w (response body: %s)",
65 err,
66 body)
67 }
68 if tokenResponse.AccessToken == "" {
69 return nil, fmt.Errorf("unable to retrieve GCP credentials: got unexpected empty accessToken from GCP Metadata Server. Response body: %s", body)
70 }
71
72 builder := bsoncore.NewDocumentBuilder().AppendString("accessToken", tokenResponse.AccessToken)
73 return builder.Build(), nil
74 }
75
View as plain text