Como autenticar APIs do Google (API do Google Drive) do Google Compute Engine e localmente sem baixar as credenciais da conta de serviço?
Nossa empresa está trabalhando no processamento de dados do Planilhas Google (no Google Drive) do Google Cloud Platform e estamos tendo alguns problemas com a autenticação.
Existem dois lugares diferentes onde precisamos executar o código que faz chamadas de API para o Google Drive: na produção no Google Compute Engine e nos ambientes de desenvolvimento, ou seja, localmente nos laptops dos desenvolvedores.
Nossa empresa é bastante rígida quanto às credenciais e não permite o download de chaves JSON de credenciais de contas de serviço (essa é uma prática recomendada e oferece maior segurança). Aparentemente, todos os documentos do GCP dizem para simplesmente baixar a chave JSON para uma conta de serviço e usá-la. Ou os documentos de APIs / desenvolvedores do Google dizem para criar um ID de cliente OAuth2 e baixar sua chave como aqui .
Eles costumam usar códigos 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)
Mas não podemos (ou simplesmente não queremos) fazer o download das chaves JSON da nossa conta de serviço, então ficaremos presos se apenas seguirmos os documentos.
Para o ambiente do Google Compute Engine, conseguimos autenticar usando GCP Application Default Credentials (ADCs) - ou seja, não especificando explicitamente as credenciais para usar no código e permitindo que as bibliotecas de cliente "simplesmente funcionem" - isso funciona muito bem, desde que garantam que a VM é criada com os escopos corretos https://www.googleapis.com/auth/drivee o e-mail da conta de serviço de computação padrão recebe permissão para a planilha que precisa ser acessada - isso é explicado nos documentos aqui . Você pode fazer isso assim;
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()
No entanto, como fazemos isso para o desenvolvimento, ou seja, localmente nos laptops de nossos desenvolvedores? Novamente, sem baixar nenhuma chave JSON e, de preferência, com a abordagem mais “funcional” possível?
Normalmente usamos gcloud auth application-default loginpara criar credenciais de aplicativo padrão que as bibliotecas cliente do Google usam e que “simplesmente funcionam”, como para o Google Storage. No entanto, isso não funciona para APIs do Google fora do GCP, como a API do Google Drive service = build('sheets', 'v4')que falha com este erro: “A solicitação tinha escopos de autenticação insuficientes.”. Em seguida, tentamos todos os tipos de soluções, como:
credentials, project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/drive"])
e
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)
)
e muito mais ... Todos fornecem uma miríade de erros / problemas que não podemos superar ao tentar fazer a autenticação na API do Google Drive :(
Alguma ideia?
Respostas
Um método para facilitar a autenticação de ambientes de desenvolvimento é usar a representação da conta de serviço .
Aqui está um blog sobre como usar a falsificação de identidade de conta de serviço, incluindo os benefícios de fazer isso. @johnhanley (que escreveu o post do blog) é um cara legal e tem muitas respostas muito informativas sobre o SO também!
Para que sua máquina local seja autenticada para a API do Google Drive, você precisará criar credenciais de aplicativo padrão em sua máquina local que represente uma conta de serviço e aplicar os escopos necessários para as APIs que deseja acessar.
Para poder se passar por uma conta de serviço, seu usuário deve ter a função roles/iam.serviceAccountTokenCreator. Essa função pode ser aplicada a um projeto inteiro ou a uma conta de serviço individual.
Você pode usar o gcloudpara fazer isso:
gcloud iam service-accounts add-iam-policy-binding [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL] \
--member user:[USER_EMAIL] \
--role roles/iam.serviceAccountTokenCreator
Depois de fazer isso, crie as credenciais locais:
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]
Isso resolverá o erro de escopo que você obteve. Os três escopos extras adicionados além do escopo da API do Drive são os escopos padrão que gcloud auth application-default loginse aplicam e são necessários.
Se você aplicar escopos sem personificação, receberá um erro como este ao tentar autenticar:
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/.">
Depois de configurar as credenciais, você pode usar o mesmo código que é executado no Google Compute Engine em sua máquina local :)
Observação: também é possível definir a representação para todos os comandos gcloud:
gcloud config set auth/impersonate_service_account [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
Criar credentails de aplicativo padrão em sua máquina local personificando uma conta de serviço é uma maneira inteligente de autenticar o código de desenvolvimento. Isso significa que o código terá exatamente as mesmas permissões da conta de serviço que está representando. Se esta for a mesma conta de serviço que executará o código em produção, você sabe que o código em desenvolvimento é executado da mesma forma que em produção. Também significa que você nunca precisa criar ou fazer download de nenhuma chave de conta de serviço.