From 210908877c66451ddf102d948905ce1fde879ed6 Mon Sep 17 00:00:00 2001 From: Tze Liang Date: Thu, 22 Jun 2023 07:27:08 +0000 Subject: [PATCH 1/5] feat: add secretmanager info module (#579) --- plugins/modules/gcp_secretmanager_info.py | 198 ++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 plugins/modules/gcp_secretmanager_info.py diff --git a/plugins/modules/gcp_secretmanager_info.py b/plugins/modules/gcp_secretmanager_info.py new file mode 100644 index 00000000..8ca95ee7 --- /dev/null +++ b/plugins/modules/gcp_secretmanager_info.py @@ -0,0 +1,198 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2023, Tze L. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function +import os +import json +from ansible_collections.google.cloud.plugins.module_utils.gcp_utils import navigate_hash, GcpSession, GcpModule, GcpRequest + +__metaclass__ = type + +################################################################################ +# Documentation +################################################################################ + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ["preview"], 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: gcp_secretmanager_info.py +description: +- Gather info for GCP Secret Manager +short_description: Gather info for GCP Secret Manager - List secrets and versions metadata. +author: Tze L. (https://github.com/tl-aiyor) +requirements: +- python >= 2.6 +- requests >= 2.18.4 +- google-auth >= 1.3.0 +options: + project: + description: + - The name of the GCP Project. This is the Project number. + default: environment variable 'GCP_PROJECT' + type: str + auth_kind: + description: + - The type of credential used. + type: str + required: true + choices: + - application + - machineaccount + - serviceaccount + - accesstoken + service_account_contents: + description: + - The contents of a Service Account JSON file, either in a dictionary or as a + JSON string that represents it. + type: jsonarg + service_account_file: + description: + - The path of a Service Account JSON file if serviceaccount is selected as type. + type: path + service_account_email: + description: + - An optional service account email address if machineaccount is selected and + the user does not wish to use the default email. + type: str + access_token: + description: + - An OAuth2 access token if credential type is accesstoken. + type: str + scopes: + description: + - Array of scopes to be used + type: list + elements: str + default: https://www.googleapis.com/auth/cloud-platform + env_type: + description: + - Specifies which Ansible environment you're running this module within. + - This should not be set unless you know what you're doing. + - This only alters the User Agent string for any API requests. + type: str +notes: +- for authentication, you can set service_account_file using the C(GCP_SERVICE_ACCOUNT_FILE) + env variable. +- for authentication, you can set service_account_contents using the C(GCP_SERVICE_ACCOUNT_CONTENTS) + env variable. +- For authentication, you can set service_account_email using the C(GCP_SERVICE_ACCOUNT_EMAIL) + env variable. +- For authentication, you can set access_token using the C(GCP_ACCESS_TOKEN) + env variable. +- For authentication, you can set auth_kind using the C(GCP_AUTH_KIND) env variable. +- For authentication, you can set scopes using the C(GCP_SCOPES) env variable. +- Environment variables values will only be used if the playbook values are not set. +- The I(service_account_email) and I(service_account_file) options are mutually exclusive. +''' + +EXAMPLES = ''' +- name: get list of secrets and the associated versions - secret payload excluded + gcp_secretmanager_info: + project: "{{ project_id }}" + auth_kind: application +''' + +RETURN = ''' +resources: + description: List of resources + returned: always + type: complex + contains: + name: + description: + - The full name of the secret (e.g., projects/111111111111/secrets/mysecret). + returned: success + type: str + etag: + description: + - See reference for more info: https://cloud.google.com/secret-manager/docs/etags + returned: success + type: str + createTime: + description: + - The creation time of the secret + type: str + versions: + description: + - An array consists of list of secret version metadata. + - This does not include + returned: success + type: complex + contains: + name: + description: + - The full name of the secret version (e.g., projects/111111111111/secrets/mysecret/versions/1). + type: str + createTime: + description: + - The creation time of the secret version + type: str + state: + description: + - The state of the version. ENABLED or DISABLED + type: str + etag: + description: + - See reference for more info: https://cloud.google.com/secret-manager/docs/etags + type: str +''' + +def main(): + module = GcpModule(argument_spec=dict( + project=dict(default=os.environ['GCP_PROJECT'], type='str'))) + + if not module.params['scopes']: + module.params['scopes'] = [ + 'https://www.googleapis.com/auth/cloud-platform'] + + secrets_url = "https://secretmanager.googleapis.com/v1/projects/{project}/secrets".format( + **module.params + ) + auth = GcpSession(module, 'secretmanager') + secrets = fetch_list(secrets_url, auth, 'secrets') + results = [] + for secret in secrets: + secret_versions_url = "https://secretmanager.googleapis.com/v1/{name}/versions".format( + **secret + ) + + secret['versions'] = fetch_list(secret_versions_url, auth, 'versions') + results.append(secret) + return_value = {'resources': results} + module.exit_json(**return_value) + +def get_secret_metadata(link, auth): + response = auth.get(link) + return response.json() + +def fetch_list(link, auth, array_name): + return auth.list(link, return_if_object, array_name=array_name) + + +def return_if_object(module, response): + # If not found, return nothing. + if response.status_code == 404: + return None + + # If no content, return nothing. + if response.status_code == 204: + return None + + try: + module.raise_for_status(response) + result = response.json() + except getattr(json.decoder, 'JSONDecodeError', ValueError) as inst: + module.fail_json(msg="Invalid JSON response with error: %s" % inst) + + if navigate_hash(result, ['error', 'errors']): + module.fail_json(msg=navigate_hash(result, ['error', 'errors'])) + + return result + + +if __name__ == "__main__": + main() \ No newline at end of file From 520a814aeaf0c86dd8d1173ea219b8657d8a4af2 Mon Sep 17 00:00:00 2001 From: Tze Date: Sat, 8 Jul 2023 20:20:09 +1000 Subject: [PATCH 2/5] fix: add final newline to satisfy pylint req --- plugins/modules/gcp_secretmanager_info.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/modules/gcp_secretmanager_info.py b/plugins/modules/gcp_secretmanager_info.py index 8ca95ee7..d1f24b49 100644 --- a/plugins/modules/gcp_secretmanager_info.py +++ b/plugins/modules/gcp_secretmanager_info.py @@ -195,4 +195,5 @@ def return_if_object(module, response): if __name__ == "__main__": - main() \ No newline at end of file + main() + From db55e4afb72f00e4ea5152a1e2de55659fb4ecd3 Mon Sep 17 00:00:00 2001 From: Tze Date: Sat, 8 Jul 2023 20:25:15 +1000 Subject: [PATCH 3/5] nit: change author info to gitlab username --- plugins/modules/gcp_secretmanager_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/gcp_secretmanager_info.py b/plugins/modules/gcp_secretmanager_info.py index d1f24b49..40a8aff2 100644 --- a/plugins/modules/gcp_secretmanager_info.py +++ b/plugins/modules/gcp_secretmanager_info.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- # -# Copyright (C) 2023, Tze L. +# Copyright (C) 2023, Tze L. (gitlab.com/tze) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function import os From 8b88a27cdf3f5fa096e9e9a2f53c834b91425568 Mon Sep 17 00:00:00 2001 From: Tze Liang Date: Tue, 11 Jul 2023 01:42:31 +0000 Subject: [PATCH 4/5] fix: trailing whitespaces and updated documented min python req from 2.6 to 2.7 --- plugins/modules/gcp_secretmanager_info.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/modules/gcp_secretmanager_info.py b/plugins/modules/gcp_secretmanager_info.py index 40a8aff2..80726ed5 100644 --- a/plugins/modules/gcp_secretmanager_info.py +++ b/plugins/modules/gcp_secretmanager_info.py @@ -23,9 +23,9 @@ module: gcp_secretmanager_info.py description: - Gather info for GCP Secret Manager short_description: Gather info for GCP Secret Manager - List secrets and versions metadata. -author: Tze L. (https://github.com/tl-aiyor) +author: Tze L. (https://gitlab.com/tze) requirements: -- python >= 2.6 +- python >= 2.7 - requests >= 2.18.4 - google-auth >= 1.3.0 options: @@ -119,12 +119,12 @@ resources: versions: description: - An array consists of list of secret version metadata. - - This does not include + - This does not include returned: success type: complex contains: name: - description: + description: - The full name of the secret version (e.g., projects/111111111111/secrets/mysecret/versions/1). type: str createTime: @@ -141,9 +141,10 @@ resources: type: str ''' + def main(): module = GcpModule(argument_spec=dict( - project=dict(default=os.environ['GCP_PROJECT'], type='str'))) + project=dict(default=os.environ.get('GCP_PROJECT'), type='str'))) if not module.params['scopes']: module.params['scopes'] = [ @@ -157,7 +158,7 @@ def main(): results = [] for secret in secrets: secret_versions_url = "https://secretmanager.googleapis.com/v1/{name}/versions".format( - **secret + **secret ) secret['versions'] = fetch_list(secret_versions_url, auth, 'versions') @@ -165,10 +166,12 @@ def main(): return_value = {'resources': results} module.exit_json(**return_value) + def get_secret_metadata(link, auth): response = auth.get(link) return response.json() + def fetch_list(link, auth, array_name): return auth.list(link, return_if_object, array_name=array_name) @@ -196,4 +199,3 @@ def return_if_object(module, response): if __name__ == "__main__": main() - From bca101a4509c63a57da5ea578db4c72dbdf0734f Mon Sep 17 00:00:00 2001 From: Tze Liang Date: Tue, 11 Jul 2023 02:22:53 +0000 Subject: [PATCH 5/5] fix: remove colon in return doc etag description --- plugins/modules/gcp_secretmanager_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/gcp_secretmanager_info.py b/plugins/modules/gcp_secretmanager_info.py index 80726ed5..eafc0815 100644 --- a/plugins/modules/gcp_secretmanager_info.py +++ b/plugins/modules/gcp_secretmanager_info.py @@ -109,7 +109,7 @@ resources: type: str etag: description: - - See reference for more info: https://cloud.google.com/secret-manager/docs/etags + - See reference for more info. [Secret Manager etags](U(https://cloud.google.com/secret-manager/docs/etags)). returned: success type: str createTime: @@ -137,7 +137,7 @@ resources: type: str etag: description: - - See reference for more info: https://cloud.google.com/secret-manager/docs/etags + - See reference for more info. [Secret Manager etags](U(https://cloud.google.com/secret-manager/docs/etags)). type: str '''