18
18
import google .auth .compute_engine .credentials
19
19
import google .auth .iam
20
20
from google .auth .transport .requests import Request
21
+ from google .oauth2 import id_token
21
22
import google .oauth2 .credentials
22
23
import google .oauth2 .service_account
23
24
import requests
@@ -66,7 +67,6 @@ def trigger_dag(data, context=None):
66
67
# START COPIED IAP CODE
67
68
def make_iap_request (url , client_id , method = 'GET' , ** kwargs ):
68
69
"""Makes a request to an application protected by Identity-Aware Proxy.
69
-
70
70
Args:
71
71
url: The Identity-Aware Proxy-protected URL to fetch.
72
72
client_id: The client ID used by Identity-Aware Proxy.
@@ -75,54 +75,16 @@ def make_iap_request(url, client_id, method='GET', **kwargs):
75
75
**kwargs: Any of the parameters defined for the request function:
76
76
https://github.com/requests/requests/blob/master/requests/api.py
77
77
If no timeout is provided, it is set to 90 by default.
78
-
79
78
Returns:
80
79
The page body, or raises an exception if the page couldn't be retrieved.
81
80
"""
82
81
# Set the default timeout, if missing
83
82
if 'timeout' not in kwargs :
84
83
kwargs ['timeout' ] = 90
85
84
86
- # Figure out what environment we're running in and get some preliminary
87
- # information about the service account.
88
- bootstrap_credentials , _ = google .auth .default (
89
- scopes = [IAM_SCOPE ])
90
-
91
- # For service account's using the Compute Engine metadata service,
92
- # service_account_email isn't available until refresh is called.
93
- bootstrap_credentials .refresh (Request ())
94
-
95
- signer_email = bootstrap_credentials .service_account_email
96
- if isinstance (bootstrap_credentials ,
97
- google .auth .compute_engine .credentials .Credentials ):
98
- # Since the Compute Engine metadata service doesn't expose the service
99
- # account key, we use the IAM signBlob API to sign instead.
100
- # In order for this to work:
101
- # 1. Your VM needs the https://www.googleapis.com/auth/iam scope.
102
- # You can specify this specific scope when creating a VM
103
- # through the API or gcloud. When using Cloud Console,
104
- # you'll need to specify the "full access to all Cloud APIs"
105
- # scope. A VM's scopes can only be specified at creation time.
106
- # 2. The VM's default service account needs the "Service Account Actor"
107
- # role. This can be found under the "Project" category in Cloud
108
- # Console, or roles/iam.serviceAccountActor in gcloud.
109
- signer = google .auth .iam .Signer (
110
- Request (), bootstrap_credentials , signer_email )
111
- else :
112
- # A Signer object can sign a JWT using the service account's key.
113
- signer = bootstrap_credentials .signer
114
-
115
- # Construct OAuth 2.0 service account credentials using the signer
116
- # and email acquired from the bootstrap credentials.
117
- service_account_credentials = google .oauth2 .service_account .Credentials (
118
- signer , signer_email , token_uri = OAUTH_TOKEN_URI , additional_claims = {
119
- 'target_audience' : client_id
120
- })
121
- # service_account_credentials gives us a JWT signed by the service
122
- # account. Next, we use that to obtain an OpenID Connect token,
123
- # which is a JWT signed by Google.
124
- google_open_id_connect_token = get_google_open_id_connect_token (
125
- service_account_credentials )
85
+ # Obtain an OpenID Connect (OIDC) token from metadata server or using service
86
+ # account.
87
+ google_open_id_connect_token = id_token .fetch_id_token (Request (), client_id )
126
88
127
89
# Fetch the Identity-Aware Proxy-protected URL, including an
128
90
# Authorization header containing "Bearer " followed by a
@@ -132,49 +94,14 @@ def make_iap_request(url, client_id, method='GET', **kwargs):
132
94
headers = {'Authorization' : 'Bearer {}' .format (
133
95
google_open_id_connect_token )}, ** kwargs )
134
96
if resp .status_code == 403 :
135
- raise Exception ('Service account {} does not have permission to '
136
- 'access the IAP-protected application.' .format (
137
- signer_email ))
97
+ raise Exception ('Service account does not have permission to '
98
+ 'access the IAP-protected application.' )
138
99
elif resp .status_code != 200 :
139
100
raise Exception (
140
101
'Bad response from application: {!r} / {!r} / {!r}' .format (
141
102
resp .status_code , resp .headers , resp .text ))
142
103
else :
143
104
return resp .text
144
-
145
-
146
- def get_google_open_id_connect_token (service_account_credentials ):
147
- """Get an OpenID Connect token issued by Google for the service account.
148
-
149
- This function:
150
-
151
- 1. Generates a JWT signed with the service account's private key
152
- containing a special "target_audience" claim.
153
-
154
- 2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1
155
- has a target_audience claim, that endpoint will respond with
156
- an OpenID Connect token for the service account -- in other words,
157
- a JWT signed by *Google*. The aud claim in this JWT will be
158
- set to the value from the target_audience claim in #1.
159
-
160
- For more information, see
161
- https://developers.google.com/identity/protocols/OAuth2ServiceAccount .
162
- The HTTP/REST example on that page describes the JWT structure and
163
- demonstrates how to call the token endpoint. (The example on that page
164
- shows how to get an OAuth2 access token; this code is using a
165
- modified version of it to get an OpenID Connect token.)
166
- """
167
-
168
- service_account_jwt = (
169
- service_account_credentials ._make_authorization_grant_assertion ())
170
- request = google .auth .transport .requests .Request ()
171
- body = {
172
- 'assertion' : service_account_jwt ,
173
- 'grant_type' : google .oauth2 ._client ._JWT_GRANT_TYPE ,
174
- }
175
- token_response = google .oauth2 ._client ._token_endpoint_request (
176
- request , OAUTH_TOKEN_URI , body )
177
- return token_response ['id_token' ]
178
105
# END COPIED IAP CODE
179
106
180
107
# [END composer_trigger]
0 commit comments