diff --git a/compendium_v2/publishers/legacy_publisher/survey_publisher_legacy_db.py b/compendium_v2/publishers/legacy_publisher/survey_publisher_legacy_db.py index 4d12a84e01cf8b4a5ed04d3b98becbd49dd1783b..8512f37ab8a57ba991c60fed4cbb0c7472587ece 100644 --- a/compendium_v2/publishers/legacy_publisher/survey_publisher_legacy_db.py +++ b/compendium_v2/publishers/legacy_publisher/survey_publisher_legacy_db.py @@ -6,13 +6,15 @@ This module loads the survey data from 2022 from the old survey database and ret ready to be used to generate new-style surveys. """ -from decimal import Decimal import logging import enum import json import html import itertools +import os +import csv +from decimal import Decimal from sqlalchemy import text from collections import defaultdict @@ -88,6 +90,8 @@ RECURSIVE_QUERY = """ ORDER BY n.id, answers.question_id, answers.updated_at DESC; """ +SECURITY_CONTROLS_CSV = os.path.join(os.path.dirname(__file__), "../../resources/security_controls_parsed.csv") + class FundingSource(enum.Enum): CLIENT_INSTITUTIONS = 16405 @@ -690,11 +694,11 @@ def security_controls(nren_dict): if year < 2021: # prior to 2022, the mapping is different, use a different data source continue - # TODO: import the pre-2022 data from a handmade CSV. - if nren_name not in nren_dict: continue + nren = nren_dict[nren_name] + full_list = sc.get((nren_name, year), []) other_entries = [e.strip() for e in sc_other.get((nren_name, year), []) if e.strip() and e.lower() not in ["n/a", "-"]] @@ -709,9 +713,35 @@ def security_controls(nren_dict): if other_entry: full_list.append('other') - yield ('security_controls', nren_dict[nren_name], nren_dict[nren_name].id, year, full_list) + yield ('security_controls', nren, nren.id, year, full_list) if other_entry: - yield ('security_controls-Comment', nren_dict[nren_name], nren_dict[nren_name].id, year, other_entry) + yield ('security_controls-Comment', nren, nren.id, year, other_entry) + + # pop on data manually fixed from free-text fields for <2021 + with open(SECURITY_CONTROLS_CSV, 'r') as f: + reader = csv.DictReader(f) + for row in reader: + nren_name = row['nren'].upper() + year = int(row['year']) + if nren_name not in nren_dict: + continue + + nren = nren_dict[nren_name] + + controls = {**row} + del controls['nren'] + del controls['year'] + + other = '' + if controls.get('other'): + other = controls['other'].strip() + del controls['other'] + + controls_for_year = [k for k, v in controls.items() if v] + + yield ('security_controls', nren, nren.id, year, controls_for_year) + if other: + yield ('security_controls-Comment', nren, nren.id, year, other) def institutions_urls(nren_dict): diff --git a/compendium_v2/publishers/survey_publisher_legacy_excel.py b/compendium_v2/publishers/survey_publisher_legacy_excel.py index c73ef1aff54c14256539e06161df9a0be90cd004..d9bb2a604b06089bdf69f0effa1e70acbe50ecc6 100644 --- a/compendium_v2/publishers/survey_publisher_legacy_excel.py +++ b/compendium_v2/publishers/survey_publisher_legacy_excel.py @@ -12,6 +12,8 @@ import itertools import logging import math import click +import os +import csv from sqlalchemy import select, delete from collections import defaultdict @@ -27,6 +29,8 @@ setup_logging() logger = logging.getLogger('survey-publisher-legacy-excel') +SECURITY_CONTROLS_CSV = os.path.join(os.path.dirname(__file__), "../resources/security_controls_parsed.csv") + def db_budget_migration(nren_dict): # move data from Survey DB budget table @@ -595,6 +599,42 @@ def db_ops_automation_migration(nren_dict): db.session.commit() +def security_controls_migration(nren_dict): + db.session.execute(delete(presentation_models.SecurityControls).where( + presentation_models.SecurityControls.year < 2021)) + + # pop on data manually fixed from free-text fields + with open(SECURITY_CONTROLS_CSV, 'r') as f: + reader = csv.DictReader(f) + for row in reader: + nren_name = row['nren'].upper() + year = int(row['year']) + if nren_name not in nren_dict: + continue + + nren = nren_dict[nren_name] + + controls = {**row} + del controls['nren'] + del controls['year'] + + other = '' + if controls.get('other'): + other = controls['other'].strip() + del controls['other'] + + controls_for_year = [k for k, v in controls.items() if v] + + new_entry = presentation_models.SecurityControls( + nren=nren, + nren_id=nren.id, + year=year, + security_control_descriptions=[*controls_for_year, other] if other else controls_for_year + ) + db.session.merge(new_entry) + db.session.commit() + + def _cli(app): with app.app_context(): nren_dict = helpers.get_uppercase_nren_dict() @@ -620,6 +660,7 @@ def _cli(app): db_capacity_migration(nren_dict) db_non_r_e_peers_migration(nren_dict) db_ops_automation_migration(nren_dict) + security_controls_migration(nren_dict) @click.command() diff --git a/compendium_v2/resources/security_controls_parsed.csv b/compendium_v2/resources/security_controls_parsed.csv new file mode 100644 index 0000000000000000000000000000000000000000..dfb080bf50377f6932c331bf8c3c9eb18f43044b --- /dev/null +++ b/compendium_v2/resources/security_controls_parsed.csv @@ -0,0 +1,117 @@ +"nren","year","anti_virus","anti_spam","firewall","ddos_mitigation","monitoring","ips_ids","acl","segmentation","integrity_checking","other" +"ACONET",2017,,,1,1,,,,,, +"ACONET",2018,,,1,1,,,,,, +"ACONET",2019,,,1,1,,,,,, +"ACONET",2020,,,1,,,,,,, +"BELNET",2018,1,1,1,,,,1,,1,"version management" +"BELNET",2019,1,1,1,1,,,1,,1,"version management" +"BELNET",2020,,,1,1,,,,,,"Anti-malware, vulnerability management" +"CARNET",2017,1,,1,1,,,1,,, +"CARNET",2018,1,,1,1,,,1,,, +"CARNET",2019,1,,1,1,,,1,,, +"CARNET",2020,1,,1,,,,1,,, +"CYNET",2020,,,,,,1,,,,"Endpoint security" +"CESNET",2016,,,,,,,,,,"Not a public information." +"CESNET",2017,1,1,1,,,1,,,,"active monitoring, honeypots" +"CESNET",2018,1,1,1,,,1,,,,"active monitoring, honeypots, Rate-limiting, RTBH filtering (BGP community)" +"CESNET",2019,1,1,1,,,1,,,,"active monitoring, honeypots, Rate-limiting, RTBH filtering, Flowspec, RPKI - BGP zone signed, DDoS Protector (in-house research)" +"CESNET",2020,,,,,,,,,,"Regular penetration testing of the infrastructure, Monitoring and application of FlowSpec, rate-limiting, RTBH communities etc." +"DEIC",2016,,1,,,,,,,, +"DEIC",2017,,1,,,,,,,, +"DEIC",2018,1,1,1,,,,,,, +"DEIC",2020,,,1,,,1,1,,,"log analysis" +"EENET",2016,1,,,,,,,,, +"EENET",2017,1,,,,,,,,, +"EENET",2018,1,,1,,,,,,, +"EENET",2019,1,,1,,,,,,, +"FUNET",2017,,,,,,,,,, +"FUNET",2018,,,,,,,,,, +"FUNET",2019,,,,,,,,,, +"FUNET",2020,,,,,,,,,, +"RENATER",2016,1,,1,,,,,,1, +"RENATER",2018,1,,1,,,,,,1,"anti-malware. All servers are behind at least one firewall, two firewalls if they are back-office servers" +"RENATER",2019,1,,1,,,,,,1,"anti-malware. All servers are behind at least one firewall, two firewalls if they are back-office servers" +"MARNET",2018,,,1,,,,,,, +"MARNET",2019,,,1,,,,,,, +"GRENA",2016,1,,1,,,,,,, +"GRENA",2017,1,,1,,,,,,, +"GRENA",2018,1,1,1,,,,,,, +"GRENA",2019,1,1,1,1,,,,,, +"GRENA",2020,1,1,1,1,,,,,, +"DFN",2018,1,1,1,,,,,,1, +"DFN",2019,1,1,1,,,,,,1, +"DFN",2020,1,,1,,,,,,1,"VPN, Strong Password, server root-kit detection, 4-eyes-principle for changes" +"GRNET S.A.",2020,1,,1,,,1,,,,"PeakFlow DDoS monitoring" +"KIFU",2016,1,,,,,,,,, +"KIFU",2017,1,,,,,,,,, +"KIFU",2018,1,,,,,,,,, +"KIFU",2019,1,,,,,,,,, +"KIFU",2020,1,,1,,,,,,1, +"HEANET",2017,1,,1,,,,1,1,, +"HEANET",2018,1,,1,,,,1,1,, +"HEANET",2019,1,,,,,,1,1,,"Flowspec" +"HEANET",2020,,,1,,,,1,,, +"IUCC",2018,,,,,,,,,,"WAF" +"IUCC",2019,1,,,,,,,,,"WAF" +"IUCC",2020,1,,1,,,,,,, +"GARR",2017,1,,,,,,1,,, +"GARR",2018,1,,,,,,1,,, +"GARR",2019,1,,,,,,1,,, +"GARR",2020,1,1,,,,,1,,, +"LITNET",2018,1,1,,,,,,,, +"LITNET",2019,1,1,1,,,,1,,, +"LITNET",2020,,,1,,,,,,,"Next generation end point protection Forti-client, Integrated security, performance, and availability monitoring FortiSIEM, Windows Defender" +"RESTENA",2016,,,,,,,,,, +"RENAM",2018,,,,,,,,,, +"RENAM",2019,,,,,,,,,, +"SURF",2016,1,,1,,,,,,,"device encryption, mail encryption" +"SURF",2017,1,,1,,,,,,,"device encryption, mail encryption" +"SURF",2018,1,,1,,,,,,,"device encryption, mail encryption" +"SURF",2019,1,,1,,,,,,,"device encryption, mail encryption" +"PIONIER",2016,1,,1,,,,,,, +"PIONIER",2017,1,,1,,,,,,, +"PIONIER",2018,1,,1,,,,,,, +"PIONIER",2019,1,,1,,,,,,, +"PIONIER",2020,,,,,,1,,,,"VPNs" +"FCCN",2016,1,,,,,,,,," Network analyzer" +"FCCN",2017,1,,,,,,,,,"Network analyzer" +"FCCN",2018,1,,,,,,,,,"Network analyzer" +"FCCN",2019,1,,1,,,1,,,,"Network analyzer" +"FCCN",2020,1,,1,,,,,,,"VPN" +"SANET",2017,1,,,,,,,,, +"SANET",2018,1,,,,,,,,, +"SANET",2019,1,,,,,,,,, +"ARNES",2016,1,,,,,,,,, +"ARNES",2017,1,,,,,,,,, +"ARNES",2018,1,,,,,,,,, +"ARNES",2019,1,,,,,,,,, +"REDIRIS",2016,1,,1,,,,,,, +"REDIRIS",2019,1,,1,,,,,,, +"SWITCH",2016,1,,1,,,,,,, +"SWITCH",2017,1,,1,,1,,,,,"Log Management" +"SWITCH",2018,1,,1,,1,,,,,"Log Management" +"SWITCH",2019,1,,1,,1,,,,,"Log Management" +"ULAKBIM",2017,,,1,,,,,,, +"ULAKBIM",2018,,,1,,,,,,, +"ULAKBIM",2019,,,1,,,,,,, +"URAN",2020,,,,,,,,,,"RIPE RPKI validation tool" +"JISC",2018,1,,1,,,,,,,"DLP, MFA, SAML, DMARC, netflow, flowspec" +"JISC",2019,1,,1,,,,,,,"DLP, MFA, SAML, DMARC, netflow, flowspec, RPZ, STIX/TAXI, MFA" +"AMRES",2018,1,,1,,,,1,,,"web content filtering" +"AMRES",2019,1,,1,,,,1,,,"web content filtering" +"AMRES",2020,1,,1,1,,,,,, +"AZSCIENCENET",2016,1,,,,,,,,, +"AZSCIENCENET",2017,1,,,,,,,,, +"AZSCIENCENET",2018,1,,1,,,,,,, +"AZSCIENCENET",2019,,,1,,,,,,,"own authentication system, traffic log system, monitoring system" +"LAT",2019,,,,1,,,,,, +"ROEDUNET",2020,1,,1,,,1,,,, +"BASNET",2016,1,,,,,,,,1, +"BASNET",2017,1,,,,,,,,1, +"BASNET",2018,1,,1,,,,,,1, +"BASNET",2019,1,,1,,,,,,1, +"MREN",2020,,,1,,,,,,, +"ASNET-AM",2016,1,,,,,,,,, +"ASNET-AM",2017,1,,,,,,,,, +"ASNET-AM",2018,1,,,,,,,,, +"ASNET-AM",2019,1,1,1,,,,,,,