def test_ports_ingress_open(): app.dummy_data = AUDIT load_route_services() try: client = app.utilities.get_class_by_name( "chalicelib.criteria.aws_ec2_security_group_ingress_open.AwsEc2SecurityGroupIngressOpen" ) ec2 = client(app) env = os.environ["CSW_ENV"] session = ec2.get_session(account="103495720024", role=f"csw-{env}_CstSecurityInspectorRole") params = {"region": "eu-west-1"} groups = ec2.get_data(session, **params) for group in groups: compliance = ec2.evaluate({}, group, []) app.log.debug(app.utilities.to_json(compliance)) group["resource_compliance"] = compliance summary = ec2.summarize(groups) template_data = app.dummy_data["audits"][0] template_data["criteria"][0]["compliance_results"] = groups template_data["criteria"][0]["compliance_summary"] = summary template_data["criteria"][0]["tested"] = True response = app.templates.render_authorized_template( "test_evaluation.html", app.current_request, template_data) except Exception as err: response = {"body": str(err)} return Response(**response)
def demo_audit_report(id): app.dummy_data = AUDIT load_route_services() app.templates = TemplateHandler(app) response = app.templates.render_authorized_template( "audit.html", app.current_request, app.dummy_data["audits"][0]) return Response(**response)
def test_ports_ingress_ssh(): app.dummy_data = AUDIT load_route_services() try: client = app.utilities.get_class_by_name( "chalicelib.criteria.aws_ec2_security_group_ingress_ssh.AwsEc2SecurityGroupIngressSsh" ) ec2 = client(app) env = os.environ["CSW_ENV"] session = ec2.get_session(account="103495720024", role=f"csw-{env}_CstSecurityInspectorRole") region = "eu-west-1" groups = ec2.get_data(session, **{"region": region}) for group in groups: compliance = ec2.evaluate({}, group, []) app.log.debug(app.utilities.to_json(compliance)) group["resource_compliance"] = compliance group["status"] = models.Status.get_by_id(compliance["status_id"]) group["resource_name"] = group["GroupName"] group["resource_id"] = group["GroupId"] group["region"] = region summary = ec2.summarize(groups) template_data = { "criterion": models.Criterion.get_by_id(1).serialize(), "compliance_summary": summary, "compliance_results": groups, "tested": True, } response = app.templates.render_authorized_template( "test_evaluation.html", app.current_request, template_data) except Exception as err: response = {"body": str(err)} return Response(**response)
def route_api_monthly_delta(): """ Comparison last month vs this month to show change over time """ status_code = 200 try: load_route_services() authed = app.auth.try_login(app.current_request) if authed: monthly_deltas = models.MonthlyDeltaStats.select().order_by( models.MonthlyDeltaStats.audit_year.desc(), models.MonthlyDeltaStats.audit_month.desc(), ) items = models.MonthlySummaryStats.serialize_list(monthly_deltas) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def route_api_daily_account(): """ List of stats of the last audits for each account for each day in a given time period """ status_code = 200 try: days = 14 now = datetime.datetime.now() days_ago = now - datetime.timedelta(days=days) load_route_services() authed = app.auth.try_login(app.current_request) if authed: daily_account = ( models.DailyAccountStats.select() .where(models.DailyAccountStats.audit_date > days_ago) .order_by(models.DailyAccountStats.audit_date.desc()) ) items = models.DailyAccountStats.serialize_list(daily_account) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def route_api_daily_delta(): """ Comparison yesterday to today looking for what's changed """ status_code = 200 try: days = 14 now = datetime.datetime.now() days_ago = now - datetime.timedelta(days=days) load_route_services() authed = app.auth.try_login(app.current_request) if authed: daily_summary = ( models.DailyDeltaStats.select() .where(models.DailyDeltaStats.audit_date > days_ago) .order_by(models.DailyDeltaStats.audit_date.desc()) ) items = models.DailyDeltaStats.serialize_list(daily_summary) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def route_api_monthly_summary(): """ Average monthly summary to identify longer term trends """ status_code = 200 try: load_route_services() authed = app.auth.try_login(app.current_request) if authed: monthly_summary = models.MonthlySummaryStats.select().order_by( models.MonthlySummaryStats.audit_year.desc(), models.MonthlySummaryStats.audit_month.desc(), ) items = models.MonthlySummaryStats.serialize_list(monthly_summary) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def route_api_daily_summary(): """ Last 2 weeks summary across all accounts day by day to identify short-term trends """ status_code = 200 try: days = 14 now = datetime.datetime.now() days_ago = now - datetime.timedelta(days=days) load_route_services() authed = app.auth.try_login(app.current_request) if authed: daily_summary = ( models.DailySummaryStats.select() .where(models.DailySummaryStats.audit_date > days_ago) .order_by(models.DailySummaryStats.audit_date.desc()) ) items = models.DailySummaryStats.serialize_list(daily_summary) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def route_api_current_accounts(): """ Per account summary of latest audit results """ status_code = 200 try: load_route_services() authed = app.auth.try_login(app.current_request) if authed: current_accounts = models.CurrentAccountStats.select() items = models.CurrentAccountStats.serialize_list(current_accounts) data = {"status": "ok", "items": items} else: raise Exception("Unauthorised") except Exception as err: status_code = 403 data = {"status": "failed", "message": str(err)} json = app.utilities.to_json(data, True) response = { "body": json, "status_code": status_code, "headers": {"Content-Type": "application/json"}, } return Response(**response)
def audit_check_allow_list(id, check_id): """ Allows you to create and update allow list records for checks like SSH ingress where you want to be able to customise the list of acceptable IP/CIDRs """ account_id = int(id) check_id = int(check_id) try: load_route_services() authed = app.auth.try_login(app.current_request) if authed: user_data = app.auth.get_login_data() user = models.User.find_active_by_email(user_data["email"]) # Get most recent evaluation of criterion for this account audit_criterion = (models.AuditCriterion.select().join( models.AccountAudit).where( models.AuditCriterion.criterion_id == check_id, models.AuditCriterion.account_audit_id. account_subscription_id == account_id, ).order_by(models.AuditCriterion.id.desc()).get()) audit_criterion.serialize() # CheckClass = app.utilities.get_class_by_name(audit_criterion.criterion_id.invoke_class_name) # check = CheckClass(app) form = FormControllerAddAllowListException() form.set_user(user) defaults = form.get_model_defaults( account_subscription_id=audit_criterion.account_audit_id. account_subscription_id) allowed = form.get_allowlist( audit_criterion.account_audit_id.account_subscription_id) # defaults = check.AllowlistClass.get_defaults(account_id, user.id) template_data = { "audit_criterion": audit_criterion.serialize(), "allowlist": allowed, "exception": defaults, "errors": {}, } # json = app.utilities.to_json(template_data, True) response = app.templates.render_authorized_template( "account_check_allowlist.html", app.current_request, template_data) else: response = app.templates.render_authorized_template( "denied.html", app.current_request) except Exception as err: app.log.error("Route: check allowlist error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def account_issues(id): account_id = int(id) # TODO - add check user has access to account team load_route_services() try: account = models.AccountSubscription.get_by_id(account_id) latest = account.get_latest_audit() team = account.product_team_id if latest is not None: issues_list = latest.get_issues_list() template_data = { "breadcrumbs": [ {"title": "My teams", "link": "/team"}, {"title": team.team_name, "link": f"/team/{team.id}/status"}, ], "audit": latest.serialize(), "issues": issues_list, } response = app.templates.render_authorized_template( "audit_issues.html", app.current_request, template_data, [account] ) else: raise Exception(f"No latest audit for account: {account_id}") except Exception as err: app.log.error("Route: account issues error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def my_exceptions(): """ Page to view list of excepted resources and rule allowlists Should allow a customisation to be expired. :return: """ load_route_services() try: authed = app.auth.try_login(app.current_request) if authed: user_data = app.auth.get_login_data() user = models.User.find_active_by_email(user_data["email"]) exceptions = user.get_my_exceptions() allowlists = user.get_my_allowlists() else: exceptions = [] allowlists = [] response = app.templates.render_authorized_template( "my_exceptions.html", app.current_request, {"exceptions": exceptions, "allowlists": allowlists}, ) except Exception as err: app.log.error("Route: exception error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def logout(): load_route_services() return Response( **app.templates.render_authorized_template( "logged_out.html", app.current_request ) )
def team_list(): load_route_services() try: max_severity = get_query_param(app.current_request, "max_severity", 1) authed = app.auth.try_login(app.current_request) if authed: user_data = app.auth.get_login_data() user = models.User.find_active_by_email(user_data["email"]) teams = user.get_my_teams() else: teams = [] # teams = models.ProductTeam.select().where(models.ProductTeam.active == True) team_list = [] for team in teams: team_stats = team.get_team_stats(max_severity) team_data = {"team": team.serialize(), "summary": team_stats} team_list.append(team_data) template_data = {"teams": team_list} response = app.templates.render_authorized_template( "teams.html", app.current_request, template_data ) except Exception as err: app.log.error("Route: team error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def account_history(id): account_id = int(id) # TODO - add check user has access to account team load_route_services() try: account = models.AccountSubscription.get_by_id(account_id) team = account.product_team_id audit_history = account.get_audit_history() history_data = [] for audit in audit_history: audit_stats = audit.get_stats() history_data.append({"audit": audit.serialize(), "stats": audit_stats}) template_data = { "breadcrumbs": [ {"title": "My teams", "link": "/team"}, {"title": team.team_name, "link": f"/team/{team.id}/status"}, ], "account": account.serialize(), "audit_history": history_data, } response = app.templates.render_authorized_template( "audit_history.html", app.current_request, template_data, [account] ) except Exception as err: app.log.error("Route: account history error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def team_dashboard(id): team_id = int(id) # TODO - add check user has access to team load_route_services() try: team = models.ProductTeam.get_by_id(team_id) app.log.debug("Team: " + app.utilities.to_json(team)) criteria_stats = models.ProductTeam.get_criteria_stats([team]) app.log.debug("Criteria stats: " + app.utilities.to_json(criteria_stats)) template_data = { "team": team.serialize(), "team_summary": team.get_team_stats(), "criteria_summary": criteria_stats, "failed_resources": team.get_team_failed_resources(), } response = app.templates.render_authorized_template( "team_dashboard.html", app.current_request, template_data, [team] ) except Exception as err: app.log.error("Route: team dashboard error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def statistics_daily_route(): load_route_services() try: template_data = {} template_data["tab"] = "daily" template_data["daily"] = {} days = 14 now = datetime.datetime.now() days_ago = now - datetime.timedelta(days=days) daily_resource_count = ( models.DailyResourceCount.select() .where(models.DailyResourceCount.audit_date > days_ago) .order_by(models.DailyResourceCount.audit_date.desc()) ) template_data["daily"]["resource_status"] = models.DailyResourceCount.serialize_list( daily_resource_count ) response = app.templates.render_authorized_template( "stats.html", app.current_request, template_data ) except Exception as err: app.log.error("Route: check allowlist error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def team_status(id): team_id = int(id) # TODO - add check user has access to team load_route_services() try: max_severity = get_query_param(app.current_request, "max_severity", 1) team = models.ProductTeam.get_by_id(team_id) app.log.debug("Team: " + app.utilities.to_json(team)) team_stats = team.get_team_stats(max_severity) template_data = { "breadcrumbs": [{"title": "My teams", "link": "/team"}], "status": { "accounts_passed": { "display_stat": team_stats["all"]["accounts_passed"], "category": "Accounts Passed", "modifier_class": "passed" if team_stats["all"]["accounts_passed"] > 0 else "failed", }, "accounts_failed": { "display_stat": team_stats["all"]["accounts_failed"], "category": "Accounts Failed", "modifier_class": "passed" if team_stats["all"]["accounts_failed"] == 0 else "failed", }, "accounts_unaudited": { "display_stat": team_stats["all"]["accounts_unaudited"], "category": "Accounts Unaudited", "modifier_class": "passed" if team_stats["all"]["accounts_unaudited"] == 0 else "failed", }, "accounts_inactive": { "display_stat": team_stats["all"]["accounts_inactive"], "category": "Accounts Inactive", "modifier_class": "passed" if team_stats["all"]["accounts_inactive"] == 0 else "failed", }, "issues_found": { "display_stat": team_stats["all"]["issues_found"], "category": "Team Issues", "modifier_class": "passed" if team_stats["all"]["issues_found"] == 0 else "failed", }, }, "team": team.serialize(), "team_summary": team_stats, } response = app.templates.render_authorized_template( "team_status.html", app.current_request, template_data, [team] ) except Exception as err: app.log.error("Route: team status error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def index(): load_route_services() app.log.debug("INDEX CONTEXT = " + str(app.lambda_context)) return Response( **app.templates.render_authorized_template( "logged_in.html", app.current_request ) )
def resource_exception(id): """ Figure out if data has been posted If posted data is valid Return default populated exception if not :param id: :return: """ id = int(id) load_route_services() try: resource = models.AuditResource.get_by_id(id) account = models.AccountSubscription.get_by_id( models.AccountAudit.get_by_id( resource.account_audit_id).account_subscription_id) # TODO - add check user has access to account team compliance = (models.ResourceCompliance.select().join( models.AuditResource).where( models.AuditResource.id == resource.id)).get() exception = models.ResourceException.find_exception( resource.criterion_id.id, resource.resource_persistent_id, account.id) response = app.templates.render_authorized_template( "resource_exception.html", app.current_request, { "team": models.ProductTeam.get_by_id( account.product_team_id).serialize(), "account": account.serialize(), "resource": resource.serialize(), "criterion": models.Criterion.get_by_id(resource.criterion_id).serialize(), "compliance": compliance.serialize(), "exception": exception, "status": models.Status.get_by_id(compliance.status_id).serialize(), "mode": "create", "errors": {}, }, ) except Exception as err: app.log.error("Route: resource exception error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def check_status_resources(id, status): try: load_route_services() check_id = int(id) audit_check = models.AuditCriterion.get_by_id(check_id) audit = audit_check.account_audit_id account = audit.account_subscription_id team = account.product_team_id # TODO - add check user has access to team # TODO - Might be better to keep exceptions separate # I've not done that because they're not identified separately in the audit_criterion stats. if status == "passed": statuses = [2, 4] status = models.Status.get_by_id(2) elif status == "failed": statuses = [3] status = models.Status.get_by_id(3) else: raise Exception(f"Requested status {status} is not valid") resource_list = [] for status_id in statuses: status_list = audit_check.get_status_resources_list(status_id) resource_list = resource_list + status_list CheckClass = app.utilities.get_class_by_name( audit_check.criterion_id.invoke_class_name ) check = CheckClass(app) template_data = { "breadcrumbs": [ {"title": "My teams", "link": "/team"}, {"title": team.team_name, "link": f"/team/{team.id}/status"}, { "title": account.account_name, "link": f"/account/{account.id}/status", }, ], "audit_check": audit_check.serialize(), "resources": resource_list, "status": status, "exception_type": check.exception_type, } response = app.templates.render_authorized_template( "check_status_resources.html", app.current_request, template_data, [account] ) except Exception as err: app.log.error("Route: account issues error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def statistics_route(): load_route_services() try: template_data = {} template_data["tab"] = "about" response = app.templates.render_authorized_template( "stats.html", app.current_request, template_data ) except Exception as err: app.log.error("Route: check allowlist error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def asset_render_qs(): load_route_services() app.log.debug("asset_render function called by /assets?proxy route") try: req = app.current_request app.log.debug(str(req.uri_params)) app.log.debug(json.dumps(app.current_request)) if "proxy" in req.uri_params: proxy = req.uri_params["proxy"] mime_type = app.utilities.get_mime_type(proxy) data = read_asset(proxy) return Response(body=data, status_code=200, headers={"Content-Type": mime_type}) except Exception as e: app.log.debug(str(e)) raise BadRequestError(str(e))
def asset_render(): load_route_services() app.log.debug("asset_render function called by /assets/{proxy+} route") try: local_request = app.current_request app.log.debug("Context: " + str(local_request.context)) app.log.debug("Params: " + str(local_request.uri_params)) if "proxy" in local_request.uri_params: proxy = local_request.uri_params["proxy"] else: proxy = local_request.uri_params["proxy+"] mime_type = app.utilities.get_mime_type(proxy) app.log.debug(f"{proxy} : {mime_type}") data = read_asset(proxy) return Response(body=data, status_code=200, headers={"Content-Type": mime_type}) except Exception as e: app.log.debug(str(e)) raise BadRequestError(str(e))
def temp_login(): try: load_route_services() env = os.environ["CSW_ENV"] headers = {"Content-Type": "text/plain"} body = "Trying login" code = 200 if env != "prod": csw_client = app.auth.get_ssm_parameter( f"/csw/{env}/credentials/tester/client" ) csw_secret = app.auth.get_ssm_parameter( f"/csw/{env}/credentials/tester/secret" ) req = app.current_request qs = req.query_params if ( csw_client != "[disabled]" and csw_client == qs.get("client") and csw_secret == qs.get("secret") ): user = models.User.find_active_by_email(qs.get("email")).serialize() app.auth.user_jwt = app.auth.get_jwt(user) app.auth.cookie = app.auth.generate_cookie_header_val(app.auth.user_jwt) headers["Set-Cookie"] = app.auth.cookie body = "Logged in" else: raise Exception("Unauthorised") except Exception as err: body = "Temporary login failed " + str(err) code = 403 headers = {"Content-Type": "text/plain"} return Response(body=body, headers=headers, status_code=code)
def check_issues(id): try: load_route_services() check_id = int(id) audit_check = models.AuditCriterion.get_by_id(check_id) issues_list = audit_check.get_issues_list() audit = audit_check.account_audit_id account = audit.account_subscription_id team = account.product_team_id # TODO - add check user has access to team CheckClass = app.utilities.get_class_by_name( audit_check.criterion_id.invoke_class_name) check = CheckClass(app) template_data = { "breadcrumbs": [ { "title": "My teams", "link": "/team" }, { "title": team.team_name, "link": f"/team/{team.id}/status" }, { "title": account.account_name, "link": f"/account/{account.id}/status", }, ], "audit_check": audit_check.serialize(), "issues": issues_list, "exception_type": check.exception_type, } response = app.templates.render_authorized_template( "check_issues.html", app.current_request, template_data, [account]) except Exception as err: app.log.error("Route: account issues error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def team_issues(id): team_id = int(id) # TODO - add check user has access to team load_route_services() try: team = models.ProductTeam.get_by_id(team_id) app.log.debug("Team: " + app.utilities.to_json(team)) team_issues = team.get_team_failed_resources() template_data = { "breadcrumbs": [{"title": "My teams", "link": "/team"}], "team": team.serialize(), "account_issues": team_issues, } response = app.templates.render_authorized_template( "team_issues.html", app.current_request, template_data, [team] ) except Exception as err: app.log.error("Route: team issues error: " + str(err)) response = app.templates.default_server_error() return Response(**response)
def test_root_mfa(): load_route_services() try: client = app.utilities.get_class_by_name( "chalicelib.criteria.aws_support_root_mfa.AwsSupportRootMfa") support = client(app) env = os.environ["CSW_ENV"] session = support.get_session( account="103495720024", role=f"csw-{env}_CstSecurityInspectorRole") data = support.get_data(session) criterion = { "id": 3, "criterion_name": "MFA enabled on root user account", "description": "Checks whether the root IAM user associated with the AWS account has Multi Factor Authentication enabled.", "why_is_it_important": "Without MFA it is easier for someone to gain access to your account", "how_do_i_fix_it": "If you have the root credentials for your account enable MFA - otherwise speak to RE", } for item in data: compliance = support.evaluate({}, item, []) app.log.debug(app.utilities.to_json(compliance)) item["resource_compliance"] = compliance status = {} item["status"] = status item.update(support.translate(item)) summary = support.summarize(data) template_data = { "criterion": criterion, "compliance_summary": summary, "compliance_results": data, "tested": True, } response = app.templates.render_authorized_template( "test_evaluation.html", app.current_request, template_data) except Exception as err: response = {"body": str(err)} return Response(**response)
def validate_iam_policy(): load_route_services() try: client = app.utilities.get_class_by_name( "chalicelib.criteria.aws_iam_validate_inspector_policy.AwsIamValidateInspectorPolicy" ) iam = client(app) env = os.environ["CSW_ENV"] session = iam.get_session(account="103495720024", role=f"csw-{env}_CstSecurityInspectorRole") data = iam.get_data(session) criterion = { "id": 4, "criterion_name": "IAM inspector policy is up-to-date", "description": "Checks whether the Cloud Security Watch role matches the current definition.", "why_is_it_important": "If the role policy doesn't grant the right permissions checks will fail to be processed.", "how_do_i_fix_it": "Update the module and re-run the terraform apply to re-deploy the role and policy.", } for item in data: compliance = iam.evaluate({}, item, []) item["resource_compliance"] = compliance status = {} item["status"] = status item.update(iam.translate(item)) summary = iam.summarize(data) template_data = { "criterion": criterion, "compliance_summary": summary, "compliance_results": data, "tested": True, } response = app.templates.render_authorized_template( "test_evaluation.html", app.current_request, template_data) except Exception as err: response = {"body": str(err)} return Response(**response)
def statistics_current_route(): load_route_services() try: template_data = {} template_data["tab"] = "current" template_data["current"] = {} current_summary = models.CurrentSummaryStats.select() template_data["current"]["summary"] = models.CurrentSummaryStats.serialize_list( current_summary ) current_accounts = models.CurrentAccountStats.select() template_data["current"]["account"] = models.CurrentAccountStats.serialize_list( current_accounts ) response = app.templates.render_authorized_template( "stats.html", app.current_request, template_data ) except Exception as err: app.log.error("Route: check allowlist error: " + str(err)) response = app.templates.default_server_error() return Response(**response)