Lacework Integration

Check for container vulnerabilities detected by Lacework for your services in OpsLevel

Add a Lacework Integration

  1. In the OpsLevel app, Click Integrations in the left sidebar.
  2. Click on the + New Integration button.
  3. Click the Lacework tile to add the integration.

Create a Check

  1. Navigate to the Rubrics sub menu under the Service Maturity menu in OpsLevel.
  2. Hover over the cell that corresponds to the level and category you want your check to live in and click the + Add Check button.
  1. Create a Lacework check.
  2. Select one of the Check Templates from the dropdown.

Each of these checks will pass or fail depending on the scan results that Lacework reports. Here is an example of what you can expect if your repository failed the check from the first template. You can see that for each severity that is found we show the count. If you wish to learn more about these vulnerabilities you can find the full details in Lacework.

Completing the Setup

In order to complete your setup you’ll need to:

  • Obtain a Lacework API Access Key
  • Set up the script that will forward data to OpsLevel

Getting a Lacework Access Key

To create a Lacework API Access Key, you must:

  1. Log-in to Lacework
  2. Navigate to Settings > Configuration > API Keys
  3. Click + Add New
  4. Enter a name for the key and an optional description
  5. Ensure you Save the key

Once the key has been generated, you must download it in order to use it. The downloaded API key is just a JSON file containing a few secrets.

Forwarding Lacework data to OpsLevel

Using the snippet provided below, you can query Lacework for vulnerabilities across your containers and pipe the data to OpsLevel. We recommend using a cron job to periodically update OpsLevel with the latest Lacework results.

Requirements

  • The ability to run a bash script

  • jq must be installed and accessible via the script

        #!/bin/bash
        if [[ $# -ne 2 || ! -f $1 ]]; then
            cat < /dev/null) || seven_days_ago=$(date -d "-7 days" +"%Y-%m-%d")
        
        # Generate auth token from secrets
        token_response=$(
            curl --location --request POST "https://$lacework_base_url/api/v2/access/tokens" \
            --header "X-LW-UAKS: $lacework_secret" \
            --header 'Content-Type: application/json' \
            --header 'Accept: application/json' \
            --data-raw "{
                \"keyId\": \"$lacework_key_id\",
                \"expiryTime\": 3600
            }"
        )
        
        # Parse access_token from response
        # Using printf here to better handle UTF-8 formatting
        access_token=$(printf "%s" "$token_response" | jq '.token' | tr -d '"')
        
        vulns_url="https://$lacework_base_url/api/v2/Vulnerabilities/Containers/search"
        responses=()
        
        # Query Lacework for container vulnerability info
        while [ "$vulns_url" != "null" ]; do
            response=$(
                curl \
                --location --request POST "$vulns_url" \
                --header 'Content-Type: application/json' \
                --header 'Accept: application/json' \
                --header "Authorization: Bearer $access_token" \
                --data-raw "{
                    \"filters\": [ { \"expression\": \"ne\", \"field\": \"status\", \"value\": \"GOOD\" } ],
                    \"timeFilter\": { \"startTime\": \"$seven_days_ago\", \"endTime\": \"$todays_date\" }
                }"
            )
            # Add result to array that holds values
            responses+=($response)
        
            # Handle response being spread across multiple pages
            vulns_url=$(printf "%s" $response | jq '.paging.urls.nextPage' | tr -d '"')
        done
        
        # This takes an unordered list of vulnerabilities from Lacework and buckets the counts according to their repo name
        # and severity. If we directly piped across the data from Lacework, we'd bump into issues because the requests would
        # overshoot our request size limits.
        data_for_opslevel=$(
            printf "%s" "${responses[@]}" | jq '
                . | reduce .[] as $item ([]; $item.data+ .)
                | map({ repo: .evalCtx.image_info.repo, vulnId, severity })
                | reduce .[] as $item
                (
                    {};
                    $item.repo as $repo
                    | .[$repo] as $current
                    | $item.severity as $bucket
                    | $current[$bucket] as $count
                    | { ($bucket): ($count + 1) } as $this
                    | ($current + $this) as $next
                    | . + { ($repo): ($next) }
                )
            ' -s
        )
        
        # Ship off to OpsLevel
        curl -X POST "$opslevel_webhook_url" \
            -H 'content-type: application/json' --data-binary "$data_for_opslevel"
    

Running the Script

The script expects 2 arguments; the path to your Lacework Access Key and your OpsLevel WebHook URL.

Given an access key named lacework_key.json, the script can be run with the following command (replace {{UUID}} with the UUID specified in the OpsLevel Lacework integration:

$ ./lacework.sh lacework_key.json 'https://app.opslevel.com/integrations/custom_event/{{UUID}}'