Saltar al contenido

¿Cómo creo un token de acceso a partir de las credenciales de la cuenta de servicio mediante la API REST?

Recuerda que en las ciencias un problema puede tener más de una soluciones, de igual modo enseñamos lo más óptimo y mejor.

Solución:

El siguiente ejemplo muestra varios pasos importantes para llamar a las API de Google Cloud sin usar un SDK en Python. Un código similar funciona en casi cualquier idioma (c#, java, php, nodejs).

Cambie el código fuente con el nombre del archivo Json de su cuenta de servicio, su Zona de Google y su ID de proyecto.

Este ejemplo enumerará las instancias en una zona para el proyecto especificado. A partir de este ejemplo, conocerá el marco para llamar a una API para crear instancias de GCE.

Este código le mostrará cómo:

  1. Cómo cargar las credenciales de la cuenta de servicio desde un archivo Json.
  2. Cómo extraer la clave privada utilizada para firmar solicitudes.
  3. Cómo crear un JWT (Json Web Token) para Google Oauth 2.0.
  4. Cómo configurar Google Scopes (permisos).
  5. Cómo firmar un JWT para crear un Signed-JWT (JWS).
  6. Cómo cambiar el JWT firmado por un token de acceso de Google OAuth 2.0.
  7. Cómo configurar el tiempo de caducidad. Este programa tiene un valor predeterminado de 3600 segundos (1 hora).
  8. Cómo llamar a una API de Google y configurar el encabezado de autorización.
  9. Cómo procesar los resultados de Json devueltos y mostrar el nombre de cada instancia.

Programa de ejemplo en Python 3.x:

'''
This program lists lists the Google Compute Engine Instances in one zone
'''
# Author: John Hanley
# https://www.jhanley.com

import time
import json
import jwt
import requests
import httplib2

# Project ID for this request.
project = 'development-123456'

# The name of the zone for this request.
zone = 'us-west1-a'

# Service Account Credentials, Json format
json_filename = 'service-account.json'

# Permissions to request for Access Token
scopes = "https://www.googleapis.com/auth/cloud-platform"

# Set how long this token will be valid in seconds
expires_in = 3600   # Expires in 1 hour

def load_json_credentials(filename):
    ''' Load the Google Service Account Credentials from Json file '''

    with open(filename, 'r') as f:
        data = f.read()

    return json.loads(data)

def load_private_key(json_cred):
    ''' Return the private key from the json credentials '''

    return json_cred['private_key']

def create_signed_jwt(pkey, pkey_id, email, scope):
    ''' Create a Signed JWT from a service account Json credentials file
    This Signed JWT will later be exchanged for an Access Token '''

    # Google Endpoint for creating OAuth 2.0 Access Tokens from Signed-JWT
    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    issued = int(time.time())
    expires = issued + expires_in   # expires_in is in seconds

    # Note: this token expires and cannot be refreshed. The token must be recreated

    # JWT Headers
    additional_headers = 
            'kid': pkey_id,
            "alg": "RS256",
            "typ": "JWT"    # Google uses SHA256withRSA
    

    # JWT Payload
    payload = 
        "iss": email,       # Issuer claim
        "sub": email,       # Issuer claim
        "aud": auth_url,    # Audience claim
        "iat": issued,      # Issued At claim
        "exp": expires,     # Expire time
        "scope": scope      # Permissions
    

    # Encode the headers and payload and sign creating a Signed JWT (JWS)
    sig = jwt.encode(payload, pkey, algorithm="RS256", headers=additional_headers)

    return sig

def exchangeJwtForAccessToken(signed_jwt):
    '''
    This function takes a Signed JWT and exchanges it for a Google OAuth Access Token
    '''

    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    params = 
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion": signed_jwt
    

    r = requests.post(auth_url, data=params)

    if r.ok:
        return(r.json()['access_token'], '')

    return None, r.text

def gce_list_instances(accessToken):
    '''
    This functions lists the Google Compute Engine Instances in one zone
    '''

    # Endpoint that we will call
    url = "https://www.googleapis.com/compute/v1/projects/" + project + "/zones/" + zone + "/instances"

    # One of the headers is "Authorization: Bearer $TOKEN"
    headers = 
        "Host": "www.googleapis.com",
        "Authorization": "Bearer " + accessToken,
        "Content-Type": "application/json"
    

    h = httplib2.Http()

    resp, content = h.request(uri=url, method="GET", headers=headers)

    status = int(resp.status)

    if status < 200 or status >= 300:
        print('Error: HTTP Request failed')
        return

    j = json.loads(content.decode('utf-8').replace('n', ''))

    print('Compute instances in zone', zone)
    print('------------------------------------------------------------')
    for item in j['items']:
        print(item['name'])

if __name__ == '__main__':
    cred = load_json_credentials(json_filename)

    private_key = load_private_key(cred)

    s_jwt = create_signed_jwt(
            private_key,
            cred['private_key_id'],
            cred['client_email'],
            scopes)

    token, err = exchangeJwtForAccessToken(s_jwt)

    if token is None:
        print('Error:', err)
        exit(1)

    gce_list_instances(token)

Para más información visita mi blog. Escribo artículos como este y publico el código fuente para ayudar a otros a comprender cómo escribir software para la nube.

www.jhanley.com

Existe una forma más sencilla de generar un token desde una cuenta de servicio, utilizando las bibliotecas de Google.

from google.auth.transport import requests
from google.oauth2 import service_account

CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
CREDENTIALS_KEY_PATH = '/PATH/TO/SERVICE_ACCOUNT.json'

def get_service_account_token():
  credentials = service_account.Credentials.from_service_account_file(
          CREDENTIALS_KEY_PATH, scopes=CREDENTIAL_SCOPES)
  credentials.refresh(requests.Request())
  return credentials.token

O si desea utilizar la autenticación predeterminada

import google
from google.auth.transport import requests

CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"] 

def get_default_token():
  credentials, project_id = google.auth.default(scopes=CREDENTIAL_SCOPES)
  credentials.refresh(requests.Request())
  return credentials.token

Cuando cartas credenciales se crea el objeto, el token está vacío, pero después de actualizar cartas credencialescontiene el token de acceso que se puede usar como encabezado en las solicitudes de API

Sección de Reseñas y Valoraciones

Si crees que ha sido provechoso este post, sería de mucha ayuda si lo compartes con más juniors de esta manera contrubuyes a dar difusión a nuestro contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *