From 8311235d7552a727d36376bd404aa0f6b9b2e8db Mon Sep 17 00:00:00 2001 From: Dipesh Rathod <111430850+dipeshrath@users.noreply.github.com> Date: Wed, 21 May 2025 22:00:36 +0530 Subject: [PATCH 1/2] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0dcf75f..26944ce 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,4 @@ Licensed under the Universal Permissive License (UPL), Version 1.0. See [LICENSE](LICENSE) for more details. -ORACLE AND ITS AFFILIATES DO NOT PROVIDE ANY WARRANTY WHATSOEVER, EXPRESS OR IMPLIED, FOR ANY SOFTWARE, MATERIAL OR CONTENT OF ANY KIND CONTAINED OR PRODUCED WITHIN THIS REPOSITORY, AND IN PARTICULAR SPECIFICALLY DISCLAIM ANY AND ALL IMPLIED WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. FURTHERMORE, ORACLE AND ITS AFFILIATES DO NOT REPRESENT THAT ANY CUSTOMARY SECURITY REVIEW HAS BEEN PERFORMED WITH RESPECT TO ANY SOFTWARE, MATERIAL OR CONTENT CONTAINED OR PRODUCED WITHIN THIS REPOSITORY. IN ADDITION, AND WITHOUT LIMITING THE FOREGOING, THIRD PARTIES MAY HAVE POSTED SOFTWARE, MATERIAL OR CONTENT TO THIS REPOSITORY WITHOUT ANY REVIEW. USE AT YOUR OWN RISK. \ No newline at end of file +ORACLE AND ITS AFFILIATES DO NOT PROVIDE ANY WARRANTY WHATSOEVER, EXPRESS OR IMPLIED, FOR ANY SOFTWARE, MATERIAL OR CONTENT OF ANY KIND CONTAINED OR PRODUCED WITHIN THIS REPOSITORY, AND IN PARTICULAR SPECIFICALLY DISCLAIM ANY AND ALL IMPLIED WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. FURTHERMORE, ORACLE AND ITS AFFILIATES DO NOT REPRESENT THAT ANY CUSTOMARY SECURITY REVIEW HAS BEEN PERFORMED WITH RESPECT TO ANY SOFTWARE, MATERIAL OR CONTENT CONTAINED OR PRODUCED WITHIN THIS REPOSITORY. IN ADDITION, AND WITHOUT LIMITING THE FOREGOING, THIRD PARTIES MAY HAVE POSTED SOFTWARE, MATERIAL OR CONTENT TO THIS REPOSITORY WITHOUT ANY REVIEW. USE AT YOUR OWN RISK.. From 2c3cbab312fd9d13ef8ae28a7973a7c83d6a9131 Mon Sep 17 00:00:00 2001 From: bhlohumi Date: Wed, 4 Jun 2025 19:25:55 +0530 Subject: [PATCH 2/2] added support for console password --- iam-credential-expiry-notification/func.py | 57 +++++++++++++------- iam-credential-expiry-notification/func.yaml | 3 +- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/iam-credential-expiry-notification/func.py b/iam-credential-expiry-notification/func.py index bc0fa6c..d070145 100644 --- a/iam-credential-expiry-notification/func.py +++ b/iam-credential-expiry-notification/func.py @@ -10,6 +10,8 @@ from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase +logger = logging.getLogger() +logger.setLevel(logging.INFO) # Get Resource Principal Credentials signer = oci.auth.signers.get_resource_principals_signer() @@ -139,10 +141,15 @@ def send_email(subject,secret_client,cfg,BODY_HTML,report_data,recipient,report_ #server.send_message(msg) server.close() -def get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,resource,resource_id,type,cfg,except_user,report_data): +def get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,resource,resource_id,type,cfg,except_user,report_data,enable_delete_on_expiry): + report_date = str(datetime.datetime.strftime(datetime.datetime.now(), "%Y-%b-%d")) identifier = resource_id - created_time = datetime.datetime.strptime((resource.meta).created, "%Y-%m-%dT%H:%M:%S.%fZ") + if resource_id == "console_password": + created_time = datetime.datetime.strptime(resource, "%Y-%m-%dT%H:%M:%S.%fZ") + + else: + created_time = datetime.datetime.strptime((resource.meta).created, "%Y-%m-%dT%H:%M:%S.%fZ") warning_date = created_time + datetime.timedelta(days=int(cfg["warning_in_days"])) critical_date = created_time + datetime.timedelta(days=int(cfg["critical_in_days"])) expiry_date = created_time + datetime.timedelta(days=int(cfg["expiry_in_days"])) @@ -153,15 +160,16 @@ def get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check severity = "Expired" # Delete the credential - user_to_check = str(user_name)+"@"+str(domain_name) - if user_to_check.lower() not in except_user: - logging.getLogger().info(f'Deleting {resource.id} {type} for {user_name} in {domain_name} domain') - if type == "api_key": - identity_domains_client.delete_api_key(resource.id) - elif type == "auth_token": - identity_domains_client.delete_auth_token(resource.id) - elif type == "customer_secret_key": - identity_domains_client.delete_customer_secret_key(resource.id) + if enable_delete_on_expiry == "true": + user_to_check = str(user_name)+"@"+str(domain_name) + if user_to_check.lower() not in except_user: + logging.getLogger().info(f'Deleting {resource.id} {type} for {user_name} in {domain_name} domain') + if type == "api_key": + identity_domains_client.delete_api_key(resource.id) + elif type == "auth_token": + identity_domains_client.delete_auth_token(resource.id) + elif type == "customer_secret_key": + identity_domains_client.delete_customer_secret_key(resource.id) elif critical_date < datetime.datetime.now(): credential_check = False @@ -186,6 +194,7 @@ def handler(ctx, data: io.BytesIO=None): cfg = ctx.Config() domain_ids = cfg["domain_ocids"] except_user_input = cfg["exception_users"].split(",") + enable_delete_on_expiry = cfg['enable_delete_on_expiry'].lower() except_user = [] for item in except_user_input: except_user.append(str(item).lower()) @@ -218,7 +227,7 @@ def handler(ctx, data: io.BytesIO=None): while list_users_response.has_next_page: list_users_response = identity_domains_client.list_users(page=list_users_response.next_page) users.extend(list_users_response.data.resources) - logging.getLogger().info('fetched ' + str(len(users)) + ' users') + logging.getLogger().info('fetched ' + str(len(users)) + ' users'+ ' for domain : '+domain_name) for user in users: user_ocid = user.ocid user_name = user.user_name @@ -263,18 +272,28 @@ def handler(ctx, data: io.BytesIO=None): # get list of api keys for user list_api_keys_response = identity_domains_client.list_api_keys(filter=f'user.ocid eq \"{user_ocid}\"').data for api_key in list_api_keys_response.resources: - BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,api_key,api_key.fingerprint,"api_key",cfg,except_user,report_data) + BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,api_key,api_key.fingerprint,"api_key",cfg,except_user,report_data,enable_delete_on_expiry) list_auth_tokens_response = identity_domains_client.list_auth_tokens(filter=f'user.ocid eq \"{user_ocid}\"').data for auth_token in list_auth_tokens_response.resources: - BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,auth_token,auth_token.description,"auth_token",cfg,except_user,report_data) + BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,auth_token,auth_token.description,"auth_token",cfg,except_user,report_data,enable_delete_on_expiry) list_customer_secret_keys_response = identity_domains_client.list_customer_secret_keys(filter=f'user.ocid eq \"{user_ocid}\"').data for csk in list_customer_secret_keys_response.resources: - BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,csk,csk.access_key,"customer_secret_key",cfg,except_user,report_data) + BODY_HTML,credential_check,report_data = get_body_html(identity_domains_client,BODY_HTML,domain_name,credential_check,user_name,user_email,csk,csk.access_key,"customer_secret_key",cfg,except_user,report_data,enable_delete_on_expiry) + + password_info = identity_domains_client.search_users( + user_search_request=oci.identity_domains.models.UserSearchRequest( + schemas=["urn:ietf:params:scim:api:messages:2.0:SearchRequest"], + attribute_sets=["all"], + filter=f'ocid eq \"{user_ocid}\"' + ), + ).data.resources + pswd_last_modified = password_info[0].urn_ietf_params_scim_schemas_oracle_idcs_extension_password_state_user.last_successful_set_date + BODY_HTML, credential_check, report_data = get_body_html(identity_domains_client, BODY_HTML,domain_name, credential_check, user_name, user_email, pswd_last_modified, "console_password","console_password", cfg, except_user,report_data,enable_delete_on_expiry) - if credential_check: - logging.getLogger().info('all credentials for user ' + user_name + ' are healthy') + #if credential_check: + # logging.getLogger().info('all credentials for user ' + user_name + ' are healthy') if credential_check : continue @@ -298,7 +317,7 @@ def handler(ctx, data: io.BytesIO=None): """ #recipient = str(user_email).split(",") recipient = str(user_email) - logging.getLogger().info('sending email') + #logging.getLogger().info('sending email') send_email(SUBJECT,secret_client,cfg,BODY_HTML,"",recipient) if report_requested : @@ -325,4 +344,4 @@ def handler(ctx, data: io.BytesIO=None): except (Exception, ValueError) as ex: logging.getLogger().info('error parsing json payload: ' + str(ex)) - return response.Response(ctx, response_data=json.dumps({"message": "success"}),headers={"Content-Type": "application/json"}) + return response.Response(ctx, response_data=json.dumps({"message": "success"}),headers={"Content-Type": "application/json"}) \ No newline at end of file diff --git a/iam-credential-expiry-notification/func.yaml b/iam-credential-expiry-notification/func.yaml index a27ad29..692b565 100644 --- a/iam-credential-expiry-notification/func.yaml +++ b/iam-credential-expiry-notification/func.yaml @@ -5,7 +5,7 @@ runtime: python build_image: fnproject/python:3.9-dev run_image: fnproject/python:3.9 entrypoint: /python/bin/fdk /function/func.py handler -memory: 256 +memory: 1024 config: critical_in_days: "90" domain_ocids: ocid1.domain.oc1..aaaaaaaanp @@ -21,3 +21,4 @@ config: smtpuser: ocid1.user.oc1..aaaaaaaa warning_in_days: "30" weekly_report_day: friday + enable_delete_on_expiry: "false"