Using Named Services

A named service is a feature that allows other apps and parts of the QRadar UI to interact with an app. These named services can fit a variety of use cases.

Using this tutorial, create four different apps, each using a different configuration of named services:

Prerequisites

Each of the four apps require QRadar app SDK version 2

Named service with a command as a background process

This app serves a Flask app over port 5000, but uses a named service as a background process to repeatedly update a file that is served with a timestamp.

Create the Background Process app

Create a new folder for the app:

mkdir NamedServiceCommand && cd NamedServiceCommand

Use the QRadar app SDK to initialize the app code:

qapp create

Write the Background Process app manifest

Edit the manifest.json file to make it more relevant to the app:

{
  "name": "NamedServiceCommand",
  "description": "An app serving a data that is generated by a named service running in the background",
  "version": "1.0",
  "image": "qradar-app-base:2.0.0",
  "areas": [
    {
      "id": "FlaskArea",
      "text": "Area Served from Flask",
      "description": "Area Serving File Generated by Named Service from Flask",
      "url": "index",
      "required_capabilities": []
    }
  ],
  "services": [
    {
      "command": "/bin/bash /opt/app-root/app/background.sh",
      "directory": "/",
      "name": "NamedServiceBackgroundCommand",
      "path": "/",
      "version": "1"
    }
  ],
  "uuid": "<your unique app UUID>"
}

This manifest defines the following key properties:

  • A named service called NamedServiceBackgroundCommand that runs a script (/opt/app-root/app/background.sh) in the background.
  "services": [
    {
      "command": "/bin/bash /opt/app-root/app/background.sh",
      "directory": "/",
      "name": "NamedServiceBackgroundCommand",
      "path": "/",
      "version": "1"
    }
  ],
  • An area in the QRadar UI that serves a normal Flask endpoint. This Flask endpoint reads the output of the named service defined above and returns it.
  "areas": [
    {
      "id": "FlaskArea",
      "text": "Area Served from Flask",
      "description": "Area Serving File Generated by Named Service from Flask",
      "url": "index",
      "required_capabilities": []
    }
  ],

Add named service Background Process script

Create a script called app/background.sh to be the background named service. This is a simple bash script that repeatedly updates the /opt/app-root/store/background_output file with a message and timestamp.

#!/bin/bash

while true
do
    echo "Background named service last updated: $(date)" > /opt/app-root/store/background_output
    sleep 5
done

Update Flask Background Process endpoints

Update the app HTTP endpoints by editing the app/views.py script:

from flask import Blueprint

# pylint: disable=invalid-name
viewsbp = Blueprint('viewsbp', __name__, url_prefix='/')

# A simple endpoint that returns the 'background_output' file that is managed by the background named service
@viewsbp.route('/')
def background_output_read():
    with open('/opt/app-root/store/background_output', 'r') as file:
        background_content = file.read()
        return background_content

This sets up a simple endpoint under the path / that reads the /opt/app-root/store/background_output file generated by the named service script and returns it.

Background Process conclusion

The completed QRadar app runs two parallel processes: Flask to serve HTTP endpoints and a background script running that repeatedly updates a file that the endpoints serve.

Named service with a port Exposing Flask

This app will use a named service with a port to expose Flask, allowing the app’s Flask endpoints to be called from different parts of QRadar; in this case, as a configuration page.

Create the Exposing Flask app

Create a new folder for the app:

mkdir NamedServicePort && cd NamedServicePort

Use the QRadar App SDK to initialise the app code:

qapp create

Write the Exposing Flask app manifest

Edit the manifest.json file to to make it more relevant to the app:

{
  "name": "NamedServicePort",
  "description": "An app that uses a named service to expose Flask as a named service",
  "version": "1.0",
  "image": "qradar-app-base:2.0.0",
  "configuration_pages": [
    {
      "text": "Flask Exposed through Named Service Config Page",
      "description": "Configuration page exposing Flask as a named service",
      "url": "/index",
      "named_service": "NamedServicePort",
      "required_capabilities":[]
    }
  ],
  "services": [
    {
      "port": 5000,
      "name": "NamedServicePort",
      "path": "/",
      "version": "1"
    }
  ],
  "uuid": "<your unique app UUID>"
}

This manifest defines the following key properties:

  • A named service NamedServicePort that exposes Flask, running on default port 5000, which allows it to be queried from different parts of QRadar.
  "services": [
    {
      "port": 5000,
      "name": "NamedServicePort",
      "path": "/",
      "version": "1"
    }
  ],
  • A configuration page that displays the /index value queried from the NamedServicePort named service on the QRadar Admin tab.
  "configuration_pages": [
    {
      "text": "Flask Exposed through Named Service Config Page",
      "description": "Configuration page exposing Flask as a named service",
      "url": "/index",
      "named_service": "NamedServicePort",
      "required_capabilities":[]
    }
  ],

Update Exposing Flask app flask endpoints

Update the app HTTP endpoints by editing the app/views.py script:

from flask import Blueprint

# pylint: disable=invalid-name
viewsbp = Blueprint('viewsbp', __name__, url_prefix='/')

# A simple endpoint that returns a string, to be called from a configuration page using a named service
@viewsbp.route('/index')
def index():
    return "This is returned from Flask running through a named service"

This sets up a simple Flask HTTP endpoint that returns a string when /index is queried.

Exposing Flask conclusion

