Google Cloud stores your credentials in a database on your system. These credentials can then be used over and over. Google’s choice of a database means that the CLI
and SDK
tools can manage a huge number of credentials efficiently. Credentials are managed by configurations
.
However, Google also chose not to encrypt the database storing these credentials and I think that this is a potential security weakness and should be reconsidered. IMHO all data should be encrypted. Data that authorizes or protects other data MUST be encrypted.
More details about configurations are in another article that I wrote.
A gcloud configuration is a set of properties that govern the behavior of gcloud and other Google Cloud SDK tools. When you first install gcloud on your desktop a configuration named default
is created.
A gcloud configuration is managed by gcloud config configurations
. To see the list of configurations on your system:
1 |
gcloud config configurations list |
This will output a list of configurations present on your system:
1 2 3 4 |
NAME IS_ACTIVE ACCOUNT PROJECT DEFAULT_ZONE DEFAULT_REGION default True user1@example.com default-123456 us-west1-a us-west1 dev False user2@example.com development-123456 us-east4-c us-east4 prod False user3@example.com production-123456 us-east4-c us-east4 |
The link between a set of configurations and a set of credentials in the database is via the account id
.
The databases are stored in the following directory. Replace username
with your Windows user name.
1 |
C:\Users\username\AppData\Roaming\gcloud |
For Linux:
1 |
~/.config/gcloud |
Credentials are stored in two files: access_tokens.db
and credentials.db
in this directory. Both of these files are an SQLite database. To see the contents of these databases I wrote two small Python programs.
ACCESS_TOKENS.DB
The database access_tokens.db
contains a table named access_tokens
with four columns account_id
access_token
token_expiry
rapt_token
.
Table schema:
1 |
CREATE TABLE IF NOT EXISTS "access_tokens" (account_id TEXT PRIMARY KEY, access_token TEXT, token_expiry TIMESTAMP, rapt_token TEXT); |
The column account_id
is the email address associated with the credentials.
The access_token
is the access token used for authenticating requests, for example in CURL
and REST APIs
. In another article, I will cover in detail what access tokens and credentials look like and how to use them in your own software. I will also cover how to generate access tokens from credentials.
The token_expiry
is the date that the token expires.
The rapt_token
is involved with token refresh. I have not yet investigated how to use this.
This Python program will output the contents of the access_tokens.db
database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import sqlite3 import json import os # The name of the database to process filename = 'access_tokens.db' # Get the user's home directory on Windows home = os.environ['USERPROFILE'] # Build the full path to the database path = home + "\\AppData\\Roaming\\gcloud\\" + filename if os.path.exists(path) is False: print('Error: File does not exist') print('File:', path) exit(1) conn = sqlite3.connect(path) cursor = conn.execute('SELECT * FROM access_tokens') rows = cursor.fetchall() if len(rows) is 0: print('Error: Empty database') exit(1) # Note: This section is not displaying the access_token (row[1]) because it is too long print('{:30s} {:30s} {}'.format('Account ID', 'Expiration', 'RAPT')) for row in rows: print('{:30s} {:30s} {}'.format(row[0], row[2], row[3])) print('') print('########################################') print('Access Tokens') print('') # Code to display the access_token for row in rows: print(row[1]) # access_token |
This is the output from the program. I have obfuscated the output to protect the access tokens.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Account ID Expiration RAPT user1@example.com 2017-08-15 10:17:10.019000 None user2@example.com 2018-10-10 06:40:08.479000 None user3@example.com 2018-10-13 01:47:59.651000 None user4@example.com 2018-11-02 01:28:59.602000 None ######################################## Access Tokens ya29.GlyoabcdefghijklmnopqrstuvwxyzUtmlDD7flxUEYyV5fuvHopIoiY7Uq1234567890ABCDEFGHIJKLMNOPQRSTUCWXYZ115ZLli3AAsAEACmdCw4oRNQEYqWnmg ya29.Glwyabcdefghijklmnopqrstuvwxyzztd68YcGwQOQJc9JwAyMQl9wiTs4Q1234567890ABCDEFGHIJKLMNOPQRSTUCWXYZzoBVg66jxYqsmuTUZqYLGpz36zuKHrw ya29.Glw1abcdefghijklmnopqrstuvwxyzaus_auVkXDGjTSsqI7d3Q_qY2MfKgi1234567890ABCDEFGHIJKLMNOPQRSTUCWXYZpbsuDDDVG588MOHI0FkZZTrVT55CeQ ya29.GlxabcdefghijklmnopqrstuvwxyzMVGfDl8mjs19_ci3rGVsxfzuIWo_HxoC1234567890ABCDEFGHIJKLMNOPQRSTUCWXYZAfpuNHHEHB9jRKmifxJ2MwMq7ddZA |
CREDENTIALS.DB
The database credentials.db
contains a table named credentials
with two columns account_id
value
.
Table schema:
1 |
CREATE TABLE IF NOT EXISTS "credentials" (account_id TEXT PRIMARY KEY, value BLOB); |
The column account_id
is the email address associated with the credentials.
The column value
is your credentials in Json
format. I will cover the format of credentials in detail in another article.
This Python program will output the contents of the credentials.db
database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import sqlite3 import json import os # The name of the database to process filename = 'credentials.db' # Get the user's home directory on Windows home = os.environ['USERPROFILE'] # Build the full path to the database path = home + "\\AppData\\Roaming\\gcloud\\" + filename if os.path.exists(path) is False: print('Error: File does not exist') print('File:', path) exit(1) conn = sqlite3.connect(path) cursor = conn.execute('SELECT * FROM credentials') rows = cursor.fetchall() if len(rows) is 0: print('Error: Empty database') exit(1) # Note: This section is not displaying the value (row[1]) because it is too long print('Account ID') for row in rows: print('{}'.format(row[0])) print('') print('########################################') print('Credentials') print('') # Code to display the credential for row in rows: print(row[1]) # value |
This is the output from the program. I have obfuscated the output to protect the credentials by deleting them from the listing.
1 2 3 4 5 6 7 8 9 10 |
Account ID user1@example.com user2@example.com user3@example.com user4@example.com ######################################## Credentials <Contents deleted for this article for security reasons> |
There you have it. Details on where Google stores credentials on your system, the format of the database and what the credentials look like on your system.
I design software for enterprise-class systems and data centers. My background is 30+ years in storage (SCSI, FC, iSCSI, disk arrays, imaging) virtualization. 20+ years in identity, security, and forensics.
For the past 14+ years, I have been working in the cloud (AWS, Azure, Google, Alibaba, IBM, Oracle) designing hybrid and multi-cloud software solutions. I am an MVP/GDE with several.
Leave a Reply