diff --git a/deployment/configs/config.json b/deployment/configs/config.json index 68bb3bef..8c073376 100755 --- a/deployment/configs/config.json +++ b/deployment/configs/config.json @@ -7,7 +7,9 @@ "enabled": false, "server": "https://issues.example.com", "issue_type": "Task", - "text_field_character_limit": 32767 + "text_field_character_limit": 32767, + "risk_field_id": "", + "risk_field_param": "" }, "slack": { "enabled": true, diff --git a/hammer/library/config.py b/hammer/library/config.py index 504f1a1d..d9af1964 100755 --- a/hammer/library/config.py +++ b/hammer/library/config.py @@ -276,6 +276,14 @@ def enabled(self): def text_field_character_limit(self): return self._config.get("text_field_character_limit", 0) + @property + def risk_field_id(self): + return self._config.get("risk_field_id", "") + + @property + def risk_field_param(self): + return self._config.get("risk_field_param", "") + def __getattr__(self, key): """ Search for any attribute in config, if not found - raise exception """ if key in self._config: diff --git a/hammer/library/jiraoperations.py b/hammer/library/jiraoperations.py index cc71c00e..74dd2da5 100755 --- a/hammer/library/jiraoperations.py +++ b/hammer/library/jiraoperations.py @@ -2,17 +2,23 @@ import logging import urllib3 - from collections import namedtuple from jira import JIRA from jira import JIRAError from library.utility import empty_converter - NewIssue = namedtuple('NewIssue', [ 'ticket_id', 'ticket_assignee_id' - ]) +]) + +risk_priority_mapping = { + "Critical": "Blocker", + "High": "Critical", + "Medium": "Major", + "Low": "Minor", + "Info": "Trivial" +} class JiraReporting(object): @@ -23,7 +29,7 @@ def __init__(self, config): def add_issue(self, issue_summary, issue_description, - priority, labels, + risk, labels, account_id, owner=None, bu=None, product=None, @@ -42,9 +48,17 @@ def add_issue(self, "summary": issue_summary, "description": issue_description, "issuetype": {"name": self.config.jira.issue_type}, - "priority": {"name": priority}, "labels": labels } + + if self.config.jira.risk_field_id: + issue_data[self.config.jira.risk_field_id] = { + self.config.jira.risk_field_param: risk + } + issue_data["priority"] = {"name": 'Major'} + else: + issue_data["priority"] = {"name": risk_priority_mapping[risk]} + ticket_id = self.jira.create_ticket(issue_data) parent_ticket_id = self.config.owners.ticket_parent( @@ -114,6 +128,7 @@ def ticket_url(self, ticket_id): def add_label(self, ticket_id, label): self.jira.add_label(ticket_id, label) + class JiraOperations(object): """ Base class for interaction with JIRA """ def __init__(self, config): @@ -330,8 +345,8 @@ def add_comment(self, ticket_id, comment): def add_watcher(self, ticket_id, user): """ Adding jira ticket watcher. - - :param ticket_id: jira ticket id + + :param ticket_id: jira ticket id :param user: watcher user id :return: nothing """ diff --git a/hammer/reporting-remediation/reporting/create_ebs_public_snapshot_issue_tickets.py b/hammer/reporting-remediation/reporting/create_ebs_public_snapshot_issue_tickets.py index 204fc4f5..302c878c 100755 --- a/hammer/reporting-remediation/reporting/create_ebs_public_snapshot_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_ebs_public_snapshot_issue_tickets.py @@ -91,9 +91,10 @@ def create_tickets_ebs_public_snapshots(self): issue_summary = (f"EBS public snapshot '{snapshot_id}' " f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" issue_description = ( f"The EBS volume snapshot is marked as public.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*AccountID*: {account_id}\n" f"*Region*: {region}\n" @@ -120,7 +121,7 @@ def create_tickets_ebs_public_snapshots(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["public_snapshots"], + risk=issue_risk, labels=["public_snapshots"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_iam_key_inactive_tickets.py b/hammer/reporting-remediation/reporting/create_iam_key_inactive_tickets.py index f43b7555..fd869ea4 100755 --- a/hammer/reporting-remediation/reporting/create_iam_key_inactive_tickets.py +++ b/hammer/reporting-remediation/reporting/create_iam_key_inactive_tickets.py @@ -71,9 +71,10 @@ def create_jira_ticket(self): create_date = dateutil.parser.parse(issue.issue_details.create_date).replace(tzinfo=None).isoformat(' ', 'minutes') last_used = dateutil.parser.parse(issue.issue_details.last_used).replace(tzinfo=None).isoformat(' ', 'minutes') + issue_risk = "Low" issue_description = ( f"IAM access key has not been used for {self.config.iamUserInactiveKeys.inactive_criteria_days.days} days.\n\n" - f"*Risk*: Low\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*User Name*: {username}\n" @@ -94,7 +95,7 @@ def create_jira_ticket(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["inactive-iam-keys"], + risk=issue_risk, labels=["inactive-iam-keys"], account_id=account_id, ) except Exception: diff --git a/hammer/reporting-remediation/reporting/create_iam_key_rotation_tickets.py b/hammer/reporting-remediation/reporting/create_iam_key_rotation_tickets.py index 74fd5872..1828d159 100755 --- a/hammer/reporting-remediation/reporting/create_iam_key_rotation_tickets.py +++ b/hammer/reporting-remediation/reporting/create_iam_key_rotation_tickets.py @@ -70,9 +70,10 @@ def create_jira_ticket(self): f"in '{account_name} / {account_id}' account") create_date = dateutil.parser.parse(issue.issue_details.create_date).replace(tzinfo=None).isoformat(' ', 'minutes') + issue_risk = "Low" issue_description = ( f"IAM access key has not been rotated for {self.config.iamUserKeysRotation.rotation_criteria_days.days} days.\n\n" - f"*Risk*: Low\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*User Name*: {username}\n" @@ -92,7 +93,7 @@ def create_jira_ticket(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["iam-key-rotation"], + risk=issue_risk, labels=["iam-key-rotation"], account_id=account_id, ) except Exception: diff --git a/hammer/reporting-remediation/reporting/create_public_ami_issue_tickets.py b/hammer/reporting-remediation/reporting/create_public_ami_issue_tickets.py index 3cf6b7f5..31f250d8 100644 --- a/hammer/reporting-remediation/reporting/create_public_ami_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_public_ami_issue_tickets.py @@ -101,11 +101,13 @@ def create_tickets_public_ami(self): issue_summary = (f"AMI '{ami_id}' with public access " f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"AMI allows public access.\n\n" f"*Threat*: " f" .\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*Region*: {ami_region}\n" @@ -126,7 +128,7 @@ def create_tickets_public_ami(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["public-ami"], + risk=issue_risk, labels=["public-ami"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_rds_public_snapshot_issue_tickets.py b/hammer/reporting-remediation/reporting/create_rds_public_snapshot_issue_tickets.py index e0227dca..4c677569 100755 --- a/hammer/reporting-remediation/reporting/create_rds_public_snapshot_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_rds_public_snapshot_issue_tickets.py @@ -90,9 +90,11 @@ def create_tickets_rds_public_snapshots(self): issue_summary = (f"RDS public snapshot '{snapshot_id}'" f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"The RDS snapshot is marked as public.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*Region*: {region}\n" @@ -117,7 +119,7 @@ def create_tickets_rds_public_snapshots(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["rds-public-snapshots"], + risk=issue_risk, labels=["rds-public-snapshots"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_rds_unencrypted_instance_issue_tickets.py b/hammer/reporting-remediation/reporting/create_rds_unencrypted_instance_issue_tickets.py index 10a71429..c66edc8c 100644 --- a/hammer/reporting-remediation/reporting/create_rds_unencrypted_instance_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_rds_unencrypted_instance_issue_tickets.py @@ -91,6 +91,8 @@ def create_tickets_rds_unencrypted_instances(self): issue_summary = (f"RDS unencrypted instance '{instance_name}'" f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"The RDS instance is unencrypted.\n\n" f"*Threat*: " @@ -98,7 +100,7 @@ def create_tickets_rds_unencrypted_instances(self): f"intellectual property of the organization needs to be encrypted. Additionally, as part of the " f"initiative of Encryption Everywhere, it is necessary to encrypt the data in order to ensure the " f"confidentiality and integrity of the data.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*Region*: {region}\n" @@ -114,7 +116,7 @@ def create_tickets_rds_unencrypted_instances(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["rds-unencrypted-instances"], + risk=issue_risk, labels=["rds-unencrypted-instances"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_s3_unencrypted_bucket_issue_tickets.py b/hammer/reporting-remediation/reporting/create_s3_unencrypted_bucket_issue_tickets.py index f8b2fdb5..777538a9 100644 --- a/hammer/reporting-remediation/reporting/create_s3_unencrypted_bucket_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_s3_unencrypted_bucket_issue_tickets.py @@ -99,6 +99,8 @@ def create_tickets_s3_unencrypted_buckets(self): issue_summary = (f"S3 bucket '{bucket_name}' unencrypted " f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"Bucket is unencrypted.\n\n" f"*Threat*: " @@ -106,7 +108,7 @@ def create_tickets_s3_unencrypted_buckets(self): f"intellectual property of the organization needs to be encrypted. Additionally, as part of the " f"initiative of Encryption Everywhere, it is necessary to encrypt the data in order to ensure the " f"confidentiality and integrity of the data.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*S3 Bucket name*: {bucket_name}\n" @@ -127,7 +129,7 @@ def create_tickets_s3_unencrypted_buckets(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["s3-unencrypted"], + risk=issue_risk, labels=["s3-unencrypted"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_s3bucket_acl_issue_tickets.py b/hammer/reporting-remediation/reporting/create_s3bucket_acl_issue_tickets.py index 8fad3747..a1c0e903 100755 --- a/hammer/reporting-remediation/reporting/create_s3bucket_acl_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_s3bucket_acl_issue_tickets.py @@ -107,11 +107,13 @@ def create_tickets_s3buckets(self): issue_summary = (f"S3 bucket '{bucket_name}' with public acl " f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"Bucket ACL allows unrestricted public access.\n\n" f"*Threat*: " f"This creates potential security vulnerabilities by allowing anyone to add, modify, or remove items in a bucket.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*S3 Bucket name*: {bucket_name}\n" @@ -139,7 +141,7 @@ def create_tickets_s3buckets(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["publics3"], + risk=issue_risk, labels=["publics3"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_s3bucket_policy_issue_tickets.py b/hammer/reporting-remediation/reporting/create_s3bucket_policy_issue_tickets.py index b4411daa..2d439590 100755 --- a/hammer/reporting-remediation/reporting/create_s3bucket_policy_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_s3bucket_policy_issue_tickets.py @@ -111,11 +111,13 @@ def create_tickets_s3buckets(self): issue_summary = (f"S3 bucket '{bucket_name}' with public policy " f"in '{account_name} / {account_id}' account{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"Bucket policy allows unrestricted public access.\n\n" f"*Threat*: " f"This creates potential security vulnerabilities by allowing anyone to add, modify, or remove items in a bucket.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*S3 Bucket name*: {bucket_name}\n" @@ -142,7 +144,7 @@ def create_tickets_s3buckets(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["publics3"], + risk=issue_risk, labels=["publics3"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_security_groups_tickets.py b/hammer/reporting-remediation/reporting/create_security_groups_tickets.py index 3ade7aff..0fd4847f 100755 --- a/hammer/reporting-remediation/reporting/create_security_groups_tickets.py +++ b/hammer/reporting-remediation/reporting/create_security_groups_tickets.py @@ -297,14 +297,7 @@ def create_tickets_securitygroups(self): open_port_details = self.build_open_ports_table_jira(issue.issue_details.perms) - account_details = (f"*Risk*: High\n\n" - f"*Account Name*: {account_name}\n" - f"*Account ID*: {account_id}\n" - f"*SG Name*: {group_name}\n" - f"*SG ID*: {group_id}\n" - f"*Region*: {group_region}\n") - account_details += f"*VPC*: {group_vpc_id}\n\n" if group_vpc_id else "\n" account = Account(id=account_id, name=account_name, @@ -324,6 +317,8 @@ def create_tickets_securitygroups(self): rds_instance_details = elb_instance_details = None + issue_risk = "High" + if ec2_client is not None: ec2_instances = EC2Operations.get_instance_details_of_sg_associated(ec2_client, group_id) sg_instance_details, instance_profile_details,\ @@ -360,7 +355,7 @@ def create_tickets_securitygroups(self): source_description = "allows access from some definite public ip addresses or networks" if sg_public: - priority = "Critical" + issue_risk = 'Critical' summary_status = "Internet" issue_description = (f"Security group has EC2 instances in public subnets " f"with public IP address attached and " @@ -379,7 +374,7 @@ def create_tickets_securitygroups(self): f"critical services.\n" ) elif sg_blind_public: - priority = "Critical" + issue_risk = 'Critical' summary_status = "Internet" issue_description = (f"Security group has EC2 instances in private subnets " f"with public IP address attached and " @@ -393,7 +388,7 @@ def create_tickets_securitygroups(self): f"instances when someone is probing the public IP of the instances. " f"However, there will be no return traffic due to the lack of an IGW.\n") elif not sg_in_use: - priority = "Minor" + issue_risk = 'Medium' summary_status = "Unused" issue_description = (f"Security group has no EC2 instances attached and " f"{source_description} " @@ -404,7 +399,6 @@ def create_tickets_securitygroups(self): f"opportunities for malicious activity (hacking, denial-of-service attacks, " f"loss of data).\n") else: - priority = "Major" summary_status = "Intranet" issue_description = ( f"Security group has EC2 instances in in private subnets and " @@ -418,6 +412,15 @@ def create_tickets_securitygroups(self): tags_table = JiraOperations.build_tags_table(tags) + account_details = (f"*Risk*: {issue_risk}\n\n" + f"*Account Name*: {account_name}\n" + f"*Account ID*: {account_id}\n" + f"*SG Name*: {group_name}\n" + f"*SG ID*: {group_id}\n" + f"*Region*: {group_region}\n") + + account_details += f"*VPC*: {group_vpc_id}\n\n" if group_vpc_id else "\n" + issue_description = ( f"{issue_description}" f"{open_port_details}" @@ -455,7 +458,7 @@ def create_tickets_securitygroups(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority=priority, labels=["insecure-services"], + risk=issue_risk, labels=["insecure-services"], owner=owner, account_id=account_id, bu=bu, product=product, diff --git a/hammer/reporting-remediation/reporting/create_sqs_policy_issue_tickets.py b/hammer/reporting-remediation/reporting/create_sqs_policy_issue_tickets.py index 2f452024..148e6da4 100644 --- a/hammer/reporting-remediation/reporting/create_sqs_policy_issue_tickets.py +++ b/hammer/reporting-remediation/reporting/create_sqs_policy_issue_tickets.py @@ -114,11 +114,13 @@ def create_tickets_sqs_policy(self): f"in '{account_name} / {account_id}' account, '{queue_region}' region" f"{' [' + bu + ']' if bu else ''}") + issue_risk = "High" + issue_description = ( f"Queue policy allows unrestricted public access.\n\n" f"*Threat*: " f"This creates potential security vulnerabilities by allowing anyone to add, modify, or remove items in a SQS.\n\n" - f"*Risk*: High\n\n" + f"*Risk*: {issue_risk}\n\n" f"*Account Name*: {account_name}\n" f"*Account ID*: {account_id}\n" f"*SQS queue url*: {queue_url}\n" @@ -146,7 +148,7 @@ def create_tickets_sqs_policy(self): try: response = jira.add_issue( issue_summary=issue_summary, issue_description=issue_description, - priority="Major", labels=["publicsqs"], + risk=issue_risk, labels=["publicsqs"], owner=owner, account_id=account_id, bu=bu, product=product,