Skip to content

Commit

Permalink
Merge branch 'main' of github.com:minvws/nl-kat-coordination into fix…
Browse files Browse the repository at this point in the history
…/multi-report
  • Loading branch information
Rieven committed Oct 30, 2024
2 parents ca4f7bd + 1c08cde commit c80e644
Show file tree
Hide file tree
Showing 19 changed files with 92 additions and 47 deletions.
Binary file modified docs/source/manual/img/boefjeinfopage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/source/manual/img/crisisroom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/source/manual/img/findings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/source/manual/img/katalogus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/manual/img/mutedfindings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 37 additions & 14 deletions docs/source/manual/user-manual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
User Guide
==========

This manual covers the day-to-day use of OpenKAT via the web interface. The concepts behind OpenKAT are explained in the "How does OpenKAT work" section. When using OpenKAT for the first time, the on-boarding flow is available, see the section in this chapter.
This manual covers the day-to-day use of OpenKAT via the web interface. The concepts behind OpenKAT are explained in the "How does OpenKAT work" section. When using OpenKAT for the first time, the onboarding flow is available, see the section in this chapter.

Web interface
=============

The user interface of OpenKAT consists of five screens, which provide access to the information and main functions of the system:
The web interface of OpenKAT consists of the screens, which provide access to the information and main functions of the system:

- Crisis Room (main)
- KAT catalog
- Crisis Room (overview page)
- KAT-alog (catalog)
- Findings
- Reports
- Objects
- Tasks
- Members
Expand All @@ -20,37 +21,59 @@ The user interface of OpenKAT consists of five screens, which provide access to
Crisis Room
-----------

The Crisis Room provides the overview of all findings, which can be viewed for different times. The time of day can be selected with the option button after which the findings that were applicable at that time become visible.
The Crisis Room gives an overview of findings for, which can be viewed for different moments in time. The date can be selected and the crisis room will provide an overview for that moment in time. Crisis rooms are available for:

- all organizations (the user has access to)
- each single organization (the user has access to)

The crisis room for all organizations shows which organizations you have access to and how many findings per severity are found. The screenshot below shows that there is one organization called Purr.

.. image:: img/crisisroom.png
:alt: crisisroom
:alt: Crisisroom for all organizations

The crisis room for a single organization.

.. image:: img/crisisroom-organization.png
:alt: Crisisroom single organization


KAT catalog
KAT-alog
-----------

The KAT catalog contains all the tools that this instance of KAT has access to, all the boefjes and normalizers. Click on a boefje for more information, such as the objects it can search for.
The KAT catalog is the place where you can see which tools are available, enabled and/or disabled. Tools can be common security scanning tools, like nmap (checks which ports are open), or specific tools that check for a CVE vulnerability. The KAT catalog also contains all the normalizers, which parse the data from the tools. Each boefje and normalizer contains more information on how it works and what is required, including the objects it can search for, and which are required for the boefje to work.

Boefjes can be deployed automatically or manually. New boefjes can be added by the administrator, either locally or by adding an external KAT catalog in Rocky's config file.
Before a boefje or normalizer can run the following two conditions must be met:
- The boefje and corresponding normalizer are enabled. Note: all normalizers are enabled by default.
- The clearance level of your object (e.g. hostname or URL) is similar or higher than the required scan level of the enabled boefje.

Automatic deployment of boefjes depends on the safeguard level, which can be set for each object. If no safeguard is set, it can be derived from a logically connected object for which it is.
New boefjes can be added by an administrator in the web interface, or by manually adding an external KAT catalog in the Rocky's config ile.

.. image:: img/katalogus.png
:alt: KAT catalog

Each boefje has an info page with information about the tools used, the associated objects and the safeguard level required to use the boefje.
Each boefje has an details page with information about the tool, the scan level and additional settings that can be given to the boefje. It also gives an overview on the required objects before the boefje can run ("Consumes") and which output objects are created ("Produces"). The details page also gives an overview of all associated tasks and which objects match the clearance level.

.. image:: img/boefjeinfopage.png
:alt: Findings
:alt: Boefje information page

Findings
--------

The findings made by KAT can be seen on the Findings page. Use the filters to select the findings. Click on the finding for more information or to generate a report on this finding.
The findings page gives an overview of all findings found by KAT. The filter section can be used to apply various filters to show specific findings (e.g. critical findings only) and/or hosts. The search bar can be used to search for specific findings or hosts. Clicking on a finding shows more information on this finding. Each finding can be viewed in the tree or graph by clicking the corresponding icons behind the finding.

A finding is also an object in the data model. This simply means that the finding can also be found on the Objects page.

.. image:: img/findings.png
:alt: Findings

