google.golang.org/grpc@v1.72.2/credentials/google/google.go (about) 1 /* 2 * 3 * Copyright 2018 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package google defines credentials for google cloud services. 20 package google 21 22 import ( 23 "context" 24 "fmt" 25 26 "google.golang.org/grpc/credentials" 27 "google.golang.org/grpc/credentials/alts" 28 "google.golang.org/grpc/credentials/oauth" 29 "google.golang.org/grpc/grpclog" 30 "google.golang.org/grpc/internal" 31 ) 32 33 const defaultCloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform" 34 35 var logger = grpclog.Component("credentials") 36 37 // DefaultCredentialsOptions constructs options to build DefaultCredentials. 38 type DefaultCredentialsOptions struct { 39 // PerRPCCreds is a per RPC credentials that is passed to a bundle. 40 PerRPCCreds credentials.PerRPCCredentials 41 // ALTSPerRPCCreds is a per RPC credentials that, if specified, will 42 // supercede PerRPCCreds above for and only for ALTS connections. 43 ALTSPerRPCCreds credentials.PerRPCCredentials 44 } 45 46 // NewDefaultCredentialsWithOptions returns a credentials bundle that is 47 // configured to work with google services. 48 // 49 // This API is experimental. 50 func NewDefaultCredentialsWithOptions(opts DefaultCredentialsOptions) credentials.Bundle { 51 if opts.PerRPCCreds == nil { 52 var err error 53 // If the ADC ends up being Compute Engine Credentials, this context 54 // won't be used. Otherwise, the context dictates all the subsequent 55 // token requests via HTTP. So we cannot have any deadline or timeout. 56 opts.PerRPCCreds, err = newADC(context.TODO()) 57 if err != nil { 58 logger.Warningf("NewDefaultCredentialsWithOptions: failed to create application oauth: %v", err) 59 } 60 } 61 if opts.ALTSPerRPCCreds != nil { 62 opts.PerRPCCreds = &dualPerRPCCreds{ 63 perRPCCreds: opts.PerRPCCreds, 64 altsPerRPCCreds: opts.ALTSPerRPCCreds, 65 } 66 } 67 c := &creds{opts: opts} 68 bundle, err := c.NewWithMode(internal.CredsBundleModeFallback) 69 if err != nil { 70 logger.Warningf("NewDefaultCredentialsWithOptions: failed to create new creds: %v", err) 71 } 72 return bundle 73 } 74 75 // NewDefaultCredentials returns a credentials bundle that is configured to work 76 // with google services. 77 // 78 // This API is experimental. 79 func NewDefaultCredentials() credentials.Bundle { 80 return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{}) 81 } 82 83 // NewComputeEngineCredentials returns a credentials bundle that is configured to work 84 // with google services. This API must only be used when running on GCE. Authentication configured 85 // by this API represents the GCE VM's default service account. 86 // 87 // This API is experimental. 88 func NewComputeEngineCredentials() credentials.Bundle { 89 return NewDefaultCredentialsWithOptions(DefaultCredentialsOptions{ 90 PerRPCCreds: oauth.NewComputeEngine(), 91 }) 92 } 93 94 // creds implements credentials.Bundle. 95 type creds struct { 96 opts DefaultCredentialsOptions 97 98 // Supported modes are defined in internal/internal.go. 99 mode string 100 // The active transport credentials associated with this bundle. 101 transportCreds credentials.TransportCredentials 102 // The active per RPC credentials associated with this bundle. 103 perRPCCreds credentials.PerRPCCredentials 104 } 105 106 func (c *creds) TransportCredentials() credentials.TransportCredentials { 107 return c.transportCreds 108 } 109 110 func (c *creds) PerRPCCredentials() credentials.PerRPCCredentials { 111 if c == nil { 112 return nil 113 } 114 return c.perRPCCreds 115 } 116 117 var ( 118 newTLS = func() credentials.TransportCredentials { 119 return credentials.NewTLS(nil) 120 } 121 newALTS = func() credentials.TransportCredentials { 122 return alts.NewClientCreds(alts.DefaultClientOptions()) 123 } 124 newADC = func(ctx context.Context) (credentials.PerRPCCredentials, error) { 125 return oauth.NewApplicationDefault(ctx, defaultCloudPlatformScope) 126 } 127 ) 128 129 // NewWithMode should make a copy of Bundle, and switch mode. Modifying the 130 // existing Bundle may cause races. 131 func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) { 132 newCreds := &creds{ 133 opts: c.opts, 134 mode: mode, 135 } 136 137 // Create transport credentials. 138 switch mode { 139 case internal.CredsBundleModeFallback: 140 newCreds.transportCreds = newClusterTransportCreds(newTLS(), newALTS()) 141 case internal.CredsBundleModeBackendFromBalancer, internal.CredsBundleModeBalancer: 142 // Only the clients can use google default credentials, so we only need 143 // to create new ALTS client creds here. 144 newCreds.transportCreds = newALTS() 145 default: 146 return nil, fmt.Errorf("unsupported mode: %v", mode) 147 } 148 149 if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer { 150 newCreds.perRPCCreds = newCreds.opts.PerRPCCreds 151 } 152 153 return newCreds, nil 154 } 155 156 // dualPerRPCCreds implements credentials.PerRPCCredentials by embedding the 157 // fallback PerRPCCredentials and the ALTS one. It pickes one of them based on 158 // the channel type. 159 type dualPerRPCCreds struct { 160 perRPCCreds credentials.PerRPCCredentials 161 altsPerRPCCreds credentials.PerRPCCredentials 162 } 163 164 func (d *dualPerRPCCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { 165 ri, ok := credentials.RequestInfoFromContext(ctx) 166 if !ok { 167 return nil, fmt.Errorf("request info not found from context") 168 } 169 if authType := ri.AuthInfo.AuthType(); authType == "alts" { 170 return d.altsPerRPCCreds.GetRequestMetadata(ctx, uri...) 171 } 172 // This ensures backward compatibility even if authType is not "tls". 173 return d.perRPCCreds.GetRequestMetadata(ctx, uri...) 174 } 175 176 func (d *dualPerRPCCreds) RequireTransportSecurity() bool { 177 return d.altsPerRPCCreds.RequireTransportSecurity() || d.perRPCCreds.RequireTransportSecurity() 178 }