Solution |
The following steps will walk you through the creation and execution of an LQL query that will pull a list of all running AWS EC2 instances without a Lacework Agent installed on them. However, you can use this same process to create and execute LQL queries for other use cases as well. For more information on LQL, check out the Lacework Query Language (LQL) documentation.
-
Open a terminal and navigate to a directory of your choosing where you can create a new file. This will be your working directory.
-
Create a file in that working directory called hosts-without-agent.yml.
-
Open the hosts-without-agent.yml file in your code/text editor and paste the following contents (since we’re using YAML, be very mindful of spaces/indentation).
queryId: LWCustomCompliance_AWSEC2InstancesWithoutAgents queryText: |- { source { LW_CFG_AWS_EC2_INSTANCES as ec2_instances }
filter { ec2_instances.RESOURCE_CONFIG:State.Name = 'running'
and not ( ec2_instances.RESOURCE_CONFIG:InstanceId::String in { source { LW_HE_PROCESSES as processes with LW_HE_MACHINES as machine }
filter { ( RIGHT(processes.EXE_PATH, 13) = 'datacollector' or RIGHT(processes.EXE_PATH, 19) = 'LWDataCollector.exe' ) }
return distinct { machine.TAGS:InstanceId::String as InstanceId } } ) }
return distinct { ec2_instances.ACCOUNT_ID::String as ACCOUNT, ec2_instances.ARN::String as ARN, ec2_instances.RESOURCE_CONFIG:InstanceId::String as INSTANCE_ID } }
This LQL is querying the LW_CFG_AWS_EC2_INSTANCES data source for all running EC2 instances in your environment then uses the LW_HE_PROCESSES and LW_HE_MACHINES data sources to correlate and determine which instances don’t have the Lacework agent datacollector process running on them.
IMPORTANT NOTE: If you are using GCP or Azure, you can find the LQL for those Cloud Service Providers at the end of this article in the Additional Resources section. All you would have to do is replace the AWS LQL with the GCP or Azure LQL.
-
Once saved, back in your terminal in the working directory, run this command to execute the query: lacework query run -f hosts-without-agent.yml --range "last day"
This will execute the query for the last 24 hours thanks to the --range “last day” flag. If you want to expand the range, you may do so by either specifying some other natural language range (e.g., --range "last 3 days" or --range "last month" ) or by using the --start and --end flags (run lacework query run --help for more information and execution options).
-
If you have running hosts without Lacework Agents installed on them, you should see data returned!
Taking Things a Step Further:
If you want to get a little more advanced, you can save the above LQL as a Query within your Lacework tenant. Doing so allows you to call the query from anywhere using either the CLI or API without the need to specify a local YAML file. For example, let’s take the above LQL, save it as a Query, then call that query using the CLI and API.
-
Save the hosts-without-agent.yml LQL as a Query with the command: lacework query create -f hosts-without-agent.yml
This will create a new Query in your tenant with the name LWCustomCompliance_AWSEC2InstancesWithoutAgents , which is the value specified for queryId: inside the LQL file.
-
Now let’s execute that query using the Lacework CLI. Run the following command: lacework query run LWCustomCompliance_AWSEC2InstancesWithoutAgents --range "last day"
-
Next, let’s utilize the Lacework CLI to call the Lacework API (the quickest way to use the API). We’ll use the endpoint, /api/v2/Queries/<queryId>/execute , where <queryId> is the ID of the query you want to execute (e.g., LWCustomCompliance_AWSEC2InstancesWithoutAgents ). To do so, run the following command:
lacework api post /api/v2/Queries/LWCustomCompliance_AWSEC2InstancesWithoutAgents/execute -d '{ "arguments": [ {"name": "StartTimeRange", "value": "2024-01-18T00:00:00.000Z"}, {"name": "EndTimeRange", "value": "2024-01-19T00:00:00.000Z"} ] }'
-
And voila! You’ve successfully saved a Query in your Lacework tenant and used the Lacework CLI and API to execute that query.
Additional Resources:
LQL for GCP Compute Instances without a Lacework Agent installed:
queryId: LWCustomCompliance_GCPComputeInstancesWithoutAgents queryText: |- { source { LW_CFG_GCP_COMPUTE_INSTANCE as compute_instance }
filter { compute_instance.RESOURCE_CONFIG:status = "RUNNING" and not ( compute_instance.RESOURCE_CONFIG:id::String in { source { LW_HE_PROCESSES as processes with LW_HE_MACHINES as machine } filter { ( RIGHT(processes.EXE_PATH, 13) = "datacollector" or RIGHT(processes.EXE_PATH, 19) = "LWDataCollector.exe" ) } return distinct { machine.TAGS:InstanceId::String as InstanceId } } ) }
return distinct { compute_instance.RESOURCE_CONFIG:name::String as INSTANCE_NAME, compute_instance.URN::String as URN, compute_instance.PROJECT_ID::String as PROJECT } }
LQL for Azure Virtual Machines without a Lacework Agent installed:
queryId: LWCustomCompliance_AzureVirtualMachinesWithoutAgents queryText: |- { source { LW_CFG_AZURE_COMPUTE_VIRTUALMACHINES as virtual_machines }
filter { virtual_machines.RESOURCE_CONFIG:extended.instanceView.powerState.displayStatus = "VM running"
and not ( virtual_machines.RESOURCE_CONFIG:vmId::String in { source { LW_HE_PROCESSES as processes with LW_HE_MACHINES as machine }
filter { ( RIGHT(processes.EXE_PATH, 13) = "datacollector" or RIGHT(processes.EXE_PATH, 19) = "LWDataCollector.exe" ) }
return distinct { machine.TAGS:InstanceId::String as InstanceId } } ) }
return distinct { virtual_machines.SUBSCRIPTION_NAME::String as SUBSCRIPTION, virtual_machines.URN::String as URN, virtual_machines.RESOURCE_ID::String as VM_NAME } }
|