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

Is it possible to manipulate Google Workspace domains with domain-wide access via Workload Identity Federation? #63

Closed
ken5scal opened this issue Nov 28, 2021 · 8 comments · Fixed by #64

Comments

@ken5scal
Copy link

As the title suggest, I'm wondering the way to access API in Google Workspace domain via Workload Identity Federation?
The service account is already set up and successfully connected Google Workspace, if request is made with downloaded service account key.

I thought delegates input option may be the way to go, but while it gives me the access token, it is not for the Google Workspace API as following message suggests.

panic: failed listing groups: googleapi: Error 404: Domain not found., notFound

I'm not even sure it is possible in the first place, so allow me to raise the issue with blank template.
Thanks in advance!

@ken5scal
Copy link
Author

This is my Code, where GOOGLE_SERVICE_ACCOUNT_CREDENTIALS is either service account key or credentials_file_path output from google-github-actions/auth

	credInString := os.Getenv("GOOGLE_SERVICE_ACCOUNT_CREDENTIALS")
	ctx := context.Background()
	cred, err := google.CredentialsFromJSONWithParams(ctx, []byte(credInString), google.CredentialsParams{
		Scopes:  scopes,
		Subject: "google-workspace-user@example.com",
	})
	if err != nil {
		panic(fmt.Sprintf("CredentialsFromJSONWithParams: %v", err))
	}
	
	client := oauth2.NewClient(ctx, cred.TokenSource)

	if adminSrv, err := admin.NewService(ctx, option.WithHTTPClient(client)); err != nil {
		panic(fmt.Sprintf("Unable to initialize admin SDK: %v", err))
	}

Using Web Identity Federation

It fails with an error message suggesting the token is not valid one for the workspace.
Token acquisition seems to be done in multiple steps as sts.googleapis.com issues an intermediate token, and then use it for Service Account Credential API generateAccessToken method.

2021/11/28 18:46:25 <-- 200 https://pipelines.actions.githubusercontent.com/some-kind-of-id-I-though-i-should-hide/00000000-0000-0000-0000-000000000000/_apis/distributedtask/hubs/Actions/plans/plan-id/jobs/job-id/idtoken?api-version=2.0&audience=https%3A%2F%2Fiam.googleapis.com%2Fprojects%2Fproject-id%2Flocations%2Fglobal%2FworkloadIdentityPools%2Fsa-account%2Fproviders%2Fgithub-action (168.66ms)
2021/11/28 18:46:25 --> POST https://sts.googleapis.com/v1/token
2021/11/28 18:46:25 <-- 200 https://sts.googleapis.com/v1/token (87.98ms)
2021/11/28 18:46:25 --> POST https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-account@my-project.iam.gserviceaccount.com:generateAccessToken
2021/11/28 18:46:25 <-- 200 https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/sa-account@my-project.iam.gserviceaccount.com:generateAccessToken (59.77ms)
GET /admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false HTTP/1.1
2021/11/28 18:46:25 --> GET https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false
Host: www.googleapis.com
Authorization: ya29.c.KqoDGgjhbll-...(very long one)
User-Agent: google-api-go-client/0.5
X-Goog-Api-Client: gl-go/1.17.2 gdcl/20200728

2021/11/28 18:46:25 <-- 404 https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false (120.02ms)
2021/11/28 18:46:25 <-- 404 https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false (120.21ms)
panic: failed listing groups: googleapi: Error 404: Domain not found., notFound

Using Service Account (Static) Key

The token acquisition is done via https://oauth2.googleapis.com/token endpoint, and that's it.
The token is valid one and successfully received the response.

2021/11/28 18:20:45 --> POST https://oauth2.googleapis.com/token
2021/11/28 18:20:45 <-- 200 https://oauth2.googleapis.com/token (262.69ms)
GET /admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.省略
User-Agent: google-api-go-client/0.5
X-Goog-Api-Client: gl-go/1.17.2 gdcl/20200728

2021/11/28 18:20:45 --> GET https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false
2021/11/28 18:20:45 <-- 200 https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false (495.99ms)
2021/11/28 18:20:45 <-- 200 https://www.googleapis.com/admin/directory/v1/groups?alt=json&customer=my_customer&prettyPrint=false (496.07ms)
6

@sethvargo
Copy link
Member

The default scope is https://googleapis.com/auth/cloud-platform. You'll need to customize the scope (probably to https://www.googleapis.com/auth/admin.directory.domain although I'm not super familiar with that API)

@ken5scal
Copy link
Author

I actually have done that, but both delegates and scopes seems to be only relevant to service accounts of Google Cloud, but not Google Workspace.

@sethvargo
Copy link
Member

Hi @ken5scal - I think you're correct. The Security Token Service (sts.googleapis.com) exchanges temporary credentials for short-lived tokens to access Google Cloud resources. I think this will change in the future, but for now it seems restricted to Google Cloud APIs.

@sethvargo
Copy link
Member

Alright, I did some digging. It's not currently possible to use Domain-Wide Delegation with the IAM Credentials endpoint. I've filed this feature request internally and will update the documentation in this repo in a bit. The root cause is around being able to set a custom Subject field, which is not currently supported in the IAM Credentials endpoint (which this repo uses).

For now, the best I can offer is for you to build and sign your own JWT and use that for authentication:

  1. Use WIF to generate an OAuth token with signJwt permission
  2. Use that OAuth token to call the :signJwt method with a custom JWT payload as linked above on the IAM Credentials endpoint
  3. Exchange that signed JWT for an OAuth token using the /token endpoint
  4. Use that new OAuth token to call the Workspace APIs

@ken5scal
Copy link
Author

ken5scal commented Dec 3, 2021

@sethvargo Cool, thanks for an investigation. I will try it out.

@sethvargo
Copy link
Member

@ken5scal I added support for DWD in #70 (it just automates the steps I outlined above). I has some caveats documented in the readme, the biggest of which is that you can't have tokens valid > 1hr, even if you set the org policy to allow extension up to 12h.

@ken5scal
Copy link
Author

ken5scal commented Dec 7, 2021

oh, wow. That's one quick development, and I deeply appreciate it.
Let me try it out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

2 participants