A finding is also an object in the data model, and can also be found on the objects page.
Muted findings
--------------
Findings can be muted until a specific date. This will prevent the finding(s) from showing up in the default view. Using the filters you can show all muted findings, or both muted and non-muted findings.

One or more findings can be selected. The textbox at the bottom allows for a description as to why this finding is muted (e.g. for audit purposes, or for review at a later point in time). Below the textbox the expiry date for the selected findings can be provided. Click the button 'Mute Findings' to mute the selected findings.

.. image:: img/mutedfindings.png
:alt: Mute findings


Objects
Expand Down
12 changes: 7 additions & 5 deletions octopoes/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions octopoes/requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
Expand All @@ -584,7 +585,8 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \
--hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6
requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972
--hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 \
--hash=sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf
requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
Expand Down Expand Up @@ -777,9 +779,9 @@ uvicorn==0.29.0 ; python_version >= "3.10" and python_version < "4.0" \
vine==5.1.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc \
--hash=sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0
waitress==3.0.0 ; python_version >= "3.10" and python_version < "4" \
--hash=sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1 \
--hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669
waitress==3.0.1 ; python_version >= "3.10" and python_version < "4" \
--hash=sha256:26cdbc593093a15119351690752c99adc13cbc6786d75f7b6341d1234a3730ac \
--hash=sha256:ef0c1f020d9f12a515c4ec65c07920a702613afcad1dbfdc3bcec256b6c072b3
wcwidth==0.2.13 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
Expand Down
4 changes: 3 additions & 1 deletion octopoes/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
Expand All @@ -498,7 +499,8 @@ referencing==0.35.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:191e936b0c696d0af17ad7430a3dc68e88bc11be6514f4757dc890f04ab05889 \
--hash=sha256:8080727b30e364e5783152903672df9b6b091c926a146a759080b62ca3126cd6
requests-file==2.0.0 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972
--hash=sha256:20c5931629c558fda566cacc10cfe2cd502433e628f568c34c80d96a0cc95972 \
--hash=sha256:3e493d390adb44aa102ebea827a48717336d5268968c370eaf19abaf5cae13bf
requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0" \
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
Expand Down
4 changes: 2 additions & 2 deletions rocky/reports/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ class CustomReportScheduleForm(BaseRockyForm):

class ParentReportNameForm(BaseRockyForm):
parent_report_name = forms.CharField(
label=_("Report name format"), required=False, initial="{report type} for {oois_count} objects"
label=_("Report name format"), required=False, initial="${report_type} for ${oois_count} objects"
)


class ChildReportNameForm(BaseRockyForm):
child_report_name = forms.CharField(
label=_("Subreports name format"), required=True, initial="{report type} for {ooi}"
label=_("Subreports name format"), required=True, initial="${report_type} for ${ooi}"
)


Expand Down
27 changes: 19 additions & 8 deletions rocky/reports/runner/report_runner.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime, timezone
from string import Template

from django.conf import settings
from tools.models import Organization
Expand Down Expand Up @@ -30,18 +31,28 @@ def run(self, report_task: ReportTask) -> None:
)

self.bytes_client.organization = report_task.organisation_id
report_names = []
oois_count = 0
subreport_names = []
oois_count = len(recipe.input_recipe["input_oois"])

for report_type_id, data in report_data.items():
oois_count += len(data)
report_type = get_report_by_id(report_type_id)

for ooi in data:
report_name = recipe.subreport_name_format.replace("{ooi}", ooi).replace(
"{report type}", str(report_type.name)
ooi_human_readable = Reference.from_str(ooi).human_readable
subreport_name = Template(recipe.subreport_name_format).safe_substitute(
ooi=ooi_human_readable, report_type=str(report_type.name)
)
report_names.append((report_name, report_name))
subreport_names.append((subreport_name, subreport_name))

parent_report_name = Template(recipe.report_name_format).safe_substitute(oois_count=str(oois_count))

if "${ooi}" in parent_report_name and oois_count == 1:
ooi = recipe.input_recipe["input_oois"][0]
ooi_human_readable = Reference.from_str(ooi).human_readable
parent_report_name = Template(parent_report_name).safe_substitute(ooi=ooi_human_readable)
if "${report_type}" in parent_report_name and len(report_types) == 1:
report_type = get_report_by_id(recipe.report_types[0])
parent_report_name = Template(parent_report_name).safe_substitute(report_type=str(report_type.name))

save_report_data(
self.bytes_client,
Expand All @@ -56,8 +67,8 @@ def run(self, report_task: ReportTask) -> None:
}
},
report_data,
report_names,
recipe.report_name_format.replace("{oois_count}", str(oois_count)),
subreport_names,
parent_report_name,
)

