From bea7981bdb1fc1128cde4a5072adafcd7490898d Mon Sep 17 00:00:00 2001 From: Ross Scroggs Date: Wed, 1 Jan 2020 05:22:57 -0800 Subject: [PATCH] When rotating an sakey, only delete the existing key, no others (#1064) * When rotating an sakey, only delete the existing key, no others * Make sakeys retention explicit * Fix bug * Rotate, local key generation default * Allow explicit specification of retain_none in rotate sakeys It is still the default value. --- src/GamCommands.txt | 4 ++-- src/gam.py | 31 +++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/GamCommands.txt b/src/GamCommands.txt index eaf0dfbe..3933e9a3 100644 --- a/src/GamCommands.txt +++ b/src/GamCommands.txt @@ -838,8 +838,8 @@ gam delete project [] [gam||(filter )] gam show projects [] [all|gam||(filter )] gam print projects [] [all|gam||(filter )] [todrive] -gam create sakey|sakeys [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)] -gam rotate sakey|sakeys [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)] +gam rotate sakey|sakeys [retain_none|retain_existing|replace_current] + [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)] gam delete sakey|sakeys + [doit] gam show sakey|sakeys [all|system|user] diff --git a/src/gam.py b/src/gam.py index a3cbeee1..fb512cac 100755 --- a/src/gam.py +++ b/src/gam.py @@ -7870,10 +7870,11 @@ def doShowServiceAccountKeys(): key['current'] = key['name'] == currentPrivateKeyId print_json(None, keys) -def doCreateRotateServiceAccountKeys(rotateCmd): +def doRotateServiceAccountKeys(): iam = buildGAPIServiceObject('iam', None) - local_key_size = 0 + local_key_size = 2048 body = {} + mode = 'retainnone' i = 3 while i < len(sys.argv): myarg = sys.argv[i].lower().replace('_', '') @@ -7889,13 +7890,17 @@ def doCreateRotateServiceAccountKeys(rotateCmd): if local_key_size not in [1024, 2048, 4096]: controlflow.system_error_exit(3, 'localkeysize must be 1024, 2048 or 4096. 1024 is weak and dangerous. 2048 is recommended. 4096 is slow.') i += 2 + elif myarg in ['retainnone', 'retainexisting', 'replacecurrent']: + mode = myarg + i += 1 else: - controlflow.system_error_exit(3, '%s is not a valid argument to "gam %s sakey"' % (myarg, ['create', 'rotate'][rotateCmd])) + controlflow.system_error_exit(3, '%s is not a valid argument to "gam rotate sakeys"' % myarg) clientId = GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] + currentPrivateKeyId = GM_Globals[GM_OAUTH2SERVICE_JSON_DATA]['private_key_id'] name = 'projects/-/serviceAccounts/%s' % clientId - keys = gapi.get_items(iam.projects().serviceAccounts().keys(), 'list', 'keys', - name=name, keyTypes='USER_MANAGED') - print(' Service Account {0} has {1} existing key(s)'.format(clientId, len(keys))) + if mode != 'retainexisting': + keys = gapi.get_items(iam.projects().serviceAccounts().keys(), 'list', 'keys', + name=name, keyTypes='USER_MANAGED') if local_key_size: private_key, publicKeyData = _generatePrivateKeyAndPublicCert(name, local_key_size) print(' Uploading new public certificate to Google...') @@ -7909,10 +7914,16 @@ def doCreateRotateServiceAccountKeys(rotateCmd): private_key_id = result['name'].rsplit('/', 1)[-1] fileutils.write_file(GC_Values[GC_OAUTH2SERVICE_JSON], oauth2service_data, continue_on_error=False) print(' Wrote new private key {0} to {1}'.format(private_key_id, GC_Values[GC_OAUTH2SERVICE_JSON])) - if rotateCmd: + if mode != 'retainexisting': + count = len(keys) if mode == 'retainnone' else 1 + print(' Revoking {0} existing key(s) for Service Account {1}'.format(count, clientId)) for key in keys: - print(' Revoking existing key %s for service account' % key['name'].rsplit('/', 1)[-1]) - gapi.call(iam.projects().serviceAccounts().keys(), 'delete', name=key['name']) + keyName = key['name'].rsplit('/', 1)[-1] + if mode == 'retainnone' or keyName == currentPrivateKeyId: + print(' Revoking existing key %s for service account' % keyName) + gapi.call(iam.projects().serviceAccounts().keys(), 'delete', name=key['name']) + if mode != 'retainnone': + break def doDeleteServiceAccountKeys(): iam = buildGAPIServiceObject('iam', None) @@ -14379,7 +14390,7 @@ def ProcessGAMCommand(args): elif command == 'rotate': argument = sys.argv[2].lower() if argument in ['sakey', 'sakeys']: - doCreateRotateServiceAccountKeys(True) + doRotateServiceAccountKeys() else: controlflow.system_error_exit(2, '%s is not a valid argument for "gam rotate"' % argument) sys.exit(0)