59

I'm trying to make a project that will upload Google Storage JSON file to BigQuery (just automate something that is done manually now), and I'd like to use a 'service account' for this as my script is going to be run on daily basis.

After reading everything I can found about using service account, I'm still struggling to authenticate.

Here is what i've done so far:

  1. Created JSON key file for service account
  2. Installed client libraries: pip install --upgrade google-cloud-bigquery
  3. Installed Google Cloud SDK according to: https://cloud.google.com/sdk/docs/
  4. Run export GOOGLE_APPLICATION_CREDENTIALS=<path_to_service_account_file> with key path specified correctly

Now I'm trying to run the following python script:

from google.cloud import bigquery
bigquery_client = bigquery.Client()

But I get this error:

google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credential and re-run the application. For more information, please see https://developers.google.com/accounts/docs/application-default-credentials.

I'm quite new to both Python and the Google Cloud API so possbily missed something. Can someone point out where/what was wrong in my steps above or point me to clear instruction for dummys about setting up and running simple script with BigQuery using service account?

5 Answers 5

85

I usually set this variable in the python script itself, something like:

import os
from google.cloud.bigquery.client import Client

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'path_to_json_file'
bq_client = Client()
Sign up to request clarification or add additional context in comments.

4 Comments

setting the credentials locally and running the script works. But when I am creating a docker image for the script it shows that JSON file is not there! How do I add service JSON file to the docker image
@Madhi I recommend asking this question on SO explaining what you are trying to do (I imagine this is something related to not properly adding the file in the build docker process but more information is needed in your case)
Thanks for the reply comment. I figured out the solution and everything is working fine inside a docker image. Thanks!
@Madhi please post your solutions for others to see
45

If you have implemented more fine-grained control over service accounts permissions and you have an app that needs to use several of them (say one for Pub/Sub, one for storage), then you would have to set the GOOGLE_APPLICATION_CREDENTIALS environment variable before creating each client.

Instead, you can load your credentials separately and pass them to their appropriate clients like so:

import json
    
from google.cloud import storage
from google.oauth2 import service_account
    
project_id = 'my-test-project'
    
with open('/path/to/my/service_keys/storage_service.json') as source:
    info = json.load(source)

storage_credentials = service_account.Credentials.from_service_account_info(info)
    
storage_client = storage.Client(project=project_id, credentials=storage_credentials)

Just make sure in your IAM console that the account has the right permissions to perform the operations you need it to do, but luckily in that case the error messages are really informative.

3 Comments

Hi, I know this is an old post, but I just had a quick question, as I am stuck with setting up my service account. Is it a case that once you set your key, you download it and store it where you want it? or there is a way to find the location as to where this is stored? this is where I am confused. Need to paste path of service.json in my python file that I downloaded to run a dataflow pipeline.
@mowem10 You can always download the key again from GCP and then move it to where the script can find it 😊
This doesn't work anymore - fails with AttributeError: 'Credentials' object has no attribute 'authorize'. (google-cloud-storage 2.19.0, google-auth 2.38.0, google-auth-oauthlib 1.2.1). It seems there's no longer a way to use service account credentials in the SDK, other than by using GOOGLE_APPLICATION_CREDENTIALS , which is considered bad practice by Google.
16

Are you running the script in the same command line session as the one you set your environment variable in using export? If not, you might want to look into setting it for your user or system (see this question for more info).

Another option that might make things even easier and takes care of these things automatically is using the gcloud cli tool. If you look at the second option here under the How the Application Default Credentials work, you can find info on how to use it to manage the credentials for you (gcloud auth login and gcloud auth application-default login)

2 Comments

In my case, the gcloud auth application-default login command was the right (and non-obvious) solution. Thanks!
This gcloud auth application-default login requirement was so hard to find!
6

I simply set credentials as a variable in python code, not a good idea to show credentials directly in python code though :)

#!pip install google-api-python-client
#!pip install google-cloud-dns

from google.oauth2 import service_account
from googleapiclient import discovery
from google.cloud import dns


#Downloaded credentials in JSON format
gcp_sa_credentials={
  "type": "service_account",
  "project_id": "mygcpprojectid-1122",
  "private_key_id": "myprivkeyid",
  "private_key": "-----BEGIN PRIVATE KEY-----\nmyprivatekey\n-----END PRIVATE KEY-----\n",
  "client_email": "[email protected]",
  "client_id": "myclientid",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/client-mail%40mygcpprojectid-1122.iam.gserviceaccount.com"
}

project_id=gcp_sa_credentials["project_id"]

credentials = service_account.Credentials.from_service_account_info(gcp_sa_credentials)
client = dns.Client(project=project_id,credentials=credentials)

2 Comments

dns is not defined. We need pip install google-cloud-storage then from google.cloud import storage as dns
@mountrix , I have specified callling dns.Client() now, can be managed through pip install google-cloud-dns then from google.cloud import dns
5

This is an old question however I want to add that you must create a new service account and not use an old one. A recent Google Cloud Next presentation on security stated that there is no guarantee that the default service account will exist in future, and it could be removed at any time (or its available permissions changed), so none of your applications should depend on it. Also I've found that there are potential issues with authentication when using the default service account and creating a new one is more likely to allow the control you need to successfully authenticate.

Refer to the following YouTube presentation from 11mins 10s in:

https://youtu.be/ZQHoC0cR6Qw?t=670

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.