Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing ADC in GKE with the admin directory sdk #1698

Closed
ichbinfrog opened this issue Sep 23, 2022 · 3 comments
Closed

Implementing ADC in GKE with the admin directory sdk #1698

ichbinfrog opened this issue Sep 23, 2022 · 3 comments
Assignees
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: question Request for information or clarification. Not an issue.

Comments

@ichbinfrog
Copy link

I'm trying to implement ADC for https://github.com/dexidp/dex. For fetching Google Groups information, dex uses a service account with Domain-Wide Delegation (see documentation).

My current implementation (see snippet) yields an error in GKE due to the fact that google.FindDefaultCredentials fetches credentials from the metadata server.

The only way I've been able to implement it within GKE was with the following snippet:

// If no service account file path is set, the following impersonation flow is attempted:
// - The base Application Default Credentials is used (SA1)
// - That service account (SA1) is then used to impersonate the service account designated by the targetPrincipal field (SA2)
// - SA2's token source is then used to impersonate the Google Workspace super user designated by adminEmail
ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
  TargetPrincipal: targetPrincipal,
  Subject:         email,
  Scopes:          []string{admin.AdminDirectoryGroupReadonlyScope},
})
if err != nil {
  return nil, fmt.Errorf("failed to fetch application default credentials: %w", err)
}
return admin.NewService(ctx, option.WithTokenSource(ts))

I therefore have a few questions:

  • Is this the canonical flow for using Application Default Credentials (with a given subject and scopes) to use the admin directory service in GKE?
  • If so, is there a recommended method of implementing unit tests for this behavior?
@ichbinfrog ichbinfrog added priority: p3 Desirable enhancement or fix. May not be included in next release. type: question Request for information or clarification. Not an issue. labels Sep 23, 2022
@codyoss
Copy link
Member

codyoss commented Sep 23, 2022

Can you describe more what you are doing? When you say implement ADC I am a little confused. ADC is our term for detecting creds from the environment in a predictable way. It is speced out here: https://google.aip.dev/auth/4110.

If you are doing anything that requires domain-wide-delegation and managing group type activities this is a use case for impersonation, so it looks like you landed in the right area.

Is this the canonical flow for using Application Default Credentials (with a given subject and scopes) to use the admin directory service in GKE?

You must impersonate in this use-case to become the admin user, so yes. We have a small example here which is similar to the code you provided: https://pkg.go.dev/google.golang.org/api/impersonate#example-CredentialsTokenSource-AdminUser

If so, is there a recommended method of implementing unit tests for this behavior?

I would argue anything with auth should not be unit tested, but instead integration tested. If you wanted to write a unit test though you could do so by standing up a fake webserver and intercept the requrests. Or put these details behind and interface and mock it. Hope that helps.

@codyoss
Copy link
Member

codyoss commented Oct 7, 2022

Closing due to lack of response.

@codyoss codyoss closed this as completed Oct 7, 2022
@sagikazarmark
Copy link

@codyoss thank you for your answer!

The question is related to Dex. Dex is an identity federation solution that federates across various IdPs, incliding Google. We use the admin service to query group membership information for a user after the OIDC flow.

Currently we are fighting a set of regressions as a result of adding support for using "default" credentials (so far we only used the admin service if a service account JSON file was configured).

The problem we are facing that our current configuration mechanism doesn't work universally across different environments.

Here is a snippet from the current code:

	var jsonCredentials []byte

	if serviceAccountFilePath == "" {
		credential, err := google.FindDefaultCredentials(ctx)
		if err != nil {
			// ...
		}
		jsonCredentials = credential.JSON
	} else {
		jsonCredentials, err = os.ReadFile(serviceAccountFilePath)
		if err != nil {
			// ...
		}
	}
	config, err := google.JWTConfigFromJSON(jsonCredentials, admin.AdminDirectoryGroupReadonlyScope)
	if err != nil {
		// ...
	}

	// Only attempt impersonation when there is a user configured
	if email != "" {
		config.Subject = email
	}

	return admin.NewService(ctx, option.WithHTTPClient(config.Client(ctx)))

The problem with the above snippet is that credential.JSON is nil on GKE for instance.

As you can see, currently we parse the credential as JSON and set the subject to impersonate.

@ichbinfrog was kind enough to submit a PR fixing the regression using the solution he explained above.

There is however another solution I've seen that seemingly doesn't require us to parse the credentials as JSON to impersonate a user which (to me at least) seems more elegant than the custom credential source solution:

	srv, err := admin.NewService(ctx, option.ImpersonateCredentials(email), option.WithScopes(admin.AdminDirectoryGroupReadonlyScope))
	if err != nil {
		//...
	}

Unfortunately, I'm not that familiar with how the admin service works. Can you advise on which solution is better @codyoss ?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: p3 Desirable enhancement or fix. May not be included in next release. type: question Request for information or clarification. Not an issue.
Projects
None yet
Development

No branches or pull requests

3 participants