From 8dc50643f5ccb264c4c6caae335d20f5d26fcc45 Mon Sep 17 00:00:00 2001 From: Eli Battat Date: Sun, 18 May 2025 17:09:02 +0300 Subject: [PATCH] Add unused access key policy --- POLICIES.md | 1 + README.md | 1 + .../common/clouds/aws/iam/iam_operations.py | 157 ++++++++++++++++++ .../elasticsearch/modals/policy_es_data.py | 2 + cloud_governance/common/utils/configs.py | 2 + .../main/environment_variables.py | 4 +- cloud_governance/main/example.yaml | 2 +- .../main/main_oerations/main_operations.py | 2 +- cloud_governance/policy/aws/monthly_report.py | 3 +- .../policy/aws/unused_access_key.py | 55 ++++++ .../common_policies/send_aggregated_alerts.py | 3 +- .../helpers/abstract_policy_operations.py | 6 +- .../helpers/aws/aws_policy_operations.py | 31 +++- .../zombie_non_cluster_polices.py | 2 +- docs/source/index.md | 1 + docs/source/podman.md | 2 +- .../clouds/aws/daily/policies/run_policies.py | 6 +- jenkins/tenant/aws/common/run_policies.py | 4 +- jenkins/tenant/aws/ovn/run_policies.py | 4 +- 19 files changed, 268 insertions(+), 20 deletions(-) create mode 100644 cloud_governance/policy/aws/unused_access_key.py diff --git a/POLICIES.md b/POLICIES.md index 52e911f27..f19726ac1 100644 --- a/POLICIES.md +++ b/POLICIES.md @@ -24,6 +24,7 @@ This tool support the following policies: monitoring the active connection count. * [s3_inactive](cloud_governance/policy/aws/s3_inactive.py): Identify the empty s3 buckets, causing the resource quota issues. +* [unused_access_key](cloud_governance/policy/aws/unused_access_key.py): Identify user with unused active access key, causing the security issue * [empty_roles](cloud_governance/policy/aws/empty_roles.py): Identify the empty roles that do not have any attached policies to them. * [ebs_in_use](cloud_governance/policy/aws/ebs_in_use.py): list in use volumes. diff --git a/README.md b/README.md index 7eb47777b..6622bc96a 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ List of Policies: - zombie_snapshots - unused_nat_gateway - s3_inactive +- unused_access_key - empty_roles - tag_resources - tag_iam_user diff --git a/cloud_governance/common/clouds/aws/iam/iam_operations.py b/cloud_governance/common/clouds/aws/iam/iam_operations.py index b4f5ac3cc..f87d4c4d1 100644 --- a/cloud_governance/common/clouds/aws/iam/iam_operations.py +++ b/cloud_governance/common/clouds/aws/iam/iam_operations.py @@ -5,10 +5,13 @@ from cloud_governance.common.clouds.aws.utils.common_methods import get_boto3_client from cloud_governance.common.clouds.aws.utils.utils import Utils from cloud_governance.common.logger.init_logger import logger +from datetime import datetime, timezone class IAMOperations: + ACCESS_KEY_LABEL_MAP = {"access key 1": 0, "access key 2": 1} + def __init__(self, iam_client=None): self.iam_client = iam_client if iam_client else get_boto3_client('iam') self.utils = Utils() @@ -158,3 +161,157 @@ def untag_role(self, role_name: str, tags: list): return True except Exception as err: raise err + + def tag_user(self, user_name: str, tags: list): + """ + This method tags the IAM user. + :param user_name: The name of the IAM user to tag. + :param tags: A list of tags to associate with the user. + :return: True if tagging is successful, otherwise raises an exception. + """ + try: + self.iam_client.tag_user(UserName=user_name, Tags=tags) + return True + except Exception as err: + raise err + + def get_iam_users_access_keys(self): + """ + Retrieves IAM users and summarizes: + - Access key status (active/inactive) + - Access key age in days + - Access key last used in days (or "N/A" if never used) + - Tags (as a list of dictionaries) + - Most recent key usage: last_activity_days + - IAM client region (global context, since IAM is non-regional) + - IAM user unique ID: ResourceId + + Returns: + dict: { + "username": { + "Access key 1": [status, age_days, last_used_days], + "Access key 2": [...], + "last_activity_days": int or "N/A", + "tags": [{"Key": "tag_key", "Value": "tag_value"}, ...], + "region": "us-east-1", + "ResourceId": "AIDAEXAMPLEUSERID" + }, + ... + } + """ + result = {} + now = datetime.now(timezone.utc) + region_name = self.iam_client.meta.region_name or "global" + + paginator = self.iam_client.get_paginator('list_users') + for page in paginator.paginate(): + for user in page['Users']: + username = user['UserName'] + result[username] = {} + # Access keys + access_keys = self.iam_client.list_access_keys(UserName=username)['AccessKeyMetadata'] + for idx, key in enumerate(access_keys, start=1): + label = f"Access key {idx}" + status = key['Status'].lower() + age_days = (now - key['CreateDate']).days + + # Get access key last used + try: + response = self.iam_client.get_access_key_last_used(AccessKeyId=key['AccessKeyId']) + last_used_date = response.get('AccessKeyLastUsed', {}).get('LastUsedDate') + if last_used_date: + last_used_days = (now - last_used_date).days + else: + last_used_days = "N/A" + except Exception: + last_used_days = "N/A" + + result[username][label] = {'label': label, 'status': status, 'age_days': age_days, 'last_activity_days': last_used_days if last_used_days is not None else "N/A"} + + # Tags as list of dicts + try: + tag_response = self.iam_client.list_user_tags(UserName=username) + tags = tag_response.get('Tags', []) + except Exception: + tags = [] + + result[username]["tags"] = tags + result[username]["region"] = region_name + result[username]["ResourceId"] = user.get('UserId') # <-- Unique ID + + return result + + def has_active_access_keys(self, username: str, access_key_label: str = None) -> bool: + """ + Checks if the given IAM user has any active access keys. + Optionally filters by access key label ("Access Key 1" or "Access Key 2"). + + Args: + username (str): IAM user name + access_key_label (str): Label to filter access keys ("Access Key 1"/"Access Key 2") + + Returns: + bool: True if any access key is active (and matches the label if provided), False otherwise + """ + try: + keys = self.iam_client.list_access_keys(UserName=username)['AccessKeyMetadata'] + except Exception as e: + logger.error(f"Failed to list access keys for user '{username}': {e}") + return False + + # Sort keys by CreateDate ascending (oldest first) + keys.sort(key=lambda k: k['CreateDate']) + + if access_key_label: + idx = self.ACCESS_KEY_LABEL_MAP.get(access_key_label.lower()) + if idx is None or idx >= len(keys): + return False + return keys[idx].get('Status') == 'Active' + + return any(k.get('Status') == 'Active' for k in keys) + + def deactivate_user_access_key(self, username: str, **kwargs): + """ + Deactivates the specified access key for the given IAM user. + + Args: + username (str): IAM user name + access_key_label (str): Access Key 1 or Access Key 2 (case-insensitive) + """ + access_key_label = kwargs.get('access_key_label', '').lower() + if not access_key_label: + logger.warning("No access key label provided for deactivation.") + return + + try: + access_keys = self.iam_client.list_access_keys(UserName=username)['AccessKeyMetadata'] + except Exception as e: + logger.error(f"Failed to list access keys for user '{username}': {e}") + return + + # Sort keys by CreateDate ascending (oldest first) for consistent indexing + access_keys.sort(key=lambda k: k['CreateDate']) + + idx = self.ACCESS_KEY_LABEL_MAP.get(access_key_label) + if idx is None or idx >= len(access_keys): + logger.warning(f"Access key label '{access_key_label}' not found for user '{username}'") + return + + key_to_deactivate = access_keys[idx] + access_key_id = key_to_deactivate['AccessKeyId'] + current_status = key_to_deactivate['Status'].lower() + + if current_status == 'active': + try: + self.iam_client.update_access_key( + UserName=username, + AccessKeyId=access_key_id, + Status='Inactive' + ) + logger.info(f"Access key '{access_key_id}' deactivated for user '{username}'") + except Exception as e: + logger.error(f"Failed to deactivate access key '{access_key_id}' for user '{username}': {e}") + else: + logger.info(f"Access key '{access_key_id}' is already inactive for user '{username}'") + + logger.info(f"Access key deactivation processed for user '{username}'.") diff --git a/cloud_governance/common/elasticsearch/modals/policy_es_data.py b/cloud_governance/common/elasticsearch/modals/policy_es_data.py index da458be77..36be09fa7 100644 --- a/cloud_governance/common/elasticsearch/modals/policy_es_data.py +++ b/cloud_governance/common/elasticsearch/modals/policy_es_data.py @@ -37,6 +37,8 @@ class PolicyEsMetaData(dict): launch_time: str = '' running_days: int = '' create_date: str = '' + age_days: int = '' + last_activity_days: int = '' def __post_init__(self): """ diff --git a/cloud_governance/common/utils/configs.py b/cloud_governance/common/utils/configs.py index 940852d99..2310efdf5 100644 --- a/cloud_governance/common/utils/configs.py +++ b/cloud_governance/common/utils/configs.py @@ -22,6 +22,8 @@ EC2_NAMESPACE = 'AWS/EC2' CLOUDWATCH_METRICS_AVAILABLE_DAYS = 14 AWS_DEFAULT_GLOBAL_REGION = 'us-east-1' +UNUSED_ACCESS_KEY_DAYS = 90 +UNUSED_ACCESS_KEY_MAX_DAY = 1000 # X86 to Graviton GRAVITON_MAPPINGS = { diff --git a/cloud_governance/main/environment_variables.py b/cloud_governance/main/environment_variables.py index 14a6689a1..8ecbcf586 100644 --- a/cloud_governance/main/environment_variables.py +++ b/cloud_governance/main/environment_variables.py @@ -98,7 +98,7 @@ def __init__(self): 'ip_unattached', 'unused_nat_gateway', 'instance_idle', 'ec2_stop', 'ebs_in_use', 'database_idle', - 's3_inactive', + 's3_inactive', 'unused_access_key', 'empty_roles', 'zombie_snapshots', 'skipped_resources', 'monthly_report', 'optimize_resources_report'] @@ -277,7 +277,7 @@ def __init__(self): self._environment_variables_dict['POLICY_ACTIONS_DAYS'] = literal_eval( EnvironmentVariables.get_env('POLICY_ACTIONS_DAYS', '[]')) self._environment_variables_dict['DEFAULT_ADMINS'] = literal_eval( - EnvironmentVariables.get_env('DEFAULT_ADMINS', '[]')) + EnvironmentVariables.get_env('DEFAULT_ADMINS', '["yinsong@redhat.com", "ebattat@redhat.com"]')) self._environment_variables_dict['KERBEROS_USERS'] = literal_eval( EnvironmentVariables.get_env('KERBEROS_USERS', '[]')) self._environment_variables_dict['POLICIES_TO_ALERT'] = literal_eval( diff --git a/cloud_governance/main/example.yaml b/cloud_governance/main/example.yaml index 4a5b66b66..60423c1d9 100644 --- a/cloud_governance/main/example.yaml +++ b/cloud_governance/main/example.yaml @@ -23,7 +23,7 @@ ATHENA_ACCOUNT_SECRET_KEY: "" non_cluster_policies: [ 'instance_run', 'unattached_volume', 'cluster_run', 'ip_unattached', 'unused_nat_gateway', 'instance_idle', - 'ec2_stop', 'ebs_in_use', 'database_idle', 's3_inactive', + 'ec2_stop', 'ebs_in_use', 'database_idle', 's3_inactive', 'unused_access_key', 'empty_roles', 'tag_resources', 'cost_usage_reports', 'zombie_snapshots', 'skipped_resources', 'monthly_report', 'optimize_resources_report' ] diff --git a/cloud_governance/main/main_oerations/main_operations.py b/cloud_governance/main/main_oerations/main_operations.py index 463df8dca..b2ebbf486 100644 --- a/cloud_governance/main/main_oerations/main_operations.py +++ b/cloud_governance/main/main_oerations/main_operations.py @@ -42,7 +42,7 @@ def run(self): # @Todo support for all the aws policies, currently supports ec2_run as urgent requirement if self._policy in policies and self._policy in ["instance_run", "unattached_volume", "cluster_run", "ip_unattached", "unused_nat_gateway", "instance_idle", - "zombie_snapshots", "database_idle", "s3_inactive", + "zombie_snapshots", "database_idle", "s3_inactive", "unused_access_key", "empty_roles", "tag_resources", "cost_usage_reports"]: source = policy_type if Utils.equal_ignore_case(policy_type, self._public_cloud_name): diff --git a/cloud_governance/policy/aws/monthly_report.py b/cloud_governance/policy/aws/monthly_report.py index 4f59ad522..d7c4d0a49 100644 --- a/cloud_governance/policy/aws/monthly_report.py +++ b/cloud_governance/policy/aws/monthly_report.py @@ -37,7 +37,8 @@ def policy_description(self, policy_name: str): 'ip_unattached': 'Delete all the elastic_ips that are unused', 'unused_nat_gateway': ' Delete all unused nat gateways', 'zombie_snapshots': 'Delete all the snapshots which the AMI does not use', - 's3_inactive': 'Delete the empty buckets which don’t have any content.', + 's3_inactive': 'Delete the empty buckets which don’t have any content', + 'unused_access_key': 'Deactivate user access keys that are still active but have not been used', 'empty_roles': 'Delete the empty role which does\'t have any policies', 'zombie_cluster_resource': 'Delete up the cluster resources which are not deleted while cleaning the cluster' } diff --git a/cloud_governance/policy/aws/unused_access_key.py b/cloud_governance/policy/aws/unused_access_key.py new file mode 100644 index 000000000..f85798db6 --- /dev/null +++ b/cloud_governance/policy/aws/unused_access_key.py @@ -0,0 +1,55 @@ +from cloud_governance.common.utils.configs import UNUSED_ACCESS_KEY_DAYS, UNUSED_ACCESS_KEY_MAX_DAY +from cloud_governance.policy.helpers.aws.aws_policy_operations import AWSPolicyOperations + + +class UnusedAccessKey(AWSPolicyOperations): + RESOURCE_ACTION = "DeActivate" + + def __init__(self): + super().__init__() + + def run_policy_operations(self): + """ + This method returns a list of users with at least one active access key whose last used date is greater than UNUSED_ACCESS_KEY_DAYS + :return: + :rtype: + """ + unused_access_keys = [] + iam_users_access_keys = self._get_iam_users_access_keys() + for username, user_data in iam_users_access_keys.items(): + for access_key_label, access_key_data in user_data.items(): + if 'access key' in access_key_label.lower(): + last_activity_days = access_key_data['last_activity_days'] + age_days = access_key_data['age_days'] + # if access key last_activity_days is "N/A", use age_days + if last_activity_days == "N/A": + last_activity_days = age_days + region = user_data['region'] + user_name = username + tags = user_data.get('Tags', []) + cleanup_result = False + cleanup_days = 0 + if int(last_activity_days) >= UNUSED_ACCESS_KEY_DAYS and self._has_active_access_keys(user_name, access_key_label) and self.get_skip_policy_value(tags=tags) not in ('NOTDELETE', 'SKIP'): + cleanup_days = self.get_clean_up_days_count(tags=tags) + cleanup_result = self.verify_and_delete_resource(resource_id=user_name, tags=tags, + clean_up_days=cleanup_days, access_key_label=access_key_label) + resource_data = self._get_es_schema(resource_id=user_name, + user=self.get_tag_name_from_tags(tags=tags, tag_name='User'), + skip_policy=self.get_skip_policy_value(tags=tags), + cleanup_days=cleanup_days, + dry_run=self._dry_run, + name=user_name, + region=region, + cleanup_result=str(cleanup_result), + resource_action=self.RESOURCE_ACTION, + cloud_name=self._cloud_name, + resource_type='UnusedAccessKey', + resource_state='Active', + age_days=age_days, + last_activity_days=last_activity_days, + unit_price=0) + unused_access_keys.append(resource_data) + if not cleanup_result: + self.update_resource_day_count_tag(resource_id=user_name, cleanup_days=cleanup_days, tags=tags) + + return unused_access_keys diff --git a/cloud_governance/policy/common_policies/send_aggregated_alerts.py b/cloud_governance/policy/common_policies/send_aggregated_alerts.py index dde2f614b..64de5ad7b 100644 --- a/cloud_governance/policy/common_policies/send_aggregated_alerts.py +++ b/cloud_governance/policy/common_policies/send_aggregated_alerts.py @@ -162,7 +162,8 @@ def __update_delete_days(self, policy_es_data: list): if days >= days_to_take_action: delete_date = datetime.utcnow().date().__str__() alert_user = True - if record.get('policy') in ['empty_roles', 's3_inactive']: + # Cross region policies + if record.get('policy') in ['empty_roles', 's3_inactive', 'unused_access_key']: record['RegionName'] = 'us-east-1' if Utils.equal_ignore_case(dry_run, 'yes'): record['DeleteDate'] = 'dry_run=yes' diff --git a/cloud_governance/policy/helpers/abstract_policy_operations.py b/cloud_governance/policy/helpers/abstract_policy_operations.py index 96ec7f9fc..25e701846 100644 --- a/cloud_governance/policy/helpers/abstract_policy_operations.py +++ b/cloud_governance/policy/helpers/abstract_policy_operations.py @@ -111,7 +111,7 @@ def get_skip_policy_value(self, tags: Union[list, dict]) -> str: return 'NA' @abstractmethod - def _delete_resource(self, resource_id: str): + def _delete_resource(self, resource_id: str, **kwargs): """ This method deletes the resource :param resource_id: @@ -144,7 +144,7 @@ def verify_and_delete_resource(self, resource_id: str, tags: Union[list, dict], :rtype: """ if self._resource_id == resource_id and self._force_delete and self._dry_run == 'no': - self._delete_resource(resource_id=resource_id) + self._delete_resource(resource_id=resource_id, **kwargs) return True if not days_to_delete_resource: days_to_delete_resource = self._days_to_take_action @@ -157,7 +157,7 @@ def verify_and_delete_resource(self, resource_id: str, tags: Union[list, dict], if clean_up_days >= days_to_delete_resource: if self._dry_run == 'no': if self.get_skip_policy_value(tags=tags) not in ('NOTDELETE', 'SKIP'): - self._delete_resource(resource_id=resource_id) + self._delete_resource(resource_id=resource_id, **kwargs) cleanup_resources = True return cleanup_resources diff --git a/cloud_governance/policy/helpers/aws/aws_policy_operations.py b/cloud_governance/policy/helpers/aws/aws_policy_operations.py index e7591ec8c..3d7af2641 100644 --- a/cloud_governance/policy/helpers/aws/aws_policy_operations.py +++ b/cloud_governance/policy/helpers/aws/aws_policy_operations.py @@ -21,7 +21,7 @@ def __init__(self): self.policy_name = self._environment_variables_dict.get('policy') self._cloud_name = 'AWS' self._ec2_client = get_boto3_client(client='ec2', region_name=self._region) - self._s3_client = get_boto3_client('s3', region_name=self._region) + self._s3_client = get_boto3_client(client='s3', region_name=self._region) self._iam_operations = IAMOperations() self._rds_operations = RDSOperations(region_name=self._region) self._s3operations = S3Operations(region_name=self._region) @@ -46,7 +46,7 @@ def get_tag_name_from_tags(self, tags: list, tag_name: str) -> str: return tag.get('Value').strip() return '' - def _delete_resource(self, resource_id: str): + def _delete_resource(self, resource_id: str, **kwargs): """ This method deletes the resource by verifying the policy :param resource_id: @@ -58,6 +58,8 @@ def _delete_resource(self, resource_id: str): try: if self._policy == 's3_inactive': self._s3_client.delete_bucket(Bucket=resource_id) + elif self._policy == 'unused_access_key': + self._iam_operations.deactivate_user_access_key(username=resource_id, **kwargs) elif self._policy == 'empty_roles': response = self._iam_operations.delete_role(role_name=resource_id) elif self._policy == 'unattached_volume': @@ -147,6 +149,8 @@ def update_resource_tags(self, tags: list, resource_id: str): try: if self._policy == 's3_inactive': self._s3_client.put_bucket_tagging(Bucket=resource_id, Tagging={'TagSet': tags}) + elif self._policy == 'unused_access_key': + self._iam_operations.tag_user(user_name=resource_id, tags=tags) elif self._policy == 'empty_roles': self._iam_operations.tag_role(role_name=resource_id, tags=tags) elif self._policy in ('ip_unattached', 'unused_nat_gateway', 'zombie_snapshots', 'unattached_volume', @@ -196,6 +200,29 @@ def _get_all_volumes(self, **kwargs) -> list: volumes = self._ec2_operations.get_volumes(**kwargs) return volumes + def _get_iam_users_access_keys(self) -> dict: + """ + This method returns a list of user access keys with their age in days, last used time in days, user tags, and more. + :return: list of user access keys + """ + return self._iam_operations.get_iam_users_access_keys() + + def _has_active_access_keys(self, user_name: str, access_key_label: str) -> bool: + """ + This method checks if the given IAM user has any active access keys. + :return: + :rtype: + """ + return self._iam_operations.has_active_access_keys(username=user_name, access_key_label=access_key_label) + + def _deactivate_access_key(self, user_name: str, access_key_label: str) -> bool: + """ + This method checks if the given IAM user has any active access keys. + :return: + :rtype: + """ + return self._iam_operations.deactivate_user_access_key(username=user_name, access_key_label=access_key_label) + def _get_active_cluster_ids(self): """ This method returns the active cluster id's diff --git a/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/zombie_non_cluster_polices.py b/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/zombie_non_cluster_polices.py index 06226bf42..ec8e9c9f2 100644 --- a/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/zombie_non_cluster_polices.py +++ b/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/zombie_non_cluster_polices.py @@ -45,7 +45,7 @@ def run(self): logger.error('ElasticSearch host is not pingable, Please check ') if self._policy_output: - # if self._policy not in ('ec2_idle', 'ebs_in_use', 'ec2_run', 's3_inactive', 'zombie_snapshots', 'nat_gateway_unused'): + # if self._policy not in ('ec2_idle', 'ebs_in_use', 'ec2_run', 's3_inactive', 'unused_access_key', 'zombie_snapshots', 'nat_gateway_unused'): # beautify_data = self._beautify_upload_data(upload_resource_data=response) # policy_result = {'count': len(beautify_data), self._policy: beautify_data} logger.info(policy_result) diff --git a/docs/source/index.md b/docs/source/index.md index 4d992e003..e6cfe210d 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -37,6 +37,7 @@ This tool support the following policies: by monitoring the active connection count. * [s3_inactive](../../cloud_governance/policy/aws/s3_inactive.py): Identify the empty s3 buckets, causing the resource quota issues. +* [unused_access_key](../../cloud_governance/policy/aws/unused_access_key.py): Identify user with unused active access key, causing the security issue * [empty_roles](../../cloud_governance/policy/aws/empty_roles.py): Identify the empty roles that do not have any attached policies to them. * [ebs_in_use](../../cloud_governance/policy/aws/ebs_in_use.py): list in use volumes. diff --git a/docs/source/podman.md b/docs/source/podman.md index 5d99b4b8f..80ea57fd5 100644 --- a/docs/source/podman.md +++ b/docs/source/podman.md @@ -7,7 +7,7 @@ sudo podman run --rm --name cloud-governance -e policy="instance_idle" -e AWS_AC # policy=ec2_run sudo podman run --rm --name cloud-governance -e policy="ec2_run" -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" -e AWS_DEFAULT_REGION="us-east-2" -e dry_run="yes" -e policy_output="s3://bucket/logs" -e log_level="INFO" "quay.io/cloud-governance/cloud-governance" -# select policy ['ec2_stop', 's3_inactive', 'empty_roles', 'ip_unattached', 'nat_gateway_unused', 'zombie_snapshots'] +# select policy ['ec2_stop', 's3_inactive', 'unused_access_key', 'empty_roles', 'ip_unattached', 'unused_nat_gateway', 'zombie_snapshots'] sudo podman run --rm --name cloud-governance -e policy="policy" -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" -e AWS_DEFAULT_REGION="us-east-2" -e dry_run="yes" -e log_level="INFO" "quay.io/cloud-governance/cloud-governance" # policy=ebs_unattached diff --git a/jenkins/clouds/aws/daily/policies/run_policies.py b/jenkins/clouds/aws/daily/policies/run_policies.py index 66bf5c360..676bbd14b 100644 --- a/jenkins/clouds/aws/daily/policies/run_policies.py +++ b/jenkins/clouds/aws/daily/policies/run_policies.py @@ -47,7 +47,7 @@ def get_policies(file_type: str = '.py', exclude_policies: list = None): exclude_global_cost_policies = ['cost_explorer', 'optimize_resources_report', 'monthly_report', 'cost_over_usage', 'skipped_resources', 'cost_explorer_payer_billings', 'cost_billing_reports', 'spot_savings_analysis'] -GLOBAL_POLICIES = ["s3_inactive", "empty_roles"] +GLOBAL_POLICIES = ["s3_inactive", "empty_roles", "unused_access_key"] available_policies = get_policies(exclude_policies=exclude_global_cost_policies) @@ -104,10 +104,10 @@ def run_policies(policies: list, dry_run: str = 'yes'): for policy in policies: container_env_dict.update({"AWS_DEFAULT_REGION": region, 'policy': policy}) container_cmd = '' - if policy in ('empty_roles', 's3_inactive') and region == 'us-east-1': + if policy in ('empty_roles', 's3_inactive', 'unused_access_key') and region == 'us-east-1': container_cmd = get_container_cmd(container_env_dict) else: - if policy not in ('empty_roles', 's3_inactive'): + if policy not in ('empty_roles', 's3_inactive', 'unused_access_key'): container_cmd = get_container_cmd(container_env_dict) if container_cmd: run_cmd(container_cmd) diff --git a/jenkins/tenant/aws/common/run_policies.py b/jenkins/tenant/aws/common/run_policies.py index 103533837..3045e17df 100644 --- a/jenkins/tenant/aws/common/run_policies.py +++ b/jenkins/tenant/aws/common/run_policies.py @@ -103,10 +103,10 @@ def run_policies(policies: list, dry_run: str = 'yes'): for policy in policies: container_env_dict.update({"AWS_DEFAULT_REGION": region, 'policy': policy}) container_cmd = '' - if policy in ('empty_roles', 's3_inactive') and region == 'us-east-1': + if policy in ('empty_roles', 's3_inactive', 'unused_access_key') and region == 'us-east-1': container_cmd = get_container_cmd(container_env_dict) else: - if policy not in ('empty_roles', 's3_inactive'): + if policy not in ('empty_roles', 's3_inactive', 'unused_access_key'): container_cmd = get_container_cmd(container_env_dict) if container_cmd: run_cmd(container_cmd) diff --git a/jenkins/tenant/aws/ovn/run_policies.py b/jenkins/tenant/aws/ovn/run_policies.py index 38eb711f3..05c59568d 100644 --- a/jenkins/tenant/aws/ovn/run_policies.py +++ b/jenkins/tenant/aws/ovn/run_policies.py @@ -77,10 +77,10 @@ def run_policies(policies: list, dry_run: str = 'yes'): for policy in policies: container_env_dict.update({"AWS_DEFAULT_REGION": region, 'policy': policy}) container_cmd = '' - if policy in ('empty_roles', 's3_inactive') and region == 'us-east-1': + if policy in ('empty_roles', 's3_inactive', 'unused_access_key') and region == 'us-east-1': container_cmd = get_container_cmd(container_env_dict) else: - if policy not in ('empty_roles', 's3_inactive'): + if policy not in ('empty_roles', 's3_inactive', 'unused_access_key'): container_cmd = get_container_cmd(container_env_dict) if container_cmd: run_cmd(container_cmd)