self.bytes_client.organization = None
6 changes: 3 additions & 3 deletions rocky/reports/templates/partials/report_names_header.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ <h2>{% translate "Report name" %}</h2>
{% blocktranslate trimmed %}
To make the report names more descriptive, you can include placeholders for the
object name, the report type and/or the reference date. For subreports and reports over a single object,
use the placeholder "{ooi}" for the object name, "{report type}" for the report type and use a
use the placeholder "${ooi}" for the object name, "${report_type}" for the report type and use a
<a href="https://strftime.org/" target="_blank" rel="noopener">Python strftime code</a> for the reference
date. For reports over multiple objects, use "{oois_count}" for the number of objects in the report.
date. For reports over multiple objects, use "${oois_count}" for the number of objects in the report.
{% endblocktranslate %}
</p>
<p>
{% blocktranslate trimmed %}
For example, the format "{report type} for {ooi} at %x" could generate:
For example, the format "${report_type} for ${ooi} at %x" could generate:
"DNS Report for example.com at 01/01/25".
{% endblocktranslate %}
</p>
Expand Down
3 changes: 2 additions & 1 deletion rocky/reports/views/aggregate_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView

from reports.report_types.aggregate_organisation_report.report import AggregateOrganisationReport
from reports.views.base import (
Expand Down Expand Up @@ -68,7 +69,7 @@ def get_context_data(self, **kwargs):


class ReportTypesSelectionAggregateReportView(
AggregateReportStepsMixin, BreadcrumbsAggregateReportView, ReportTypeSelectionView
AggregateReportStepsMixin, BreadcrumbsAggregateReportView, ReportTypeSelectionView, TemplateView
):
"""
Shows all possible report types from a list of Objects.
Expand Down
2 changes: 1 addition & 1 deletion rocky/reports/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def get_context_data(self, **kwargs):
return context


class ReportTypeSelectionView(BaseReportView, ReportBreadcrumbs, TemplateView):
class ReportTypeSelectionView(BaseReportView, ReportBreadcrumbs):
"""
Shows report types and handles selections and requests.
"""
Expand Down
3 changes: 2 additions & 1 deletion rocky/reports/views/generate_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView

from reports.views.base import (
REPORTS_PRE_SELECTION,
Expand Down Expand Up @@ -66,7 +67,7 @@ def get_context_data(self, **kwargs):


class ReportTypesSelectionGenerateReportView(
GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportTypeSelectionView
GenerateReportStepsMixin, BreadcrumbsGenerateReportView, ReportTypeSelectionView, TemplateView
):
"""
Shows all possible report types from a list of OOIs.
Expand Down
6 changes: 3 additions & 3 deletions rocky/reports/views/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def save_report_data(
raw_id = bytes_client.upload_raw(
raw=ReportDataDict(input_data).model_dump_json().encode(), manual_mime_types={"openkat/report"}
)
name = now.strftime(parent_report_name.replace("{report type}", str(ConcatenatedReport.name)))
name = now.strftime(parent_report_name.replace("${report_type}", str(ConcatenatedReport.name)))

if not name or name.isspace():
name = ConcatenatedReport.name
Expand Down Expand Up @@ -164,7 +164,7 @@ def save_report_data(
manual_mime_types={"openkat/report"},
)
report_type = get_report_by_id(report_type_id)
name = now.strftime(parent_report_name.replace("{report type}", str(report_type.name)))
name = now.strftime(parent_report_name.replace("${report_type}", str(report_type.name)))

if not name or name.isspace():
name = ConcatenatedReport.name
Expand Down Expand Up @@ -206,7 +206,7 @@ def save_report(self, report_names: list) -> Report | None:
self.get_input_data(),
report_data,
report_names,
report_names[0][0],
report_names[0][1],
)

# If OOI could not be found or the date is incorrect, it will be shown to the user as a message error
Expand Down
5 changes: 4 additions & 1 deletion rocky/reports/views/multi_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView

from reports.report_types.multi_organization_report.report import MultiOrganizationReport
from reports.views.base import (
Expand Down Expand Up @@ -58,7 +59,9 @@ class OOISelectionMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportV
report_type = MultiOrganizationReport


class ReportTypesSelectionMultiReportView(MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportTypeSelectionView):
class ReportTypesSelectionMultiReportView(
MultiReportStepsMixin, BreadcrumbsMultiReportView, ReportTypeSelectionView, TemplateView
):
"""
Shows all possible report types from a list of OOIs.
Chooses report types for the 'Multi Report' flow.
Expand Down
Loading

0 comments on commit c80e644

Please sign in to comment.