terminal = false packages = [ "typing_extensions", "pyyaml", "pandas", "rdflib", "static/d3fendtools-0.0.1-py3-none-any.whl" ] [[fetch]] files = [ "./app.py", "./static/ontology.ttl", "./static/d3fend-short.ttl"]

Design & D3FEND an experimental webapp to support secure architectural design.

Here you can paste your kubernetes manifest file and generate mermaid graphs out of them. Importing a Kubernetes manifest file will only generate a nice mermaid diagram. It is useful for documentation purposes but not for security assessment.

ATT&CK Summary with artifacts and attacks.

att&ck summary placeholder

This is a description of your IT architecture in RDF format. Nodes are described using MITRE categories.

graph placeholder

This is a python console that you can use to inspect and query the semantic graphs `g` and `g1`. Moreover, you can issue SPARQL queries using the `g.query()` method. Currently it does only show the returned value of the last python line, so statements such as print(), while evaluated, are not shown.

d3f = dict(g1.namespaces())["d3f"] nodes = g.query(""" PREFIX d3f: <%s> SELECT ?s WHERE { ?s rdfs:subClassOf+ d3f:DefensiveTechnique . } LIMIT 5 """ % d3f) list(nodes)

    

Intro

This tool shows how to use the D3FEND ontology to support the design and review of IT architectures.

  • The first step is to represent your components and their relationships in a mermaid graph.
  • You can classify your components using font-awesome icons (see the gallery). For example the fa:fa-envelope icon is used to reference is an email.
    Client -->|d3f:Email| MTA
    The application is capable to label major sofware applications (e.g. nginx, postfix, ...) and to map them to the corresponding D3FEND classes (e.g. d3f:MailTransferAgent). You can also use the fab:fa-react icon to indicate that a component is a WebUI.
  • Once you have created your mermaid graph, you can click on the D3FEND tab to see the corresponding D3FEND graph. The D3FEND graph is represented as a turtle file. You can copy and paste it in your favorite RDF editor (e.g. W3C RDF validator).
  • The "Summary" tabs shows a table with the main entities of the D3FEND graph and the attacks associated with the specific DigitalArtifacts. The table contains hyperlinks to the corresponding D3FEND classes and ATT&CK techniques.

Open Source

This tool is Open Source, contributions are welcome.

D3FEND Summary with artifacts and defemses.

