From 67630d4c52aef5ddcb15cff4f3b6594d447e8992 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Sun, 18 Jun 2023 14:46:06 +0200 Subject: [PATCH] Enable keystone token caching by OSC SDK uses python keyring library to enable token caching. Normally this is requiring a proper desktop (interactive) session, but there are some backend plugins working in non-interactive mode. Store cache in an unencrypted file on FS (this is not worse than storing passwords in plaintext). Change-Id: I42d698f15db5918443073fff8f27b926126d1d0f --- functions-common | 10 +++++++++- lib/libraries | 4 ++++ tools/update_clouds_yaml.py | 27 ++++++++++++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/functions-common b/functions-common index c57c4cc054..03d7c96417 100644 --- a/functions-common +++ b/functions-common @@ -1047,6 +1047,8 @@ function get_or_create_service { --description="$3" \ -f value -c id ) + # Drop cached token to invalidate catalog info in the token + remove_token_cache echo $service_id } @@ -1064,7 +1066,6 @@ function _get_or_create_endpoint_with_interface { endpoint_id=$(openstack --os-cloud devstack-system-admin endpoint create \ $1 $2 $3 --region $4 -f value -c id) fi - echo $endpoint_id } @@ -1088,6 +1089,8 @@ function get_or_create_endpoint { if [[ -n "$5" ]]; then _get_or_create_endpoint_with_interface $1 internal $5 $2 fi + # Drop cached token to invalidate catalog info in the token + remove_token_cache # return the public id to indicate success, and this is the endpoint most likely wanted echo $public_id } @@ -2517,6 +2520,11 @@ function is_fips_enabled { [ "$fips" == "1" ] } +function remove_token_cache { + # Remove Keyring cache file + rm ~/.local/share/python_keyring/keyring_pass.cfg +} + # Restore xtrace $_XTRACE_FUNCTIONS_COMMON diff --git a/lib/libraries b/lib/libraries index 9ea32304fc..146434e2b9 100755 --- a/lib/libraries +++ b/lib/libraries @@ -138,6 +138,10 @@ function install_libs { # doesn't pull in etcd3. pip_install etcd3 pip_install etcd3gw + + # Add libraries required for token caching by OpenStackSDK/CLI + pip_install keyring + pip_install keyrings.alt } # Restore xtrace diff --git a/tools/update_clouds_yaml.py b/tools/update_clouds_yaml.py index 74dcdb2a07..918988245b 100755 --- a/tools/update_clouds_yaml.py +++ b/tools/update_clouds_yaml.py @@ -30,7 +30,9 @@ class UpdateCloudsYaml(object): self._clouds_path = os.path.expanduser( '~/.config/openstack/clouds.yaml') self._create_directory = True - self._clouds = {} + self._keyringrc_path = os.path.expanduser( + '~/.config/python_keyring/keyringrc.cfg') + self._config = {} self._cloud = args.os_cloud self._cloud_data = { @@ -65,14 +67,17 @@ class UpdateCloudsYaml(object): def _read_clouds(self): try: with open(self._clouds_path) as clouds_file: - self._clouds = yaml.safe_load(clouds_file) + self._config = yaml.safe_load(clouds_file) except IOError: # The user doesn't have a clouds.yaml file. print("The user clouds.yaml file didn't exist.") - self._clouds = {} + if "cache" not in self._config: + # Enable auth (and only auth) caching. Currently caching into the + # file on FS is configured in `_write_clouds` function. + self._config["cache"] = {"auth": True} def _update_clouds(self): - self._clouds.setdefault('clouds', {})[self._cloud] = self._cloud_data + self._config.setdefault('clouds', {})[self._cloud] = self._cloud_data def _write_clouds(self): @@ -81,7 +86,19 @@ class UpdateCloudsYaml(object): os.makedirs(clouds_dir) with open(self._clouds_path, 'w') as clouds_file: - yaml.dump(self._clouds, clouds_file, default_flow_style=False) + yaml.dump(self._config, clouds_file, default_flow_style=False) + + # Enable keyring token caching + keyringrc_dir = os.path.dirname(self._keyringrc_path) + os.makedirs(keyringrc_dir, exist_ok=True) + + # Configure auth caching into the file on FS. We do not bother of any + # expiration since SDK is smart enough to reauth once the token becomes + # invalid. + with open(self._keyringrc_path, 'w') as keyringrc_file: + keyringrc_file.write("[backend]\n") + keyringrc_file.write( + "default-keyring=keyrings.alt.file.PlaintextKeyring\n") def main():