¿Cómo autenticar las API de Google (API de Google Drive) desde Google Compute Engine y localmente sin descargar las credenciales de la cuenta de servicio?
Nuestra empresa está trabajando en el procesamiento de datos de Google Sheets (dentro de Google Drive) de Google Cloud Platform y tenemos algunos problemas con la autenticación.
Hay dos lugares diferentes donde necesitamos ejecutar código que hace llamadas API a Google Drive: dentro de la producción en Google Compute Engine y dentro de los entornos de desarrollo, es decir, localmente en las computadoras portátiles de nuestros desarrolladores.
Nuestra empresa es bastante estricta con las credenciales y no permite la descarga de claves JSON de credenciales de cuentas de servicio (esta es una mejor práctica y proporciona mayor seguridad). Aparentemente, todos los documentos de GCP dicen simplemente descargar la clave JSON para una cuenta de servicio y usarla. O los documentos de API / Desarrolladores de Google dicen que debe crear una ID de cliente OAuth2 y descargar su clave como aquí .
A menudo usan un código como este:
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
Pero no podemos (o simplemente no queremos) descargar nuestras claves JSON de cuenta de servicio, por lo que estamos atascados si solo seguimos los documentos.
Para el entorno de Google Compute Engine, hemos podido autenticarnos mediante el uso de credenciales predeterminadas de la aplicación (ADC) de GCP, es decir, sin especificar explícitamente las credenciales para usar en el código y dejar que las bibliotecas cliente "simplemente funcionen". Esto funciona muy bien siempre y cuando se garantice que la máquina virtual se crea con los alcances correctos https://www.googleapis.com/auth/drive
y el correo electrónico de la cuenta de servicio de cálculo predeterminado recibe permiso para acceder a la hoja; esto se explica en los documentos aquí . Puedes hacer esto así;
from googleapiclient.discovery import build
service = build('sheets', 'v4')
SPREADSHEET_ID="<sheet_id>"
RANGE_NAME="A1:A2"
s = service.spreadsheets().values().get(
spreadsheetId=SPREADSHEET_ID,
range=RANGE_NAME, majorDimension="COLUMNS"
).execute()
Sin embargo, ¿cómo hacemos esto para el desarrollo, es decir, localmente en las computadoras portátiles de nuestros desarrolladores? Nuevamente, sin descargar ninguna clave JSON, y preferiblemente con el enfoque más "simplemente funciona" posible.
Por lo general, usamos gcloud auth application-default login
para crear credenciales de aplicación predeterminadas que usan las bibliotecas cliente de Google y que "simplemente funcionan", como para Google Storage. Sin embargo, esto no funciona para las API de Google fuera de GCP, como la API de Google Drive service = build('sheets', 'v4')
que falla con este error: "La solicitud tenía alcances de autenticación insuficientes". Luego probamos todo tipo de soluciones como:
credentials, project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/drive"])
y
credentials, project_id = google.auth.default()
credentials = google_auth_oauthlib.get_user_credentials(
["https://www.googleapis.com/auth/drive"], credentials._client_id, credentials._client_secret)
)
y más ... Todos los cuales dan una gran cantidad de errores / problemas que no podemos superar cuando intentamos realizar la autenticación en la API de Google Drive :(
¿Alguna idea?
Respuestas
Un método para facilitar la autenticación desde entornos de desarrollo es utilizar la suplantación de cuentas de servicio .
Aquí hay un blog sobre el uso de la suplantación de la cuenta de servicio, incluidos los beneficios de hacerlo. @johnhanley (quien escribió la publicación del blog) es un gran tipo y también tiene muchas respuestas muy informativas sobre SO.
Para poder hacer que su máquina local se autentique para la API de Google Drive, deberá crear credenciales de aplicación predeterminadas en su máquina local que se haga pasar por una cuenta de servicio y aplicar los alcances necesarios para las API a las que desea acceder.
Para poder hacerse pasar por una cuenta de servicio, su usuario debe tener el rol roles/iam.serviceAccountTokenCreator
. Este rol se puede aplicar a un proyecto completo o a una cuenta de servicio individual.
Puede usar el gcloudpara hacer esto:
gcloud iam service-accounts add-iam-policy-binding [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL] \
--member user:[USER_EMAIL] \
--role roles/iam.serviceAccountTokenCreator
Una vez hecho esto, cree las credenciales locales:
gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/accounts.reauth \
--impersonate-service-account=[COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
Esto resolverá el error de alcance que obtuvo. Los tres ámbitos adicionales añadidos más allá del ámbito de la API de Drive son los ámbitos predeterminados que se gcloud auth application-default login
aplican y son necesarios.
Si aplica ámbitos sin suplantación, obtendrá un error como este al intentar autenticarse:
HttpError: <HttpError 403 when requesting https://sheets.googleapis.com/v4/spreadsheets?fields=spreadsheetId&alt=json returned "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the sheets.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.">
Una vez que haya configurado las credenciales, puede usar el mismo código que se ejecuta en Google Compute Engine en su máquina local :)
Nota: también es posible establecer la suplantación de identidad para todos los comandos de gcloud:
gcloud config set auth/impersonate_service_account [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
Crear credenciales de aplicación predeterminadas en su máquina local haciéndose pasar por una cuenta de servicio es una forma hábil de autenticar el código de desarrollo. Significa que el código tendrá exactamente los mismos permisos que la cuenta de servicio que está suplantando. Si esta es la misma cuenta de servicio que ejecutará el código en producción, sabrá que el código en desarrollo se ejecuta de la misma manera que en producción. También significa que nunca tendrá que crear ni descargar claves de Cuenta de servicio.