Skip to content

Commit 3c3409e

Browse files
Fix credentials for groups settings api (#5165)
#### Motivation In order to call the groups settings API to allow adding external members to groups, the service account credentials need to contain the correct scope `'https://www.googleapis.com/auth/apps.groups.settings'` to verify its admin role in the correspondent Google Workspace (oss-fuzz.com in this case). #### Rationale Calling the get default creds with this scope does not work correctly. My guess is that the GKE/GCE gets the Application Default Credentials via its metadata server, which is configured by default to issue tokens within a limited set of defined scopes (e.g., `cloud-platform`). An alternative is self-impersonating the service account to generate new Credentials with the right scopes. This avoids having to deal with creating a secret containing a new key for the default service account and then generating the credentials based on this key. Note: For this to work, the SA must have the `Service Account Token Creator` role. This is already set for the Compute Engine default account in all prod environments. #### Tests Tested in dev by running the oss_fuzz_cc_groups cronjob with test groups. logs: https://screenshot.googleplex.com/76a7vJjjKC4NhCe.png Check complete investigation on: b/477964128
1 parent 5e605ee commit 3c3409e

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/clusterfuzz/_internal/google_cloud_utils/credentials.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616

1717
from google.auth import compute_engine
1818
from google.auth import credentials
19+
from google.auth import impersonated_credentials
1920
from google.auth.transport import requests
2021
from google.oauth2 import service_account
2122

2223
from clusterfuzz._internal.base import memoize
2324
from clusterfuzz._internal.base import retry
2425
from clusterfuzz._internal.base import utils
26+
from clusterfuzz._internal.google_cloud_utils import compute_metadata
2527
from clusterfuzz._internal.google_cloud_utils import secret_manager
2628
from clusterfuzz._internal.metrics import logs
2729
from clusterfuzz._internal.system import environment
@@ -99,3 +101,31 @@ def get_signing_credentials(service_account_info):
99101
request, '', service_account_email=creds.service_account_email)
100102
token = creds.token
101103
return signing_creds, token
104+
105+
106+
def get_scoped_service_account_credentials(
107+
scopes: list[str]) -> impersonated_credentials.Credentials | None:
108+
"""Gets scoped credentials by self-impersonating the service account."""
109+
creds, _ = get_default()
110+
service_account_email = getattr(creds, 'service_account_email', None)
111+
if service_account_email == 'default':
112+
# Resolve the default service account email using GCE metadata server.
113+
service_account_email = compute_metadata.get(
114+
'instance/service-accounts/default/email')
115+
116+
if not service_account_email:
117+
logs.warning('Could not retrieve service account email when getting scoped'
118+
'credentials.')
119+
return None
120+
121+
logs.info(
122+
f'Using scoped credentials from service account: {service_account_email}')
123+
scoped_creds = impersonated_credentials.Credentials(
124+
source_credentials=creds,
125+
target_principal=service_account_email,
126+
target_scopes=scopes,
127+
)
128+
request = requests.Request()
129+
scoped_creds.refresh(request)
130+
131+
return scoped_creds

src/clusterfuzz/_internal/google_cloud_utils/google_groups.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ def get_identity_api() -> discovery.Resource | None:
4343
def get_group_settings_api() -> discovery.Resource | None:
4444
"""Return the groups settings api client."""
4545
if not hasattr(_local, 'groups_settings_service'):
46-
creds, _ = credentials.get_default()
46+
scopes = ['https://www.googleapis.com/auth/apps.groups.settings']
47+
creds = credentials.get_scoped_service_account_credentials(scopes)
4748
_local.groups_settings_service = discovery.build(
4849
'groupssettings', 'v1', credentials=creds, cache_discovery=False)
4950

0 commit comments

Comments
 (0)