d3f summary placeholder
import logging logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) # Pyodide imports import pyodide_js from pyodide import create_proxy log.info(f"{pyodide_js.version= }") import js from functools import partial from time import time import re import html import rdflib # Import local application. import app # Import library via js-proxy, requires pyodide>0.21 from js import mermaid, d3 log.info(f"mermaid: {dir(mermaid)}") mermaidAPI = mermaid.default.mermaidAPI mermaidAPI.initialize(**{ "maxTextSize": 100_000, "securityLevel": "loose", "flowchart": { "useMaxWidth": False, "htmlLabels": False, } }) CONFIG = { "strip_prefix": True, # "urn:k8s:" } ontology = app.initialize_graph(["static/ontology.ttl","static/d3fend-short.ttl"]) # Publish information in the global namespace # to be accessible from the console. text_mmd = "" status = { "mermaid": { "last-rendered-unfilter-text": None, "diagram-text": None }, "d3fend": None, "last_update": time(), } def kube_to_graph(event): """Generate a d3f graph from kubernetes text. This only works in "kubernetes" mode. """ log.warning(f"event {event}") text = Element("kubernetes").value # Always re-create the RDF graph. log.warning("No RDF graph, creating one..") t0 = time() if not text: log.warning("No text, skipping..") return graph_ttl = app.kuberdf.parse_manifest(text) Element("turtle-graph").write(graph_ttl) log.warning("Created RDF graph in %d.." % (time()-t0,)) status["d3fend"] = app.kuberdf.D3fendKube("", ontology=ontology) status["d3fend"].g.parse(data=graph_ttl, format="turtle") def update_graph_and_render_mermaid(event): raise NotImplementedError("This is not used anymore.") log.warning("update_graph_and_render_mermaid: %s" % (event,)) if hasattr(event, "inputType") and Element("mermaid").value.count("\n") > 1000: log.warning("Skipping update, too big.") return # If toggle-kube-view is checked, don't update the graph. kube_view = js.document.querySelector("#toggle-kube-view").checked if kube_view: log.warning("In kube view, skipping..") return # Populate g1 from the mermaid text. mmd_to_graph(event) render_mmd(event) def create_report(event, id_, f): # Generate the d3fend tables. t0 = time() _g = status["d3fend"].annotate() try: html = f(_g, aggregate=True) Element(f"{id_}-summary").clear() Element(f"{id_}-summary").element.innerHTML = html except Exception as e: log.error(f"Error in {id_} summary: {e}") log.warning("Created summary in %d.." % (time()-t0,)) def render_mmd(event): """Render the `mermaid-graph` with `mermaid`.text""" global status log.warning(f"render_mmd: event {event}") try: text_mmd, mermaid_svg = app.generate_diagram_mmd( text=Element("mermaid").value, filter_=Element("mermaid-filter").element.value, flip=Element("mermaid-chk-flip").element.checked, mermaidAPI=mermaidAPI, ) status["mermaid"]["diagram-text"] = text_mmd js.document.getElementById("mermaid-graph").innerHTML = mermaid_svg # Enable zooming via d3 library. svgs = js.d3.selectAll("svg") for svg in svgs: js.mermaid_enable_zoom(svg) except Exception as e: log.exception(f"Error in mermaid: {e}") def graph_to_mmd(event): global status, CONFIG g1 = status["d3fend"].g if not g1: log.error("No RDF graph..") return text_mmd = app.rdf_to_mermaid(g1) if CONFIG["strip_prefix"]: text_mmd = text_mmd.replace("urn:k8s:", "") # Update the mermaid textarea Element("mermaid").element.innerHTML = text_mmd status["mermaid"]["last-rendered-unfilter-text"] = str(time()) render_mmd(None) def refresh_mermaid_on_input(event): log.warning(dir(event)) if (event.key == "Enter"): # Cancel the default action, if needed event.preventDefault() # Trigger the button element with a click Element("mermaid-btn-redraw").element.click() initialized = False if not initialized: render_mmd(None) # Register events. # when pressing enter on mermaid-filter, run update_graph_and_render_mermaid Element("mermaid-filter").element.addEventListener( "keypress", create_proxy(refresh_mermaid_on_input) ) Element("mermaid-btn-fullscreen").element.addEventListener( "click", create_proxy(app.mermaid_toggle_fullscreen) ) js.document.getElementById("mermaid-chk-flip").addEventListener( "click", create_proxy(render_mmd) ) for element_id in ("mermaid-btn-redraw", "tab1-tab"): js.document.getElementById(element_id).addEventListener( "click", create_proxy(render_mmd) ) @app.event_listener("kubernetes-reload", "click") def kube_to_mmd(event): kube_to_graph(event) graph_to_mmd(event) @app.event_listener("tab-attack-tab", "click") def create_report_attack(event): return create_report(event, "attack", partial(app.attack_summary_html, type="kubernetes")) @app.event_listener("tab-d3fend-tab", "click") def create_report_d3fend(event): return create_report(event, "d3fend", partial(app.d3fend_summary_html, type="kubernetes")) # Copy to clipboard. js.document.getElementById("attack-summary-copy").addEventListener( "click", create_proxy(lambda event: _copy_element_to_clipboard_with_js("attack-summary")) ) js.document.getElementById("d3fend-summary-copy").addEventListener( "click", create_proxy(lambda event: _copy_element_to_clipboard_with_js("d3fend-summary")) ) js.document.getElementById("turtle-graph-copy").addEventListener( "click", create_proxy(lambda event: _copy_element_to_clipboard_with_js("turtle-graph")) ) initialized = True