The completed QRadar app exposes Flask as a named service and uses a configuration page (which is visible on the QRadar Admin tab) to query the named service.

Named service with a command and a port replacing Flask

This app replaces Flask with a named service running on the default port (5000) that instead uses the built-in Python HTTP server.

Create the Replacing Flask app

Create a new folder for the app:

mkdir NamedServiceCommandAndPort && cd NamedServiceCommandAndPort

Use the QRadar app SDK to initialize the app code:

qapp create

Write the Replacing Flask app manifest

Edit the manifest.json file to make it more relevant to the app:

{
  "name": "NamedServiceCommandAndPort",
  "description": "An app serving using a named service running with a command and port",
  "version": "1.0",
  "image": "qradar-app-base:2.0.0",
  "load_flask": "false",
  "areas": [
    {
      "id": "NamedServiceCommandAndPortArea",
      "text": "Area Served from Named Service",
      "description": "Area Served from Named Service with Command and Port",
      "named_service": "NamedServiceCommandAndPort",
      "url": "index.html",
      "required_capabilities": []
    }
  ],
  "services": [
    {
      "command": "python3 -m http.server 5000",
      "directory": "/opt/app-root/app/named_service",
      "name": "NamedServiceCommandAndPort",
      "path": "/",
      "version": "1",
      "port": 5000
    }
  ],
  "uuid": "<your unique app UUID>"
}

This manifest defines the following key properties:

  • The app does not load Flask. Instead, it uses a named service running on the default port 5000.
  "load_flask": "false",
  • A named service called NamedServiceWithCommand, using the built in Python HTTP server to serve files out of the /opt/app-root/app/named_service directory over port 5000.
  "services": [
    {
      "command": "python3 -m http.server 5000",
      "directory": "/opt/app-root/app/named_service",
      "name": "NamedServiceWithCommand",
      "path": "/",
      "version": "1",
      "port": 5000
    }
  ],
  • An area in the QRadar UI that queries this named service for a file called index.html.
  "areas": [
    {
      "id": "NamedServiceCommandAndPort",
      "text": "Area Served from Named Service",
      "description": "Area Served from Named Service with Command and Port",
      "url": "index.html",
      "required_capabilities": []
    }
  ],

Add content to serve to the replacing Flask

Create a directory to hold the content to serve from the named service from the top-level directory of your app workspace:

mkdir -p app/named_service

Create the app/named_service/index.html file to be served by the named service and requested by the area defined in the manifest:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello from Named Service With Command and Port</title>
  </head>
  <body>
      <h1>This page is being served from a named service</h1>
  </body>
</html>

Create a debug file that responds to QRadar App Framework healthchecks. This is a requirement of QRadar apps. It is the only way QRadar can determine if an app is up and running: a 200 OK response to the /debug path on the default port (5000). Create the file app/debug. This can be any minimal content. The only requirements are that it must return 200 OK when queried and return a small amount of data.

Example:

File to return 200 to the /debug endpoint

Replacing Flask conclusion

The completed QRadar app uses the built-in Python HTTP server running as a named service to present an HTML webpage as a QRadar area.

Named service with a command, a port, and endpoints running in parallel to Flask

This app runs Flask and a named service in Parallel. The named service runs using the Python built-in HTTP server. The app serves an area from Flask and a configuration page from the named service.

Create the Parallel Flask Process app

Create a new folder for the app:

mkdir NamedServiceCommandPortEndpoints && cd NamedServiceCommandPortEndpoints

Use the QRadar app SDK to initialise the app code:

qapp create

Write the Parallel Flask Process app manifest

Edit the manifest.json file to make it more relevant to the app:

{
  "name": "NamedServiceCommandPortEndpoints",
  "description": "An app that uses Flask and a Python webserver as a named service running in parallel",
  "version": "1.0",
  "image": "qradar-app-base:2.0.0",
  "areas": [
    {
      "id": "FlaskIndex",
      "text": "Area Served from Flask",
      "description": "Area Served from Flask",
      "url": "index",
      "required_capabilities": []
    }
  ],
  "configuration_pages": [
    {
      "text": "Configuration Page Served through Named Service",
      "description": "Configuration page served through named service",
      "url": "/index.html",
      "named_service": "NamedServiceCommandPortEndpoints",
      "required_capabilities":[]
    }
  ],
  "services": [
    {
      "command": "python3 -m http.server 5001",
      "directory": "/opt/app-root/app/named_service",
      "name": "NamedServiceCommandPortEndpoints",
      "path": "/",
      "version": "1",
      "port": 5001,
      "endpoints":  [
        {
          "name":"config_index",
          "path":"index.html",
          "http_method": "GET",
          "parameters": []
        }
      ]
    }
  ],
  "uuid": "<your unique app UUID>"
}

Add content to serve to the Parallel Flask Process app

Create a directory to contain the content to serve from the named service from the top-level directory of your app workspace:

mkdir -p app/named_service

Now create the app/named_service/index.html file to be served by the named service and requested by the configuration page defined in the manifest:

<!DOCTYPE html>
<html>
  <head>
    <title>Hello from Named Service With Command, Port, and Endpoints</title>
  </head>
  <body>
      <h1>This page is being served from a named service</h1>
  </body>
</html>

Parallel Flask Process conclusion

The completed QRadar app uses both Flask and the built-in Python HTTP server to return content for both an area and a configuration page.