From 375852c87c717331b8c7f5afb76f37e99d2b571a Mon Sep 17 00:00:00 2001 From: Alexey Chuprikov Date: Fri, 9 Aug 2019 19:44:14 +0300 Subject: [PATCH] Add endpoint to import issues to DDB Add new endpoint /import. It takes the list of issues and saves them to appropriate DDB tables. This is just basic functionality. Validation and documentation will be added later. --- .../identification/lambdas/api/authorizer.py | 1 + .../identification/lambdas/api/entrypoint.py | 45 ++++++++++++++++--- hammer/library/ddb_issues.py | 5 ++- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/hammer/identification/lambdas/api/authorizer.py b/hammer/identification/lambdas/api/authorizer.py index 79f3262e..135952f2 100644 --- a/hammer/identification/lambdas/api/authorizer.py +++ b/hammer/identification/lambdas/api/authorizer.py @@ -35,6 +35,7 @@ def lambda_handler(event, context): policy.allowMethod(HttpVerb.GET, full_path) policy.allowMethod(HttpVerb.POST, '/identify') policy.allowMethod(HttpVerb.POST, '/remediate') + policy.allowMethod(HttpVerb.POST, '/import') authResponse = policy.build() diff --git a/hammer/identification/lambdas/api/entrypoint.py b/hammer/identification/lambdas/api/entrypoint.py index a4c0e163..90856d13 100644 --- a/hammer/identification/lambdas/api/entrypoint.py +++ b/hammer/identification/lambdas/api/entrypoint.py @@ -8,7 +8,7 @@ from library.aws.utility import Account, DDB, Sns from library.config import Config -from library.ddb_issues import Operations as IssueOperations +from library.ddb_issues import Issue, IssueStatus, Operations as IssueOperations from library.logger import set_logging from library import utility from responses import bad_request @@ -168,6 +168,35 @@ def get_scan_results(request_id): } +def validate_issues(issues, valid_issue_types): + required_parameters = ['issue_id', 'issue_type', 'account_id', 'issue_details'] + for issue in issues: + for required in required_parameters: + if required not in issue: + raise Exception(f'{required} is required field for issue') + if issue['issue_type'] not in valid_issue_types: + raise Exception(f'{issue["issue_type"]} is not supported issue type') + + +def add_issues(issues): + config = Config() + main_account = Account(region=config.aws.region) + valid_issue_types = [module.section for module in config.modules] + try: + validate_issues(issues, valid_issue_types) + except Exception as e: + return bad_request(text=str(e)) + for issue in issues: + issue_config = config.get_module_config_by_name(issue['issue_type']) + ddb_table = main_account.resource("dynamodb").Table(issue_config.ddb_table_name) + ddb_issue = Issue(issue['account_id'], issue['issue_id'], issue['issue_details']) + ddb_issue.status = IssueStatus.Open + IssueOperations.update(ddb_table, ddb_issue) + return { + 'statusCode': 200, + 'body': 'Successfully imported issues to DDB' + } + @logger def lambda_handler(event, context): try: @@ -177,21 +206,23 @@ def lambda_handler(event, context): logging.exception("failed to parse payload") return bad_request(text="malformed payload") - account_id = payload.get("account_id", None) - regions = payload.get("regions", []) - security_features = payload.get("security_features", []) - tags = payload.get("tags", None) - ids = payload.get("ids", None) - action = event.get("path", "")[1:] method = event.get("httpMethod") # do not forget to allow path in authorizer.py while extending this list if action.startswith('identify'): + account_id = payload.get("account_id", None) + regions = payload.get("regions", []) + security_features = payload.get("security_features", []) + tags = payload.get("tags", None) + ids = payload.get("ids", None) if method == "POST": return start_scan(account_id, regions, security_features, tags, ids) if method == "GET": # get request id from url path request_id = action.split('/')[1] return get_scan_results(request_id) + elif action.startswith('import'): + issues = payload.get('issues', []) + return add_issues(issues) else: return bad_request(text="wrong action") diff --git a/hammer/library/ddb_issues.py b/hammer/library/ddb_issues.py index 06cf1c4b..493d64cb 100755 --- a/hammer/library/ddb_issues.py +++ b/hammer/library/ddb_issues.py @@ -49,7 +49,7 @@ class Issue(object): """ Base class for Hammer security issue. Python representation of DDB item. """ - def __init__(self, account_id, issue_id): + def __init__(self, account_id, issue_id, issue_details=None): # account id where issue was found (HASH key) self.account_id = account_id # issue id, must be uniq in account (RANGE key) @@ -71,7 +71,8 @@ def __init__(self, account_id, issue_id): # issue status self.status = IssueStatus.Open # issue specific details - self.issue_details = Details({}) + details = Details(issue_details) if issue_details else Details({}) + self.issue_details = details # jira specific details self.jira_details = Details({})