Skip to content

Commit

Permalink
Support gcloud app default fallback credentials
Browse files Browse the repository at this point in the history
  • Loading branch information
lrakai committed Nov 19, 2023
1 parent 21def92 commit a67faf7
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 4 deletions.
8 changes: 8 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
"dependsOn": [
"docker-build"
],
"dockerRun": {
"volumes": [
{
"localPath": "${userHome}/.config/gcloud",
"containerPath": "/home/appuser/.config/gcloud"
}
],
},
"python": {
"file": "src/entry.py"
}
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,39 @@ Envrionment for working with GCP VCFs

1. Run `init.sh` (Mac/Linux)/`init.ps1` (Windows) to set up the virtual environment again. (only the `venv/` directory is impacted by this operation)

## Authentication options

The launch.json encoding of credential key, credential ID, and project ID for authentication works well for debugging the current file.
To streamline the authentication process when debugging using containers (VS Code Docker debug profile), `gcloud` application default credentials and .config.env files are used.
<ins>.config.env is higher precedence</ins> and gcloud credentials are used as a fallback.

Refer to the [`google.auth` documentation](https://googleapis.dev/python/google-auth/latest/reference/google.auth.html#google.auth.default).
Note that `CREDENTIAL_KEY` defined in `.config.env` is used to populate a file that is pointed to by the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
# gcloud auth application-default login

### gcloud CLI credentials

The gcloud credentials can be used by the google.auth Python library to authenticate with Google Cloud.
The gcloud CLI must be authenticated with <ins>application default</ins> credentials (`gcloud auth application-default login`) and a default project may be set (`gcloud config set project ...`).
The default project can be retrieved from .config.env.
If the project is not defined in .config.env, the default project must be defined in the gcloud CLI (`gcloud config set project ...`).

If gcloud is authenticated, and a default project is set and displayed by `az config get project`, a .config.env file can be omitted.

### .config.env file

The .config.env file is similar to the environment variables defined in the launch.json file but is a flat file of variable declarations.
The contents of .config.env resemble:

```sh
CREDENTIAL_ID="your-service-account@your-project.iam.gserviceaccount.com",
CREDENTIAL_KEY="{\"type\":\"service_account\",\"project_id\":\"your-project\",\"private_key_id\":\"...}",
PROJECT_ID="your-project"
```

As mentioned, gcloud credentials may be used in lieu of `CREDENTIAL_ID`, and `CREDENTIAL_KEY`.
If the PROJECT_ID is set in .config.env it overrides the gcloud configured project.

## References

- [Google APIs Explorer](https://developers.google.com/apis-explorer)
Expand Down
39 changes: 35 additions & 4 deletions src/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,50 @@
load_dotenv()

import time
from config import EVENT_CONFIG
from vcf import handler
from config import CONFIG
import vcf

import os, sys
import google.auth

class credential_helper:
credentials = None
project_id = None

@staticmethod
def get_credentials(event):
if not credential_helper.credentials:
credential_helper.credentials, credential_helper.project_id = google.auth.default()
if not credential_helper.project_id:
credential_helper.project_id = credential_helper.credentials.quota_project_id
return credential_helper.credentials

vcf.get_credentials = credential_helper.get_credentials

def timed_handler(event, context):
start = time.time()
result = handler(event, context)
result = vcf.handler(event, context)
end = time.time()
print(end - start)
return result

def entry():
result = timed_handler(EVENT_CONFIG, None)
if os.environ.get('CREDENTIAL_KEY'):
# write credentials to file
with open('/tmp/credentials.json', 'w', encoding="utf-8") as f:
f.write(os.environ.get('CREDENTIAL_KEY'))
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '/tmp/credentials.json'
# cache credentials and handle project precedence (.config.env > gcloud default)
credential_helper.get_credentials(None)
if not os.environ.get('PROJECT_ID'):
print('PROJECT_ID not set, attempting to use gcloud default project')
if credential_helper.project_id:
print(f'Using {credential_helper.project_id} as PROJECT_ID')
CONFIG['environment_params']['project_id'] = credential_helper.project_id
else:
print('Could not find default project. Attempting to continue...', file=sys.stderr)

result = timed_handler(CONFIG, None)
print(result)

if __name__ == "__main__":
Expand Down

0 comments on commit a67faf7

Please sign in to comment.