Skip to content

Commit e7ffb3a

Browse files
committed
Merge remote-tracking branch 'migration/main' into google-auth-library-python-migration
2 parents ead605a + e13fe12 commit e7ffb3a

12 files changed

+853
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright 2022 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START auth_cloud_explicit_adc]
16+
17+
from google.cloud import storage
18+
19+
import google.oauth2.credentials
20+
import google.auth
21+
22+
23+
def authenticate_explicit_with_adc():
24+
"""
25+
List storage buckets by authenticating with ADC.
26+
27+
// TODO(Developer):
28+
// 1. Before running this sample,
29+
// set up ADC as described in https://cloud.google.com/docs/authentication/external/set-up-adc
30+
// 2. Replace the project variable.
31+
// 3. Make sure you have the necessary permission to list storage buckets: "storage.buckets.list"
32+
"""
33+
34+
# Construct the Google credentials object which obtains the default configuration from your
35+
# working environment.
36+
# google.auth.default() will give you ComputeEngineCredentials
37+
# if you are on a GCE (or other metadata server supported environments).
38+
credentials, project_id = google.auth.default()
39+
# If you are authenticating to a Cloud API, you can let the library include the default scope,
40+
# https://www.googleapis.com/auth/cloud-platform, because IAM is used to provide fine-grained
41+
# permissions for Cloud.
42+
# If you need to provide a scope, specify it as follows:
43+
# credentials = google.auth.default(scopes=scope)
44+
# For more information on scopes to use,
45+
# see: https://developers.google.com/identity/protocols/oauth2/scopes
46+
47+
# Construct the Storage client.
48+
storage_client = storage.Client(credentials=credentials, project=project_id)
49+
buckets = storage_client.list_buckets()
50+
print("Buckets:")
51+
for bucket in buckets:
52+
print(bucket.name)
53+
print("Listed all storage buckets.")
54+
55+
# [END auth_cloud_explicit_adc]
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Copyright 2022 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START auth_cloud_implicit_adc]
16+
17+
from google.cloud import storage
18+
19+
20+
def authenticate_implicit_with_adc(project_id="your-google-cloud-project-id"):
21+
"""
22+
When interacting with Google Cloud Client libraries, the library can auto-detect the
23+
credentials to use.
24+
25+
// TODO(Developer):
26+
// 1. Before running this sample,
27+
// set up ADC as described in https://cloud.google.com/docs/authentication/external/set-up-adc
28+
// 2. Replace the project variable.
29+
// 3. Make sure that the user account or service account that you are using
30+
// has the required permissions. For this sample, you must have "storage.buckets.list".
31+
Args:
32+
project_id: The project id of your Google Cloud project.
33+
"""
34+
35+
# This snippet demonstrates how to list buckets.
36+
# *NOTE*: Replace the client created below with the client required for your application.
37+
# Note that the credentials are not specified when constructing the client.
38+
# Hence, the client library will look for credentials using ADC.
39+
storage_client = storage.Client(project=project_id)
40+
buckets = storage_client.list_buckets()
41+
print("Buckets:")
42+
for bucket in buckets:
43+
print(bucket.name)
44+
print("Listed all storage buckets.")
45+
46+
# [END auth_cloud_implicit_adc]
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Copyright 2025 Google LLC
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
import json
15+
import os
16+
import sys
17+
18+
import boto3
19+
from dotenv import load_dotenv
20+
from google.auth.aws import Credentials as AwsCredentials
21+
from google.auth.aws import AwsSecurityCredentials, AwsSecurityCredentialsSupplier
22+
from google.auth.exceptions import GoogleAuthError
23+
from google.auth.transport.requests import AuthorizedSession
24+
25+
load_dotenv()
26+
27+
28+
class CustomAwsSupplier(AwsSecurityCredentialsSupplier):
29+
"""Custom AWS Security Credentials Supplier."""
30+
31+
def __init__(self):
32+
"""Initializes the Boto3 session, prioritizing environment variables for region."""
33+
# Explicitly read the region from the environment first. This ensures that
34+
# a value from a .env file is picked up reliably for local testing.
35+
region = os.getenv("AWS_REGION") or os.getenv("AWS_DEFAULT_REGION")
36+
37+
# If region is None, Boto3's discovery chain will be used when needed.
38+
self.session = boto3.Session(region_name=region)
39+
self._cached_region = None
40+
print(f"[INFO] CustomAwsSupplier initialized. Region from env: {region}")
41+
42+
def get_aws_region(self, context, request) -> str:
43+
"""Returns the AWS region using Boto3's default provider chain."""
44+
if self._cached_region:
45+
return self._cached_region
46+
47+
# Accessing region_name will use the value from the constructor if provided,
48+
# otherwise it triggers Boto3's lazy-loading discovery (e.g., metadata service).
49+
self._cached_region = self.session.region_name
50+
51+
if not self._cached_region:
52+
print("[ERROR] Boto3 was unable to resolve an AWS region.", file=sys.stderr)
53+
raise GoogleAuthError("Boto3 was unable to resolve an AWS region.")
54+
55+
print(f"[INFO] Boto3 resolved AWS Region: {self._cached_region}")
56+
return self._cached_region
57+
58+
def get_aws_security_credentials(self, context, request=None) -> AwsSecurityCredentials:
59+
"""Retrieves AWS security credentials using Boto3's default provider chain."""
60+
aws_credentials = self.session.get_credentials()
61+
if not aws_credentials:
62+
print("[ERROR] Unable to resolve AWS credentials.", file=sys.stderr)
63+
raise GoogleAuthError("Unable to resolve AWS credentials from the provider chain.")
64+
65+
print(f"[INFO] Resolved AWS Access Key ID: {aws_credentials.access_key}")
66+
67+
return AwsSecurityCredentials(
68+
access_key_id=aws_credentials.access_key,
69+
secret_access_key=aws_credentials.secret_key,
70+
session_token=aws_credentials.token,
71+
)
72+
73+
74+
def main():
75+
"""Main function to demonstrate the custom AWS supplier."""
76+
print("--- Starting Script ---")
77+
78+
gcp_audience = os.getenv("GCP_WORKLOAD_AUDIENCE")
79+
sa_impersonation_url = os.getenv("GCP_SERVICE_ACCOUNT_IMPERSONATION_URL")
80+
gcs_bucket_name = os.getenv("GCS_BUCKET_NAME")
81+
82+
print(f"GCP_WORKLOAD_AUDIENCE: {gcp_audience}")
83+
print(f"GCS_BUCKET_NAME: {gcs_bucket_name}")
84+
85+
if not all([gcp_audience, sa_impersonation_url, gcs_bucket_name]):
86+
print("[ERROR] Missing required environment variables.", file=sys.stderr)
87+
raise GoogleAuthError("Missing required environment variables.")
88+
89+
custom_supplier = CustomAwsSupplier()
90+
91+
credentials = AwsCredentials(
92+
audience=gcp_audience,
93+
subject_token_type="urn:ietf:params:aws:token-type:aws4_request",
94+
service_account_impersonation_url=sa_impersonation_url,
95+
aws_security_credentials_supplier=custom_supplier,
96+
scopes=['https://www.googleapis.com/auth/devstorage.read_write'],
97+
)
98+
99+
bucket_url = f"https://storage.googleapis.com/storage/v1/b/{gcs_bucket_name}"
100+
print(f"Request URL: {bucket_url}")
101+
102+
authed_session = AuthorizedSession(credentials)
103+
try:
104+
print("Attempting to make authenticated request to Google Cloud Storage...")
105+
res = authed_session.get(bucket_url)
106+
res.raise_for_status()
107+
print("\n--- SUCCESS! ---")
108+
print("Successfully authenticated and retrieved bucket data:")
109+
print(json.dumps(res.json(), indent=2))
110+
except Exception as e:
111+
print("--- FAILED --- ", file=sys.stderr)
112+
print(e, file=sys.stderr)
113+
exit(1)
114+
115+
116+
if __name__ == "__main__":
117+
main()

0 commit comments

Comments
 (0)