def clean_sqs_policy_permissions(self): """ Class method to clean SQS queues which are violating aws best practices """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table( self.config.sqspolicy.ddb_table_name) backup_bucket = config.aws.s3_backup_bucket retention_period = self.config.sqspolicy.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.aws.accounts.items(): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues( ddb_table, account_id, SQSPolicyIssue) for issue in issues: queue_url = issue.issue_id queue_name = issue.issue_details.name queue_region = issue.issue_details.region in_whitelist = self.config.sqspolicy.in_whitelist( account_id, queue_url) if in_whitelist: logging.debug(f"Skipping {queue_name} (in whitelist)") continue if issue.timestamps.reported is None: logging.debug( f"Skipping '{queue_name}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug( f"Skipping {queue_name} (has been already remediated)") continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: account = Account( id=account_id, name=account_name, region=issue.issue_details.region, role_name=self.config.aws.role_name_reporting) if account.session is None: continue checker = SQSPolicyChecker(account=account) checker.check(queues=[queue_url]) queue = checker.get_queue(queue_name) if queue is None: logging.debug( f"Queue {queue_name} was removed by user") elif not queue.public: logging.debug( f"Queue {queue.name} policy issue was remediated by user" ) else: logging.debug(f"Remediating '{queue.name}' policy") backup_path = queue.backup_policy_s3( main_account.client("s3"), backup_bucket) remediation_succeed = True if queue.restrict_policy(): comment = ( f"Policy backup was saved to " f"[{backup_path}|https://s3.console.aws.amazon.com/s3/object/{backup_bucket}/{backup_path}]. " f"Queue '{queue.name}' policy issue " f"in '{account_name} / {account_id}' account, '{queue_region}' region " f"was remediated by hammer") else: remediation_succeed = False comment = ( f"Failed to remediate queue '{queue.name}' policy issue " f"in '{account_name} / {account_id}' account, '{queue_region}' region " f"due to some limitations. Please, check manually" ) jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated( ddb_table, issue) except Exception: logging.exception( f"Error occurred while updating queue '{queue_url}' policy " f"in '{account_name} / {account_id}', '{queue_region}' region" ) else: logging.debug( f"Skipping '{queue_name}' " f"({retention_period - no_of_days_issue_created} days before remediation)" )
def clean_s3bucket_policy_permissions(self, batch=False): """ Class method to clean S3 buckets which are violating aws best practices """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table( self.config.s3policy.ddb_table_name) backup_bucket = config.aws.s3_backup_bucket retention_period = self.config.s3policy.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.s3policy.remediation_accounts.items( ): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues( ddb_table, account_id, S3PolicyIssue) for issue in issues: bucket_name = issue.issue_id in_whitelist = self.config.s3policy.in_whitelist( account_id, bucket_name) #in_fixlist = self.config.s3policy.in_fixnow(account_id, bucket_name) if in_whitelist: logging.debug(f"Skipping {bucket_name} (in whitelist)") # Adding label with "whitelisted" to jira ticket. jira.add_label(ticket_id=issue.jira_details.ticket, label=IssueStatus.Whitelisted.value) continue # if not in_fixlist: # logging.debug(f"Skipping {bucket_name} (not in fixlist)") # continue if issue.timestamps.reported is None: logging.debug( f"Skipping '{bucket_name}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug( f"Skipping {bucket_name} (has been already remediated)" ) continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: account = Account( id=account_id, name=account_name, role_name=self.config.aws.role_name_reporting) if account.session is None: continue checker = S3BucketsPolicyChecker(account=account) checker.check(buckets=[bucket_name]) s3bucket = checker.get_bucket(bucket_name) if s3bucket is None: logging.debug( f"Bucket {s3bucket.name} was removed by user") elif not s3bucket.public_by_policy: logging.debug( f"Bucket {s3bucket.name} policy issue was remediated by user" ) else: if not batch and \ not confirm(f"Do you want to remediate '{bucket_name}' S3 bucket policy", False): continue logging.debug( f"Remediating '{s3bucket.name}' policy") backup_path = s3bucket.backup_policy_s3( main_account.client("s3"), backup_bucket) remediation_succeed = True if s3bucket.restrict_policy(): comment = ( f"Policy backup was saved to " f"[{backup_path}|https://s3.console.aws.amazon.com/s3/object/{backup_bucket}/{backup_path}]. " f"Bucket '{s3bucket.name}' policy issue " f"in '{account_name} / {account_id}' account " f"was remediated by hammer") else: remediation_succeed = False comment = ( f"Failed to remediate bucket '{s3bucket.name}' policy issue " f"in '{account_name} / {account_id}' account " f"due to some limitations. Please, check manually" ) jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated( ddb_table, issue) except Exception: logging.exception( f"Error occurred while updating bucket '{bucket_name}' policy " f"in '{account_name} / {account_id}'") else: logging.debug( f"Skipping '{bucket_name}' " f"({retention_period - no_of_days_issue_created} days before remediation)" )
def clean_iam_access_keys(self, batch=False): """ Class method to remediate IAM User access keys which are not used """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table( self.config.iamUserInactiveKeys.ddb_table_name) retention_period = self.config.iamUserInactiveKeys.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.aws.accounts.items(): logging.debug("* Account Name:" + account_name + " :::Account ID:::" + account_id) issues = IssueOperations.get_account_open_issues( ddb_table, account_id, IAMKeyInactiveIssue) for issue in issues: key_id = issue.issue_id username = issue.issue_details.username user_in_whitelist = self.config.iamUserInactiveKeys.in_whitelist( account_id, username) key_in_whitelist = self.config.iamUserInactiveKeys.in_whitelist( account_id, key_id) if user_in_whitelist or key_in_whitelist: logging.debug( f"Skipping '{key_id} / {username}' (in whitelist)") continue if issue.timestamps.reported is None: logging.debug( f"Skipping '{key_id} / {username}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug( f"Skipping '{key_id} / {username}' (has been already remediated)" ) continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: try: if not batch and \ not confirm(f"Do you want to remediate inactive access key '{key_id} / {username}'", False): continue account = Account( id=account_id, name=account_name, role_name=self.config.aws.role_name_reporting) if account.session is None: continue logging.debug( f"Remediating inactive access key '{key_id} / {username}'" ) remediation_succeed = True try: IAMOperations.disable_access_key( account.client("iam"), username, key_id) comment = ( f"Inactive access key '{key_id} / {username}' issue " f"in '{account_name} / {account_id}' account " f"was remediated by hammer") except Exception: remediation_succeed = False logging.exception( "Failed to disable '{key_id} / {username}' inactive access key" ) comment = ( f"Failed to remediate inactive access key '{key_id} / {username}' issue " f"in '{account_name} / {account_id}' account " f"due to some limitations. Please, check manually" ) jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", account_id=account_id, ) IssueOperations.set_status_remediated(ddb_table, issue) except Exception: logging.exception( f"Error occurred while disabling '{username} / {key_id}' " f"in '{account_name} / {account_id}'") else: logging.debug( f"Skipping '{key_id} / {username}' " f"({retention_period - no_of_days_issue_created} days before remediation)" )
def cleans3bucketunencrypted(self, batch=False): """ Class method to clean S3 buckets which are violating aws best practices """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table(self.config.s3Encrypt.ddb_table_name) retention_period = self.config.s3Encrypt.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.aws.accounts.items(): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues(ddb_table, account_id, S3EncryptionIssue) for issue in issues: bucket_name = issue.issue_id in_whitelist = self.config.s3Encrypt.in_whitelist(account_id, bucket_name) in_fixlist = True if in_whitelist: logging.debug(f"Skipping {bucket_name} (in whitelist)") continue if not in_fixlist: logging.debug(f"Skipping {bucket_name} (not in fixlist)") continue if issue.timestamps.reported is None: logging.debug(f"Skipping '{bucket_name}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug(f"Skipping {bucket_name} (has been already remediated)") continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: if not batch and \ not confirm(f"Do you want to remediate '{bucket_name}' S3 bucket unencrypted", False): continue account = Account(id=account_id, name=account_name, role_name=self.config.aws.role_name_reporting) if account.session is None: continue checker = S3EncryptionChecker(account=account) checker.check(buckets=[bucket_name]) s3bucket = checker.get_bucket(bucket_name) if s3bucket is None: logging.debug(f"Bucket {s3bucket.name} was removed by user") elif s3bucket.encrypted: logging.debug(f"Bucket {s3bucket.name} unencrypted issue was remediated by user") else: logging.debug(f"Remediating '{s3bucket.name}' unencrypted") # kms_key_id = None remediation_succeed = True if s3bucket.encrypt_bucket(): comment = (f"Bucket '{s3bucket.name}' unencrypted issue " f"in '{account_name} / {account_id}' account " f"was remediated by hammer") else: remediation_succeed = False comment = (f"Failed to remediate bucket '{s3bucket.name}' unencrypted issue " f"in '{account_name} / {account_id}' account " f"due to some limitations. Please, check manually") jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated(ddb_table, issue) except Exception: logging.exception(f"Error occurred while updating bucket '{bucket_name}' unencrypted " f"in '{account_name} / {account_id}'") else: logging.debug(f"Skipping '{bucket_name}' " f"({retention_period - no_of_days_issue_created} days before remediation)")
def clean_public_rds_snapshots(self, batch=False): """ Class method to remediate public rds snapshot """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table( self.config.rdsSnapshot.ddb_table_name) #backup_bucket = config.aws.s3_backup_bucket retention_period = self.config.rdsSnapshot.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.rdsSnapshot.remediation_accounts.items( ): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues( ddb_table, account_id, RdsPublicSnapshotIssue) for issue in issues: if issue.timestamps.remediated is not None: logging.debug( f"Skipping '{issue.issue_id}' (has been already remediated)" ) continue in_whitelist = self.config.rdsSnapshot.in_whitelist( account_id, issue.issue_id) if in_whitelist: logging.debug( f"Skipping '{issue.issue_id}' (in whitelist)") # Adding label with "whitelisted" to jira ticket. jira.add_label(ticket_id=issue.jira_details.ticket, label=IssueStatus.Whitelisted.value) continue if issue.timestamps.reported is None: logging.debug( f"Skipping '{issue.issue_id}' (was not reported)") continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: if not batch and \ not confirm(f"Do you want to remediate public RDS snapshot '{issue.issue_id}'", False): continue account = Account( id=account_id, name=account_name, region=issue.issue_details.region, role_name=self.config.aws.role_name_reporting) if account.session is None: continue remediation_succeed = True try: RdsSnapshotOperations.make_private( account.client("rds"), issue.issue_details.engine, issue.issue_details.name) comment = ( f"RDS public snapshot '{issue.issue_id}' issue " f"in '{account_name} / {account_id}' account, '{issue.issue_details.region}' region " f"was remediated by hammer") except Exception: remediation_succeed = False logging.exception( f"Failed to make private '{issue.issue_id}' RDS public snapshot" ) comment = ( f"Failed to remediate RDS public snapshot '{issue.issue_id}' issue " f"in '{account_name} / {account_id}' account, '{issue.issue_details.region}' region " f"due to some limitations. Please, check manually" ) jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated(ddb_table, issue) except Exception: logging.exception( f"Error occurred while updating RDS snapshot {issue.issue_id} " f"in {account_id}/{issue.issue_details.region}")
def clean_ami_public_access(self): """ Class method to clean AMI public access which are violating aws best practices """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table( self.config.publicAMIs.ddb_table_name) retention_period = self.config.publicAMIs.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.aws.accounts.items(): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues( ddb_table, account_id, PublicAMIIssue) for issue in issues: ami_id = issue.issue_id in_whitelist = self.config.publicAMIs.in_whitelist( account_id, ami_id) if in_whitelist: logging.debug(f"Skipping {ami_id} (in whitelist)") # Adding label with "whitelisted" to jira ticket. jira.add_label(ticket_id=issue.jira_details.ticket, label=IssueStatus.Whitelisted.value) continue if issue.timestamps.reported is None: logging.debug(f"Skipping '{ami_id}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug( f"Skipping {ami_id} (has been already remediated)") continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: account = Account( id=account_id, name=account_name, region=issue.issue_details.region, role_name=self.config.aws.role_name_reporting) if account.session is None: continue checker = PublicAMIChecker(account=account) checker.check(amis_to_check=[ami_id]) ami = checker.get_ami(ami_id) if ami is None: logging.debug(f"AMI {ami_id} was removed by user") elif not ami.public_access: logging.debug( f"AMI {ami.name} public access issue was remediated by user" ) else: logging.debug(f"Remediating '{ami.name}' ") remediation_succeed = True if ami.modify_image_attribute(): comment = ( f"AMI '{ami.name}' public access issue " f"in '{account_name} / {account_id}' account " f"was remediated by hammer") else: remediation_succeed = False comment = ( f"Failed to remediate AMI '{ami.name}' public access issue " f"in '{account_name} / {account_id}' account " f"due to some limitations. Please, check manually" ) jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated( ddb_table, issue) except Exception: logging.exception( f"Error occurred while updating AMI '{ami_id}' access " f"in '{account_name} / {account_id}'") else: logging.debug( f"Skipping '{ami_id}' " f"({retention_period - no_of_days_issue_created} days before remediation)" )
def clean_security_groups(self, batch=False): """ Class function to clean security groups which are violating aws best practices """ main_account = Account(region=config.aws.region) ddb_table = main_account.resource("dynamodb").Table(self.config.sg.ddb_table_name) backup_bucket = config.aws.s3_backup_bucket retention_period = self.config.sg.remediation_retention_period jira = JiraReporting(self.config) slack = SlackNotification(self.config) for account_id, account_name in self.config.sg.remediation_accounts.items(): logging.debug(f"Checking '{account_name} / {account_id}'") issues = IssueOperations.get_account_open_issues(ddb_table, account_id, SecurityGroupIssue) for issue in issues: group_name = issue.issue_details.name group_vpc_id = issue.issue_details.vpc_id group_id = issue.issue_id group_region = issue.issue_details.region # status = issue.jira_details.status name_in_whitelist = self.config.sg.in_whitelist(account_id, f"{group_vpc_id}:{group_name}") id_in_whitelist = self.config.sg.in_whitelist(account_id, group_id) if name_in_whitelist or id_in_whitelist: logging.debug(f"Skipping '{group_name} / {group_id}' (in whitelist)") # Adding label with "whitelisted" to jira ticket. jira.add_label( ticket_id=issue.jira_details.ticket, label=IssueStatus.Whitelisted.value ) continue if issue.timestamps.reported is None: logging.debug(f"Skipping '{group_name} / {group_id}' (was not reported)") continue if issue.timestamps.remediated is not None: logging.debug(f"Skipping '{group_name} / {group_id}' (has been already remediated)") continue updated_date = issue.timestamp_as_datetime no_of_days_issue_created = (self.config.now - updated_date).days if no_of_days_issue_created >= retention_period: owner = issue.jira_details.owner bu = issue.jira_details.business_unit product = issue.jira_details.product try: account = Account(id=account_id, name=account_name, region=group_region, role_name = self.config.aws.role_name_reporting) if account.session is None: continue checker = SecurityGroupsChecker(account=account, restricted_ports=self.config.sg.restricted_ports) checker.check(ids=[group_id]) sg = checker.get_security_group(group_id) if sg is None: logging.debug(f"Security group '{group_name} / {group_id}' was removed by user") elif sg.restricted: logging.debug(f"Security group '{group_name} / {group_id}' issue was remediated by user") elif sg.status != RestrictionStatus.OpenCompletely: logging.debug(f"Security group '{group_name} / {group_id}' is not completely open") else: if not batch and \ not confirm(f"Do you want to remediate security group '{group_name} / {group_id}'", False): continue logging.debug(f"Remediating '{group_name} / {group_id}' rules") backup_path = sg.backup_s3(main_account.client("s3"), backup_bucket) remediation_succeed = True processed = sg.restrict(RestrictionStatus.OpenCompletely) if processed == 0: logging.debug(f"No rules were detected to remediate in '{group_name} / {group_id}'") comment = None elif processed is None: remediation_succeed = False comment = (f"Failed to remediate security group '{group_name} / {group_id}' issue " f"in '{account_name} / {account_id}' account, '{group_region}' region " f"due to some limitations. Please, check manually") else: comment = (f"Rules backup was saved to " f"[{backup_path}|https://s3.console.aws.amazon.com/s3/object/{backup_bucket}/{backup_path}]. " f"Security group '{group_name} / {group_id}' `{RestrictionStatus.OpenCompletely.value}` issue " f"in '{account_name} / {account_id}' account, '{group_region}' region " f"was remediated by hammer") if comment is not None: jira.remediate_issue( ticket_id=issue.jira_details.ticket, comment=comment, reassign=remediation_succeed, ) slack.report_issue( msg=f"{comment}" f"{' (' + jira.ticket_url(issue.jira_details.ticket) + ')' if issue.jira_details.ticket else ''}", owner=owner, account_id=account_id, bu=bu, product=product, ) IssueOperations.set_status_remediated(ddb_table, issue) except Exception: logging.exception(f"Error occurred while updating security group '{group_name} / {group_id}' rules " f"in '{account_name} / {account_id} / {group_region}'") else: logging.debug(f"Skipping '{group_name} / {group_id}' " f"({retention_period - no_of_days_issue_created} days before remediation)")