google-cloud-go icon indicating copy to clipboard operation
google-cloud-go copied to clipboard

impersonate: NewIDTokenProvider sets options which are incongruent with detect.Options.validate()

Open emetsger opened this issue 1 year ago • 4 comments

Client

Simple unit test trying to obtain an IDTokenProvider

Environment

Goland

Go Environment

$ go version

go version go1.21.0 darwin/arm64

$ go env

GO111MODULE='on'
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/esm/Library/Caches/go-build'
GOENV='/Users/esm/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/esm/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/esm/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/esm/sdk/go1.21.0'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/Users/esm/sdk/go1.21.0/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.21.0'
GCCGO='gccgo'
AR='ar'
CC='clang'
CXX='clang++'
CGO_ENABLED='1'
GOMOD='/Users/esm/workspaces/gcp-cloudauth/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/wk/92k5298d011bf835s8cmt7mh0000gn/T/go-build2964035679=/tmp/go-build -gno-record-gcc-switches -fno-common'

Code

package gcpauth

import (
	"cloud.google.com/go/auth/impersonate"
	"context"
	"github.com/stretchr/testify/require"
	"testing"
)

func TestIDTokenProvider(t *testing.T) {
	tp, err := impersonate.NewIDTokenProvider(&impersonate.IDTokenOptions{
		Audience:        "foo",
		TargetPrincipal: "bar",
		IncludeEmail:    true,
	})

	require.NoError(t, err)

	tok, err := tp.Token(context.Background())

	require.NoError(t, err)
	require.NotNil(t, tok)
}

Expected behavior

  • Successfully obtain a TokenProvider

Actual behavior

Receive an error when invoking impersonate.NewIDTokenProvider(...):

=== RUN   TestIDTokenProvider
2023/12/12 11:03:02 
    auth_test.go:17: 
        	Error Trace:	/Users/esm/workspaces/gcp-cloudauth/auth_test.go:17
        	Error:      	Received unexpected error:
        	            	detect: both scopes and audience were provided
        	Test:       	TestIDTokenProvider
--- FAIL: TestIDTokenProvider (0.00s)

Additional context

  • cloud.google.com/go/auth v0.1.0
  • impersonate requires a value for IDTokenOptions.Audience, so it must be supplied.

Offending snippet within NewIDTokenProvider that adds both audience and scope:

		client, err = httptransport.NewClient(&httptransport.Options{
			DetectOpts: &detect.Options{
				Audience: defaultAud,
				Scopes:   []string{defaultScope},
			},
		})

httptransport.NewClient(...), non-nil err is returned by newTransport:

	trans, err := newTransport(defaultBaseTransport(clientCertProvider, dialTLSContext), opts)
	if err != nil {
		return nil, err
	}

Stack where the error is created

Stack: 
	detect.DefaultCredentials (detect.go:124) cloud.google.com/go/auth/detect
	httptransport.newTransport (transport.go:60) cloud.google.com/go/auth/httptransport
	httptransport.NewClient (httptransport.go:170) cloud.google.com/go/auth/httptransport
	impersonate.NewIDTokenProvider (idtoken.go:90) cloud.google.com/go/auth/impersonate
	gcpauth.TestIDTokenProvider (auth_test.go:11) gcpauth
	testing.tRunner (testing.go:1595) testing
	testing.(*T).Run.func1 (testing.go:1648) testing
	runtime.goexit (asm_arm64.s:1197) runtime
	testing.(*T).Run (testing.go:1648) testing

emetsger avatar Dec 12 '23 16:12 emetsger

Hi @emetsger, thank you for reporting this issue!

quartzmo avatar Dec 12 '23 18:12 quartzmo

Thanks for taking this on!

Generally I've been struggling to use the go SDK at google.golang.org/api to obtain ID tokens using the idtoken package. And after assessing various challenges around integration testing I hit pause.

Then I realized that the SDK at cloud.google.com seemed to be the state of the art, and pivoted to using cloud.googlcloud.google.com/go/auth (the packages and APIs seem much more rational than the old SDK). But I quickly hit this roadblock, so I appreciate ya'll taking a look!

In the interim, I think I will have to work around this by manually crafting a payload for invoking the https://oauth2.googleapis.com/token endpoint, and grabbing the id_token from the response.

emetsger avatar Dec 12 '23 18:12 emetsger

This still persists, as demonstrated by https://github.com/tmc/misc/blob/master/gcp-go-impersonation-issue/main.go

tmc avatar Feb 01 '24 00:02 tmc

@emetsger could you share your workaround here?

tmc avatar Feb 19 '24 22:02 tmc

@tmc unfortunately, my workaround was to use the original SDK's idtoken package at google.golang.org/api.

emetsger avatar Feb 25 '24 02:02 emetsger

Sorry for the slow response here, I will get this fixed sometime this week.

codyoss avatar Feb 26 '24 14:02 codyoss