def create_account(payer_id, role, email, name, payer_role): try: orgs_client = get_creds("organizations", Id=payer_id, role=role) new_account = orgs_client.create_account( Email=email, AccountName=name, RoleName=payer_role, IamUserAccessToBilling="ALLOW") my_logging("New Account {} creation: {}".format(email, new_account)) return new_account except botocore.exceptions.ClientError as e: my_logging("Could not create account: {}".format(e), "error") return e # ============================================================================# # CALLS FUNCTION ON ROOT ACCOUNT TO CREATE CROSSACCOUNTROLE ON LINKED ACCOUNT # # ============================================================================# # ============================================================================# # ASSUMES NEW CROSS ACCOUNT ROLE AND DELETES OLD CROSS ROLE FROM ROOT ACCOUNT # # ============================================================================# # ============================================================================# # SENDS MESSAGE TO THE ACCOUNT SETUP CONTROLLER QUEUE # # ============================================================================# # ============================================================================# # MAIN FUNCTION # # ============================================================================#
def list_aws_regions(): try: client = get_creds("ec2") return client.describe_regions()["Regions"] except botocore.exceptions.ClientError as e: my_logging("Could not list regions: {}".format(e), "error") return e
def send_to_s3(bucket_name, file_name, file): try: client = get_creds("s3") return client.put_object(Body=file, Bucket=bucket_name, Key=file_name) except botocore.exceptions.ClientError as e: my_logging("Could not put object on s3: {}".format(e), "error") return e
def get_inline_policies(**kwargs): # List inline policies inline_policies = list_resources( iam_client, "PolicyNames", "list_{}_policies".format(resource_key.lower()), "Marker", **kwargs) my_logging("InlinePolicies: {}".format(inline_policies)) return inline_policies
def get_sg_details(acc_Id, Region): try: client = get_creds("ec2", Id=acc_Id, region=Region) return list_resources(client, "SecurityGroups", "describe_security_groups", "NextToken") except botocore.exceptions.ClientError as e: my_logging("Could not get security groups: {}".format(e), "error") return e
def get_attached_policies(**kwargs): # List attached policies attached_policies = list_resources( iam_client, "AttachedPolicies", "list_attached_{}_policies".format(resource_key.lower()), "Marker", **kwargs) my_logging("AttachedPolicies: {}".format(attached_policies)) return attached_policies
def describe_resources(service, acc_Id, Region, resp_item, action, token): my_logging("Describing {} on region {}".format(service, Region)) try: client = get_creds(service, Id=acc_Id, region=Region) return list_resources(client, resp_item, action, token) except botocore.exceptions.ClientError as e: my_logging("Could not list resources: {}".format(e), "error") return e
def describe_through_regions(Id, regions, resource, resp_item, action, token): resources = {} for region in regions: my_logging("Describing {} for region {}".format(resource, region)) region_resource = describe_resources(resource, Id, region["RegionName"], resp_item, action, token) resources[region["RegionName"]] = region_resource my_logging("Done! {} described in all regions".format(resource)) return resources
def create_idp(idp_name,saml_doc): # Creates IDP on account try: create = iam_client.create_saml_provider( SAMLMetadataDocument=str(saml_doc), Name=idp_name ) my_logging("IDP created: {}".format(create)) return create except botocore.exceptions.ClientError as e: my_logging("Could not create IDP: {}".format(e)) return e
def vars_by_resource(resource): if resource == "ec2": my_logging("Setting variables for ec2") response_item = "Reservations" desc_action = "describe_instances" token_name = "NextToken" sg_type = "GroupNames" elif resource == "rds": my_logging("Setting variables for rds") response_item = "DBInstances" desc_action = "describe_db_instances" token_name = "Marker" sg_type = "DBSecurityGroupName" return response_item, desc_action, token_name, sg_type
def update_idp(Id,idp_name,saml_doc): # Sets variable with ARN for IDP idp_arn = "arn:aws:iam::{}:saml-provider/{}".format( Id, idp_name ) try: # Updates Saml Document update = iam_client.update_saml_provider( SAMLMetadataDocument=str(saml_doc), SAMLProviderArn=idp_arn ) my_logging("IDP updated: {}".format(update)) return update except botocore.exceptions.ClientError as e: my_logging("Could not update IDP: {}".format(e)) return e
def update_item(Id, expression, values): try: client = get_creds("dynamodb") response = client.update_item(TableName=environ["accounts_table"], Key={"Id": { "S": Id }}, ReturnValues="ALL_NEW", ReturnConsumedCapacity="TOTAL", ReturnItemCollectionMetrics="SIZE", UpdateExpression=expression, ExpressionAttributeValues={":v": values}) my_logging("Items recorded: {}".format(response)) return response except botocore.exceptions.ClientError as e: my_logging("Could not record items: {}".format(e), "error") return e
def lambda_handler(event, context): my_event = { "Id": "826839167791", "IamResourceType": "Group", "IamResourceName": "teste" } # Declares global variables used by other functions global resource_key resource_key = my_event["IamResourceType"] global resource_name resource_name = my_event["IamResourceName"] global iam_client iam_client = get_creds("iam", Id=my_event["Id"]) global dynamodb_client dynamodb_client = get_creds("dynamodb") # Get data about desired IAM Resource item = dynamodb_client.get_item(TableName=environ["iam_resource_table"], Key={ "ResourceName": { "S": resource_name }, "ResourceType": { "S": resource_key } }, ReturnConsumedCapacity="TOTAL", ConsistentRead=True) my_logging("Details about {} {}: {}".format(resource_key, resource_name, item)) # Enforces resource creation on account resource = create_iam_resource(**item["Item"]) my_logging("Enforce Resource: {}".format(resource)) # Enforces policies on resource policies = apply_policies(**item["Item"]) my_logging("Enforce Policies: {}".format(policies)) # Sends message to queue of the microservice that attaches User to Groups if resource_key == "User" and "Groups" in item["Item"]: my_message = send_sqs({ "Id": my_event["Id"], "User": item["Item"] }, environ["attach_user_to_groups_queue"]) my_logging( "Message to Attach User {} to Groups on account {} sent: {}". format(resource_name, my_event["Id"], my_message))
def remove_secondary_data(instances, keys): my_logging("Undesired Keys to remove whether are found: {}".format(keys)) my_logging("Instances passed to the function: {}".format(instances)) for instance in instances: for key in keys: instance.pop(key, None) my_logging("Instances after undesired keys removed: {}".format(instances)) return instances
def update_policy_ver(policy, policy_data, versions): for ver in versions: # Find the version in use (default) # and compares it with the template # If it is different, updates it if ver["IsDefaultVersion"]: # Get policy default version details ver_detail = iam_client.get_policy_version( PolicyArn=policy["Arn"], VersionId=ver["VersionId"])["PolicyVersion"] # Sets documents in variables to comparison # (It could done be directly on if statement but # this way is easier to read) ver_doc = sort_multilevel_obj(ver_detail["Document"]) my_logging("Document Version: {}".format(ver_doc)) templ_doc = sort_multilevel_obj(loads( policy_data["Document"]["S"])) my_logging("Document Template: {}".format(templ_doc)) # Compares current policy with the one should exist # If different, updates it if ver_doc != templ_doc: # If there are 5 versions already # deletes de oldest one if len(versions) >= 5: ver_id = "v1" # default version to delete from datetime import datetime from datetime import timezone comp_date = datetime.now(timezone.utc) # comparison date # Finds the oldest version for v in versions: if v["CreateDate"] < comp_date: comp_date = v["CreateDate"] ver_id = v["VersionId"] # Deletes the oldest version iam_client.delete_policy_version(PolicyArn=policy["Arn"], VersionId=str(ver_id)) # Updates policy with new version # Sets new version as default new_version = iam_client.create_policy_version( PolicyArn=policy["Arn"], PolicyDocument=str(policy_data["Document"]["S"]), SetAsDefault=True) my_logging("Policy {} Updated: {}".format( policy["PolicyName"], new_version)) return True
def get_managed_policies(client): my_logging("Describing managed policies") # Returns a List of Dicts with "PolicyName", "PolicyId", "Arn", "Path", # "DefaultVersionId", "AttachmentCount", "PermissionsBoundaryUsageCount", # "IsAttachable", "Description", "CreateDate", "UpdateDate" try: policies = list_resources(client, "Policies", "list_policies", "Marker") my_logging("Managed Policies: {}".format(policies)) return policies except botocore.exceptions.ClientError as e: my_logging("Could not list Managed Policies: {}".format(e), "error") return e
def describe_iam_resource(client, resource_type, action, token): my_logging("Describing {}".format(resource_type)) # Returns a List of Dicts with "Path", "UserName", "UserId", "Arn", "CreateDate", # "PermissionsBoundary", "Tags", # "PasswordLasUsed", # "AssumeRolePolicyDocument", "Description", "MaxSessionDuration" try: resources = list_resources(client, resource_type, action, token) my_logging("{} retrieved: {}".format(resource_type, resources)) return resources except botocore.exceptions.ClientError as e: my_logging("Could not list {}: {}".format(resource_type, e), "error") return e
def get_policies_on_resource(client, resource, action, token, key_name): my_logging("Describing {} policies for {}".format(policy_type, resource)) # When "inline", returns a List of Strings (policy names) # When "attached" returns a List of Dicts with "PolicyName" and "PolicyArn" try: kwargs = {key_name: resource} item = "AttachedPolicies" if "attached" in action else item = "PolicyNames" policies = list_resources(client, item, action, token, **kwargs) my_logging("Policies for {}: {}".format(resource, policies)) return policies except botocore.exceptions.ClientError as e: my_logging("Could not list {}: {}".format(resource, e), "error") return e
def create_dynamo_structure_iam(resource, Id): my_logging("Recording IAM Structure on table for account {}".format(Id)) try: # Parameters to create structure on DynamoDB table update_parameters = { "SET Services = if_not_exists(Services, :v)": { "M": {} }, "SET Services.IAM = if_not_exists(Services.IAM, :v)": { "M": {} }, "SET Services.IAM.{}_list = :v".format(resource): { "L": [] } } my_logging("Parameters: {}".format(update_parameters)) except Exception as e: my_logging("Error on setting update_parameters: {}".format(e)) # Loop to create structure on table where resources will be saved for expression, values in update_parameters.items(): update = update_item(Id, expression, values) my_logging(update)
def main_function(event): # EVENT SAMPLE # {"resource":"ec2|rds","Id":"123456789012","report":"main|full"} # Retrives current regions on AWS regions = list_aws_regions() my_logging("Regions: {}".format(regions)) # Sets variables according to which resource is going to be described # EC2 or RDS resp_item, desc_action, token_name, sg_type = vars_by_resource( event["resource"]) # Loops through regions describing resources resources = describe_through_regions(event["Id"], regions, event["resource"], resp_item, desc_action, token_name) # If report generated should only contain main info, removes the rest if event["report"] == "main": keys = keys_to_remove() for region in resources.values(): if event["resource"] == "rds": for item in region: remove_secondary_data(item, keys) elif event["resource"] == "ec2": for item in region: remove_secondary_data(item["Instances"], keys) # Get Security Groups created on regions my_logging("Retrieving Security groups from account") security_groups = {} for region in regions: security_groups[region["RegionName"]] = get_sg_details( event["Id"], region["RegionName"]) my_logging("SGs for {}: {}".format( region, security_groups[region["RegionName"]])) my_logging("Security Groups: {}".format(security_groups)) # Saves data collected into a Json file on S3 my_logging("Sending json to S3") file = {"Resources": resources, "SecGroups": security_groups} my_logging("File to be uploaded: {}".format(file)) send = send_to_s3( environ["bucket_resources"], "{}/{}-{}.json".format(event["Id"], now(), event["resource"]), dumps(file, default=json_serial)) my_logging("file sent: {}".format(send))
def retrieve_templ_policies(resource): my_logging("Retrieving template policies for resource {}".format(resource))
def create_iam_resource(**resource): # Get information about resource when created get_resource = my_aws_methods(iam_client, "get_{}".format(resource_key.lower()), **my_kwargs()) # Verifies if resource was retrivied or did not exist if get_resource == "NoSuchEntity": resource_params = my_kwargs() # If the resource is a Role # adds more parameters to kwargs if resource_key == "Role": resource_params["AssumeRolePolicyDocument"] = str( resource["AssumeRolePolicy"]["S"]) resource_params["Description"] = resource["Description"]["S"] if "MaxSession" in resource: resource_params["MaxSessionDuration"] = int( resource["MaxSession"]["N"]) my_logging( "resource_params updated: {}".format(resource_params)) # Creates resource create_resource = my_aws_methods( iam_client, "create_{}".format(resource_key.lower()), **resource_params) return my_logging({"status": "new", "resource": create_resource}) else: # If resource is a role # and description is incorrect, updates it if "Description" in resource and \ get_resource["Role"]["Description"] != resource["Description"]["S"]: description = iam_client.update_role( RoleName=resource_name, Description=resource["Description"]["S"]) my_logging("Description updated: {}".format(description)) get_resource["Role"]["Description"] = resource["Description"]["S"] # If resource is a role, # and max session duration is incorrect, updates it if "MaxSession" in resource and \ get_resource["Role"]["MaxSessionDuration"] != resource["MaxSession"]["N"]: max_session = iam_client.update_role( RoleName=resource_name, MaxSessionDuration=int(resource["MaxSession"]["N"])) my_logging("Session Duration updated: {}".format(max_session)) get_resource["Role"]["MaxSessionDuration"] = resource[ "MaxSession"]["N"] # If resource is a role, # updates assume-role-policy-document when necessary if "AssumeRolePolicy" in resource and \ sort_multilevel_obj(get_resource["Role"]["AssumeRolePolicyDocument"]) != sort_multilevel_obj(loads(resource["AssumeRolePolicy"]["S"])): update_assume_role = iam_client.update_assume_role_policy( RoleName=resource_name, PolicyDocument=str(resource["AssumeRolePolicy"]["S"])) my_logging("Assume Policy updated: {}".format(update_assume_role)) get_resource["Role"]["AssumeRolePolicyDocument"] = resource[ "AssumeRolePolicy"]["S"] message = {"status": "existent", "resource": get_resource} my_logging(message) return message
def apply_policies(**resource): kwargs = my_kwargs() # List inline policies inline_policies = get_inline_policies(**kwargs) # List attached policies attached_policies = get_attached_policies(**kwargs) # List managed policies maintained by customer on account managed_policies = list_resources(iam_client, "Policies", "list_policies", "Marker", Scope="Local") my_logging("ManagedPolicies: {}".format(managed_policies)) # Get the list of managed policy names on account managed_policy_names = [] for i in managed_policies: managed_policy_names.append(i["PolicyName"]) my_logging("ManagedPoliciesNames: {}".format(managed_policy_names)) # Get the names of the inline policies that shoud exist on resource templ_inline_policies = [] templ_inline_policy_names = [] if "InlinePolicies" in resource: templ_inline_policies.extend(resource["InlinePolicies"]["L"]) for i in templ_inline_policies: templ_inline_policy_names.append(i["M"]["Name"]["S"]) my_logging("TemplateInlineNames: {}".format(templ_inline_policy_names)) # Get the names of the managed policies that shoud be attached on resource templ_attach_policy_names = [] if "ManagedPolicies" in resource: for i in resource["ManagedPolicies"]["L"]: templ_attach_policy_names.append(i["S"]) my_logging( "TemplateAttachedNames: {}".format(templ_attach_policy_names)) ### Compares inline policies with the ones should exist ### # if inline policy should not exist, deletes it for item in inline_policies: if item.lower() not in map(str.lower, templ_inline_policy_names): delete_params = my_kwargs() delete_params["PolicyName"] = item delete_inline = my_aws_methods( iam_client, "delete_{}_policy".format(resource_key.lower()), **delete_params) my_logging("Delete Inline Policy: {}".format(delete_inline)) # if inline policy does not exists, creates it for item in templ_inline_policies: if item["M"]["Name"]["S"].lower() not in map(str.lower, inline_policies): create_params = my_kwargs() create_params["PolicyName"] = item["M"]["Name"]["S"] create_params["PolicyDocument"] = item["M"]["Document"]["S"] create_inline = my_aws_methods( iam_client, "put_{}_policy".format(resource_key.lower()), **create_params) my_logging("Create Inline Policy: {}".format(create_inline)) # Verifies if inline policy exists but is outdated and updates it else: get_params = my_kwargs() get_params["PolicyName"] = item["M"]["Name"]["S"] get_inline = my_aws_methods( iam_client, "get_{}_policy".format(resource_key.lower()), **get_params) my_logging("InlinePolicy {} Details: {}".format( item["M"]["Name"]["S"], get_inline)) # current_policy = get_inline["PolicyDocument"] current_policy = sort_multilevel_obj(get_inline["PolicyDocument"]) my_logging("Current Policy: {}".format(current_policy)) template = sort_multilevel_obj(loads(item["M"]["Document"]["S"])) my_logging("Template Policy: {}".format(template)) # Compares policies: Current vs Template # If they are different, updates with template version if current_policy != template: update_params = my_kwargs() update_params["PolicyName"] = item["M"]["Name"]["S"] update_params["PolicyDocument"] = item["M"]["Document"]["S"] update_inline = my_aws_methods( iam_client, "put_{}_policy".format(resource_key.lower()), **update_params) my_logging("Update Inline Policy {}: {}".format( item["M"]["Name"]["S"], update_inline)) ### Compares managed policies with the ones should exist ### # if managed policy should not exist, deletes it for item in attached_policies: if item["PolicyName"].lower() not in map(str.lower, templ_attach_policy_names): detach_params = my_kwargs() detach_params["PolicyArn"] = item["PolicyArn"] detach_policy = my_aws_methods( iam_client, "detach_{}_policy".format(resource_key.lower()), **detach_params) my_logging("Dettach Policy {}: {}".format(item["PolicyName"], detach_policy)) for item in templ_attach_policy_names: # Retrieves data about the policy on dynamodb policy_data = dynamodb_client.get_item( TableName=environ["iam_managed_policies_table"], Key={"PolicyName": { "S": item }}, ReturnConsumedCapacity="TOTAL", ConsistentRead=True) policy_data = policy_data["Item"] my_logging("Details about the Policy {}: {}".format(item, policy_data)) # Verifies whether is an AWS managed or Local managed policy # If has a Document attached on Dynamo, # Than it is Local (Maintained by customer) if "Document" in policy_data: my_logging("{} is a Customer Managed Policy".format( policy_data["PolicyName"]["S"])) # if managed policy does not exists, creates it if item.lower() not in map(str.lower, managed_policy_names): my_logging("Policy {} does not exist on account yet".format( policy_data["PolicyName"]["S"])) policy = iam_client.create_policy( PolicyName=policy_data["PolicyName"]["S"], PolicyDocument=policy_data["Document"]["S"], Description=policy_data["Description"]["S"])["Policy"] my_logging("Policy {} Created on account: {}".format( policy_data["PolicyName"]["S"], policy)) # Adds Arn of new policy to PolicyData to be Attached policy_data["Arn"] = {"S": policy["Arn"]} # Verifies if managed policy exists but is outdated else: for i in managed_policies: if i["PolicyName"].lower() == item.lower(): # Adds Arn of existent policy to PolicyData # To be Attached later policy_data["Arn"] = {"S": i["Arn"]} # List Policy Versions versions = list_resources(iam_client, "Versions", "list_policy_versions", "Marker", PolicyArn=i["Arn"]) my_logging("Versions for policy {}: {}".format( i["PolicyName"], versions)) # Verifies if policy needs to be updated update_policy_ver(i, policy_data, versions) # Verifies if managed policy (AWS or local) is attached to resource already_attached = False for i in attached_policies: if i["PolicyArn"] == policy_data["Arn"]: already_attached = True # If Policy is not attached yet, attaches it if already_attached == False: attach_params = my_kwargs() attach_params["PolicyArn"] = policy_data["Arn"]["S"] attach_to_resource = my_aws_methods( iam_client, "attach_{}_policy".format(resource_key.lower()), **attach_params) my_logging("Policy {} Attached: {}".format(item, attach_to_resource)) else: my_logging("Policy {} already attached".format(i["PolicyName"])) # Get inline and attached policies on resource again to return final state final_policies = [] # List inline policies final_inline = get_inline_policies(**my_kwargs()) final_policies.append({"inline": final_inline}) # List attached policies final_attached = get_attached_policies(**my_kwargs()) final_policies.append({"attached": final_attached}) return "Policies Enforced Successfully: {}".format(final_policies)
def main_function(event): # Variables resource = literal_eval(record["body"])["resource"] resource_name_tag = literal_eval(record["body"])["resource_name_tag"] token_name = literal_eval(record["body"])["token_name"] account = literal_eval(record["body"])["account"] my_logging("MessageId {} for account {}".format(record["messageId"], account["Id"])) # Assumes linked account role with IAM service my_logging("Setting up IAM Service...") iam_client = get_creds("iam", Id=account["Id"]) # List Selected Resource on account resource_list = list_resources( iam_client, resource, literal_eval(record["body"])["action_list_resource"], token_name) create_dynamo_structure_iam(resource, account["Id"]) # Iterates through resource listing policies my_logging("Analysing %s one by one..." % resource) for item in resource_list: my_logging(item) item["Policies"] = [] try: # Dict with parameters to list resource's inline policies parameters = {resource_name_tag: item[resource_name_tag]} inline_policies = list_resources( iam_client, "PolicyNames", literal_eval(record["body"])["action_list_resource_policies"], token_name, **parameters) except Exception as e: my_logging( "Could not list inline policies for %s %s: %s" % (str(resource_name_tag), str(item[resource_name_tag]), str(e)), "error") for policy in inline_policies: try: # Creates dict with parameters used to get policy parameters = { resource_name_tag: item[resource_name_tag], "PolicyName": policy } inline_doc = list_resources( iam_client, "PolicyDocument", literal_eval(record["body"])["action_get_resource_policy"], token_name, **parameters) item["Policies"].extend({ "PolicyName": policy, "PolicyDocument": inline_doc }) except Exception as e: my_logging( "Could not retrieve details for policy %s: %s" % (str(policy), str(e)), "error") try: # Dict with parameters to list resource"s attached policies parameters = {resource_name_tag: item[resource_name_tag]} attached_polices = list_resources( iam_client, "AttachedPolicies", literal_eval(record["body"])["action_list_attached_policies"], token_name, **parameters) except Exception as e: my_logging( "Could not list attached policies for %s %s: %s " % (str(resource_name_tag), str(item[resource_name_tag]), str(e)), "error") for i in attached_polices: try: # Creates dict with parameters used to get policy versions policy_details = list_resources(iam_client, "Versions", "list_policy_versions", token_name, PolicyArn=i["PolicyArn"]) except Exception as e: my_logging( 'Could not list versions of policy for %s %s: %s' % (str(resource_name_tag), str( item[resource_name_tag]), str(e)), "error") try: # Select default policy and save the data about it for sub in policy_details: if sub["IsDefaultVersion"]: document = iam_client.get_policy_version( PolicyArn=i["PolicyArn"], VersionId=sub["VersionId"]) item["Policies"].append({ "PolicyName": i["PolicyName"], "PolicyDocument": document["PolicyVersion"]["Document"], "DocumentVersion": sub["VersionId"] }) except Exception as e: my_logging( "Could not get document policy for %s %s: %s" % (str(resource_name_tag), str( item[resource_name_tag]), str(e)), "error") try: for policy in item["Policies"]: # Finds AdministratorAccess Policy if policy["PolicyName"] == "AdministratorAccess": try: msg = { "Alert": "Policy AdministratorAccess found attached", "Id": account["Id"], "Email": account["Email"], resource_name_tag: item[resource_name_tag], "Policy": policy } my_logging( send_sqs( msg, environ["sqs_url_AdministratorAccess"])) my_logging( send_sns( "Alert - AdministratorAccess Policy Found", msg, environ["sns_topic_administratorAccess"])) except Exception as e: my_logging(e, "error") # Iterates through policies and finds those with full access permissions for statement in policy["PolicyDocument"]["Statement"]: if isinstance(statement["Action"], str): is_full_access(statement["Action"], account["Id"], account["Email"], resource_name_tag, item[resource_name_tag], policy, environ["sqs_url_fullaccess"]) else: for action in statement["Action"]: is_full_access(action, account["Id"], account["Email"], resource_name_tag, item[resource_name_tag], policy, environ["sqs_url_fullaccess"]) except Exception as e: my_logging( "Could not verify if policies are too permissive. %s %s: %s" % (str(resource_name_tag), str( item[resource_name_tag]), str(e)), "error") item["CreateDate"] = str(item["CreateDate"]) if "PasswordLastUsed" in item: item["PasswordLastUsed"] = str(item["PasswordLastUsed"]) print( update_item( account["Id"], "SET Services.IAM.{}_list = list_append(Services.IAM.{}_list,:v)" .format(resource, resource), {"L": [{ "S": str(item) }]})) print("List of {} extracted: {}".format(resource, resource_list)) return my_logging("Execution finished")