credentials: add compute engine channel creds (#2708)

This commit is contained in:
apolcyn
2019-03-25 14:47:12 -07:00
committed by Menghan Li
parent ef9bac2604
commit 6d8271a06c
3 changed files with 81 additions and 19 deletions

View File

@ -38,7 +38,17 @@ const tokenRequestTimeout = 30 * time.Second
// //
// This API is experimental. // This API is experimental.
func NewDefaultCredentials() credentials.Bundle { func NewDefaultCredentials() credentials.Bundle {
c := &creds{} c := &creds{
newPerRPCCreds: func() credentials.PerRPCCredentials {
ctx, cancel := context.WithTimeout(context.Background(), tokenRequestTimeout)
defer cancel()
perRPCCreds, err := oauth.NewApplicationDefault(ctx)
if err != nil {
grpclog.Warningf("google default creds: failed to create application oauth: %v", err)
}
return perRPCCreds
},
}
bundle, err := c.NewWithMode(internal.CredsBundleModeFallback) bundle, err := c.NewWithMode(internal.CredsBundleModeFallback)
if err != nil { if err != nil {
grpclog.Warningf("google default creds: failed to create new creds: %v", err) grpclog.Warningf("google default creds: failed to create new creds: %v", err)
@ -46,6 +56,24 @@ func NewDefaultCredentials() credentials.Bundle {
return bundle return bundle
} }
// NewComputeEngineCredentials returns a credentials bundle that is configured to work
// with google services. This API must only be used when running on GCE. Authentication configured
// by this API represents the GCE VM's default service account.
//
// This API is experimental.
func NewComputeEngineCredentials() credentials.Bundle {
c := &creds{
newPerRPCCreds: func() credentials.PerRPCCredentials {
return oauth.NewComputeEngine()
},
}
bundle, err := c.NewWithMode(internal.CredsBundleModeFallback)
if err != nil {
grpclog.Warningf("compute engine creds: failed to create new creds: %v", err)
}
return bundle
}
// creds implements credentials.Bundle. // creds implements credentials.Bundle.
type creds struct { type creds struct {
// Supported modes are defined in internal/internal.go. // Supported modes are defined in internal/internal.go.
@ -54,6 +82,8 @@ type creds struct {
transportCreds credentials.TransportCredentials transportCreds credentials.TransportCredentials
// The per RPC credentials associated with this bundle. // The per RPC credentials associated with this bundle.
perRPCCreds credentials.PerRPCCredentials perRPCCreds credentials.PerRPCCredentials
// Creates new per RPC credentials
newPerRPCCreds func() credentials.PerRPCCredentials
} }
func (c *creds) TransportCredentials() credentials.TransportCredentials { func (c *creds) TransportCredentials() credentials.TransportCredentials {
@ -70,7 +100,10 @@ func (c *creds) PerRPCCredentials() credentials.PerRPCCredentials {
// NewWithMode should make a copy of Bundle, and switch mode. Modifying the // NewWithMode should make a copy of Bundle, and switch mode. Modifying the
// existing Bundle may cause races. // existing Bundle may cause races.
func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) { func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) {
newCreds := &creds{mode: mode} newCreds := &creds{
mode: mode,
newPerRPCCreds: c.newPerRPCCreds,
}
// Create transport credentials. // Create transport credentials.
switch mode { switch mode {
@ -81,20 +114,11 @@ func (c *creds) NewWithMode(mode string) (credentials.Bundle, error) {
// to create new ALTS client creds here. // to create new ALTS client creds here.
newCreds.transportCreds = alts.NewClientCreds(alts.DefaultClientOptions()) newCreds.transportCreds = alts.NewClientCreds(alts.DefaultClientOptions())
default: default:
return nil, fmt.Errorf("google default creds: unsupported mode: %v", mode) return nil, fmt.Errorf("unsupported mode: %v", mode)
} }
if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer { if mode == internal.CredsBundleModeFallback || mode == internal.CredsBundleModeBackendFromBalancer {
// Create per RPC credentials. newCreds.perRPCCreds = newCreds.newPerRPCCreds()
// For the time being, we required per RPC credentials for both TLS and
// ALTS. In the future, this will only be required for TLS.
ctx, cancel := context.WithTimeout(context.Background(), tokenRequestTimeout)
defer cancel()
var err error
newCreds.perRPCCreds, err = oauth.NewApplicationDefault(ctx)
if err != nil {
grpclog.Warningf("google default creds: failed to create application oauth: %v", err)
}
} }
return newCreds, nil return newCreds, nil

View File

@ -38,6 +38,7 @@ import (
const ( const (
googleDefaultCredsName = "google_default_credentials" googleDefaultCredsName = "google_default_credentials"
computeEngineCredsName = "compute_engine_channel_creds"
) )
var ( var (
@ -68,6 +69,7 @@ var (
per_rpc_creds: large_unary with per rpc token; per_rpc_creds: large_unary with per rpc token;
oauth2_auth_token: large_unary with oauth2 token auth; oauth2_auth_token: large_unary with oauth2 token auth;
google_default_credentials: large_unary with google default credentials google_default_credentials: large_unary with google default credentials
compute_engine_channel_credentials: large_unary with compute engine creds
cancel_after_begin: cancellation after metadata has been sent but before payloads are sent; cancel_after_begin: cancellation after metadata has been sent but before payloads are sent;
cancel_after_first_response: cancellation after receiving 1st message from the server; cancel_after_first_response: cancellation after receiving 1st message from the server;
status_code_and_message: status code propagated back to client; status_code_and_message: status code propagated back to client;
@ -84,19 +86,26 @@ const (
credsTLS credsTLS
credsALTS credsALTS
credsGoogleDefaultCreds credsGoogleDefaultCreds
credsComputeEngineCreds
) )
func main() { func main() {
flag.Parse() flag.Parse()
var useGDC bool // use google default creds var useGDC bool // use google default creds
var useCEC bool // use compute engine creds
if *customCredentialsType != "" { if *customCredentialsType != "" {
if *customCredentialsType != googleDefaultCredsName { switch *customCredentialsType {
grpclog.Fatalf("custom_credentials_type can only be set to %v or not set", googleDefaultCredsName) case googleDefaultCredsName:
useGDC = true
case computeEngineCredsName:
useCEC = true
default:
grpclog.Fatalf("If set, custom_credentials_type can only be set to one of %v or %v",
googleDefaultCredsName, computeEngineCredsName)
} }
useGDC = true
} }
if (*useTLS && *useALTS) || (*useTLS && useGDC) || (*useALTS && useGDC) { if (*useTLS && *useALTS) || (*useTLS && useGDC) || (*useALTS && useGDC) || (*useTLS && useCEC) || (*useALTS && useCEC) {
grpclog.Fatalf("only one of TLS, ALTS and google default creds can be used") grpclog.Fatalf("only one of TLS, ALTS, google default creds, or compute engine creds can be used")
} }
var credsChosen credsMode var credsChosen credsMode
@ -107,6 +116,8 @@ func main() {
credsChosen = credsALTS credsChosen = credsALTS
case useGDC: case useGDC:
credsChosen = credsGoogleDefaultCreds credsChosen = credsGoogleDefaultCreds
case useCEC:
credsChosen = credsComputeEngineCreds
} }
resolver.SetDefaultScheme("dns") resolver.SetDefaultScheme("dns")
@ -141,6 +152,8 @@ func main() {
opts = append(opts, grpc.WithTransportCredentials(altsTC)) opts = append(opts, grpc.WithTransportCredentials(altsTC))
case credsGoogleDefaultCreds: case credsGoogleDefaultCreds:
opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials())) opts = append(opts, grpc.WithCredentialsBundle(google.NewDefaultCredentials()))
case credsComputeEngineCreds:
opts = append(opts, grpc.WithCredentialsBundle(google.NewComputeEngineCredentials()))
case credsNone: case credsNone:
opts = append(opts, grpc.WithInsecure()) opts = append(opts, grpc.WithInsecure())
default: default:
@ -230,6 +243,12 @@ func main() {
} }
interop.DoGoogleDefaultCredentials(tc, *defaultServiceAccount) interop.DoGoogleDefaultCredentials(tc, *defaultServiceAccount)
grpclog.Infoln("GoogleDefaultCredentials done") grpclog.Infoln("GoogleDefaultCredentials done")
case "compute_engine_channel_credentials":
if credsChosen != credsComputeEngineCreds {
grpclog.Fatalf("ComputeEngineCreds need to be set for compute_engine_channel_credentials test case.")
}
interop.DoComputeEngineChannelCredentials(tc, *defaultServiceAccount)
grpclog.Infoln("ComputeEngineChannelCredentials done")
case "cancel_after_begin": case "cancel_after_begin":
interop.DoCancelAfterBegin(tc) interop.DoCancelAfterBegin(tc)
grpclog.Infoln("CancelAfterBegin done") grpclog.Infoln("CancelAfterBegin done")

View File

@ -393,7 +393,7 @@ func DoPerRPCCreds(tc testpb.TestServiceClient, serviceAccountKeyFile, oauthScop
} }
} }
// DoGoogleDefaultCredentials performs a unary RPC with google default credentials // DoGoogleDefaultCredentials performs an unary RPC with google default credentials
func DoGoogleDefaultCredentials(tc testpb.TestServiceClient, defaultServiceAccount string) { func DoGoogleDefaultCredentials(tc testpb.TestServiceClient, defaultServiceAccount string) {
pl := ClientNewPayload(testpb.PayloadType_COMPRESSABLE, largeReqSize) pl := ClientNewPayload(testpb.PayloadType_COMPRESSABLE, largeReqSize)
req := &testpb.SimpleRequest{ req := &testpb.SimpleRequest{
@ -412,6 +412,25 @@ func DoGoogleDefaultCredentials(tc testpb.TestServiceClient, defaultServiceAccou
} }
} }
// DoComputeEngineChannelCredentials performs an unary RPC with compute engine channel credentials
func DoComputeEngineChannelCredentials(tc testpb.TestServiceClient, defaultServiceAccount string) {
pl := ClientNewPayload(testpb.PayloadType_COMPRESSABLE, largeReqSize)
req := &testpb.SimpleRequest{
ResponseType: testpb.PayloadType_COMPRESSABLE,
ResponseSize: int32(largeRespSize),
Payload: pl,
FillUsername: true,
FillOauthScope: true,
}
reply, err := tc.UnaryCall(context.Background(), req)
if err != nil {
grpclog.Fatal("/TestService/UnaryCall RPC failed: ", err)
}
if reply.GetUsername() != defaultServiceAccount {
grpclog.Fatalf("Got user name %q; wanted %q. ", reply.GetUsername(), defaultServiceAccount)
}
}
var testMetadata = metadata.MD{ var testMetadata = metadata.MD{
"key1": []string{"value1"}, "key1": []string{"value1"},
"key2": []string{"value2"}, "key2": []string{"value2"},