From 0f7b86b1d13d5e46700b2b191b744fc7727ddffe Mon Sep 17 00:00:00 2001 From: Srevin Saju Date: Fri, 21 Apr 2023 23:49:21 +0530 Subject: [PATCH] feat: add support for passing access tokens, or access token credential files to the keyring as environment variables Sometimes, there are scenarios where keyring needs to be invoked from a docker container, and you would probably not want to install 'gcloud' in your docker container to keep it light weight. in these cases, its easier for the developer to create the access config file using gcloud outside the docker build, and then passing them as a docker secret. a specific scenario: while using google cloud build along with docker buildkit, the google auth keyring does not work, because the docker builder needs to be building on --network=cloudbuild, but --network=cloudbuild is an unsupported network on docker buildkit builder --- keyrings/gauth.py | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/keyrings/gauth.py b/keyrings/gauth.py index ba8d2cf..340aeaa 100644 --- a/keyrings/gauth.py +++ b/keyrings/gauth.py @@ -14,6 +14,8 @@ limitations under the License. """ +import os + import google from google.auth.transport import requests from google.auth.exceptions import DefaultCredentialsError @@ -72,13 +74,42 @@ def get_credential(self,service,username): def get_gcloud_credential(): - # fall back to fetching credentials from gcloud if Application Default Credentials fails - try: - logging.warning("Trying to retrieve credentials from gcloud...") - command = subprocess.run(['gcloud','config','config-helper','--format=json(credential)'], check=True, stdout=subprocess.PIPE, universal_newlines=True) - except Exception as e: - raise Exception ("gcloud command exited with status: {0}".format(e)) - result = json.loads(command.stdout) + # check if the user has set a GOOGLE_ACCESS_TOKEN env var + # this value can be retrieved from + # + # $ gcloud auth print-access-token + # (or) + # $ GOOGLE_ACCESS_TOKEN=$(gcloud auth print-access-token) python3 ... + # + # we will return this token immediately. + # developers please note that, this token is only valid for 1 hour. + access_token = os.getenv("GOOGLE_ACCESS_TOKEN") + if access_token is not None: + logging.warning("Using access token from GOOGLE_ACCESS_TOKEN env var...") + return access_token + + # check if the user has set a GOOGLE_ACCESS_TOKEN_CREDENTIALS + # this is a json file, which can be exported like + # + # $ gcloud config config-helper --format="json(credential)" > key.json + # $ GOOGLE_ACCESS_TOKEN_CREDENTIALS=key.json python3 some.py + # + access_token_credentials_file = os.getenv("GOOGLE_ACCESS_TOKEN_CREDENTIALS") + if access_token_credentials_file is not None: + logging.warning("Using access token from file defined in GOOGLE_ACCESS_TOKEN_CREDENTIALS env var...") + with open(access_token_credentials_file) as fp: + json_data = fp.read() + else: + # fall back to fetching credentials from gcloud if Application Default Credentials fails + # and if other env var approaches fail + try: + logging.warning("Trying to retrieve credentials from gcloud...") + command = subprocess.run(['gcloud','config','config-helper','--format=json(credential)'], check=True, stdout=subprocess.PIPE, universal_newlines=True) + except Exception as e: + raise Exception ("gcloud command exited with status: {0}".format(e)) + json_data = command.stdout + + result = json.loads(json_data) credential = result.get("credential") if credential is None: raise Exception("No credential returned from gcloud")