Моя цель - воспроизвести / воспроизвести функциональность gcloud compute addresses create
без зависимости от двоичного файла gcloud.
Я пытаюсь использовать python для аутентификации POST в конечной точке вычисления googleapis в соответствии с документацией https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address о резервировании статического внешнего IP-адреса
Но мой POST возвращается каждый раз 401.
Я создал JWT из модуля Python google.auth.jwt, и когда я декодирую его, в JWT встроены все строки, которые я ожидаю увидеть.
Я также попытался включить в JWT комбинации следующих областей OAuth:
- "https://www.googleapis.com/auth/userinfo.email"
- "https://www.googleapis.com/auth/compute"
- "https://www.googleapis.com/auth/cloud-platform"
это моя функция для получения JWT с использованием информации в файле ключа JSON моей учетной записи службы
def _generate_jwt( tokenPath, expiry_length=3600 ):
now = int(time.time())
tokenData = load_json_data( tokenPath )
sa_email = tokenData['client_email']
payload = {
'iat': now,
# expires after 'expiry_length' seconds.
"exp": now + expiry_length,
'iss': sa_email,
"scope": " ".join( [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/userinfo.email"
] ),
'aud': "https://www.googleapis.com/oauth2/v4/token",
'email': sa_email
}
# sign with keyfile
signer = google.auth.crypt.RSASigner.from_service_account_file( tokenPath )
jwt = google.auth.jwt.encode(signer, payload)
return jwt
как только у меня есть JWT, я делаю следующее сообщение, которое терпит неудачу, 401, ::
gapiURL = 'https://www.googleapis.com/compute/v1/projects/' + projectID + '/regions/' + region + '/addresses'
jwtToken = _generate_jwt( servicetoken )
headers = {
'Authorization': 'Bearer {}'.format( jwtToken ),
'content-type' : 'application/json',
}
post = requests.post( url=gapiURL, headers=headers, data=data )
post.raise_for_status()
return post.text
Я получил 401 независимо от того, сколько комбинаций областей я использовал в JWT или разрешений, предоставленных моей учетной записи службы. Что я делаю не так?
edit : большое спасибо @JohnHanley за указание на то, что я пропускаю следующий / второй запрос POST для https://www.googleapis.com/oauth2/v4/token в последовательности аутентификации GCP. Итак, вы получаете JWT для получения токена доступа.
Я изменил свои звонки, чтобы использовать модуль python jwt, а не модуль google.auth.jwt, встроенный в google.auth.crypt.RSASigner. Так что код немного проще, и я поместил его в один метод
## serviceAccount auth sequence for google :: JWT -> accessToken
def gke_get_token( serviceKeyDict, expiry_seconds=3600 ):
epoch_time = int(time.time())
# Generate a claim from the service account file.
claim = {
"iss": serviceKeyDict["client_email"],
"scope": " ".join([
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email"
]),
"aud": "https://www.googleapis.com/oauth2/v4/token",
"exp": epoch_time + expiry_seconds,
"iat": epoch_time
}
# Sign claim with JWT.
assertion = jwt.encode( claim, serviceKeyDict["private_key"], algorithm='RS256' ).decode()
data = urllib.urlencode( {
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": assertion
} )
# Request the access token.
result = requests.post(
url="https://www.googleapis.com/oauth2/v4/token",
headers={
"Content-Type": "application/x-www-form-urlencoded"
},
data=data
)
result.raise_for_status()
return loadJsonData(result.text)["access_token"]