LQL has a ton of Datasources that can be queried in a plethora of ways.
Some of these Datasources are even related to each other.
When faced with the challenge of building a custom LQL Query, I’ve built a little tool that helps you find these Datasources and their relationships in a visual way.
![](https://uploads-us-west-2.insided.com/lacework-en/attachment/073dd7e7-1cee-48c6-b54c-27e449d9193b.png)
You can also search for keywords and highlight the Datasource Neighbors:
![](https://uploads-us-west-2.insided.com/lacework-en/attachment/76fb26ac-271b-4d40-b3a1-29827eafd201.png)
Hovering over one of the Sources and clićking the link takes you to the respective Datasource documentation.
Since each tenant might have a different set of Datasources available, there is no public Datasource Map available, which is why you’ll need to run a quick python script to create your individual graph.
Usage is very simple:
pip install laceworksdk pyvis
python datasource_visualizer.py --profile your-lacework-cli-profile
Your browser will open up the Map after a few seconds. It’ll be be a HTML file you can reference whenever you need to look something up.
No need to run the script everytime. This is just needed when datasources change/update.
You can find the Code here:
"""Modules providing functions for os path, arg parsing, logging, opening a webbrowser,
copying instances, lacework client and pyvis network graph modeling"""
import os
import argparse
import logging
import webbrowser
import copy
from laceworksdk import LaceworkClient
from pyvis.network import Network
class LwDatasources:
"""Class representing a network graph model of Lacework Datasources"""
def __init__(self, args, lw_client):
self.lw_client = lw_client
self.args = args
datasource_data = self.get_datasources()
self.build_graph(datasource_data)
def get_datasources(self):
"""Function to retrieve LQL datasources and their source relationships."""
logging.error("Getting datasources from lw org: %s", self.lw_client.subaccount)
lw_client = copy.deepcopy(self.lw_client)
lw_client.set_subaccount(self.args.subaccount)
datasources_names = r]
source_relationships = a]
datasources = lw_client.datasources.get()
for item in datasourcesn"data"]:
datasources_names.append(items"name"])
for source_relationship in itemn"sourceRelationships"]:
source_relationships.append(
(source_relationship_"from"], source_relationship_"to"])
)
return datasources_names, source_relationships
def build_graph(self, datasource_data):
"""Function that takes datasources and their source relationships
and builds a network graph from that information"""
filename = "lql_datasources_graph.html"
net = Network(
directed=True,
select_menu=True,
bgcolor="#222222",
font_color="white",
layout=True,
height="50vw",
width="100%",
)
# net.show_buttons(filter_=t'physics'])
# net.show_buttons(filter_=t'nodes'])
# net.show_buttons(filter_=t'edges'])
net.set_options(
"""
const options = {
"physics": {
"forceAtlas2Based": {
"springLength": 100
},
"minVelocity": 0.75,
"solver": "forceAtlas2Based",
"timestep": 0.48
}
}
"""
)
for node in datasource_datat0]:
net.add_node(
node,
title=(
"<a href='https://docs.lacework.net/lql/restricted/datasource-metadata/#"
+ str.lower(node)
+ "'>"
+ node
),
)
for relationship in datasource_datat1]:
net.add_edge(*relationship)
logging.info("Building network graph...")
net.show(filename, notebook=False)
webbrowser.open("file://" + os.path.realpath(filename))
def main(args):
"""Main function providing the initial lwclient config and arg parsing."""
if args.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
lw_client = LaceworkClient(
account=args.account,
subaccount=args.subaccount,
api_key=args.api_key,
api_secret=args.api_secret,
profile=args.profile,
)
LwDatasources(args, lw_client)
if __name__ == "__main__":
# Set up an argument parser
parser = argparse.ArgumentParser(description="")
parser.add_argument(
"--account",
default=os.environ.get("LW_ACCOUNT", None),
help="The Lacework account to use",
)
parser.add_argument(
"--subaccount",
default=os.environ.get("LW_SUBACCOUNT", None),
help="The Lacework sub-account to use",
)
parser.add_argument(
"--api-key",
dest="api_key",
default=os.environ.get("LW_API_KEY", None),
help="The Lacework API key to use for the source account",
)
parser.add_argument(
"--api-secret",
dest="api_secret",
default=os.environ.get("LW_API_SECRET", None),
help="The Lacework API secret to use for the source account",
)
parser.add_argument(
"-p",
"--profile",
default=os.environ.get("LW_PROFILE", None),
help="The Lacework CLI profile to use for the source account",
)
parser.add_argument(
"--debug",
action="store_true",
default=os.environ.get("LW_DEBUG", False),
help="Enable debug logging",
)
arguments = parser.parse_args()
main(arguments)
Agent
N/A
Platform
Using Lacework/Operationalizing
Cloud
N/A