grr Documentation

GRR Rapid Response: remote live forensics for incident response

5,097 stars Python Python 9 files ยท ~4,287 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy grr on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name grr -p 3306:3306 --restart always ghcr.io/google/grr:latest
Configured Services & Ports
โš™๏ธ db
image: mysql:8.4
๐Ÿ”Œ Ports: 3306:3306
โš™๏ธ grr-admin-ui
image: ghcr.io/google/grr:latest
๐Ÿ”Œ Ports: 8000:8000
โš™๏ธ grr-fleetspeak-frontend
image: ghcr.io/google/grr:latest
โš™๏ธ fleetspeak-admin
image: ghcr.io/google/fleetspeak:latest
โš™๏ธ fleetspeak-frontend
image: ghcr.io/google/fleetspeak:latest
โš™๏ธ grr-worker
image: ghcr.io/google/grr:latest
โš™๏ธ grr-client
image: ubuntu:22.04
docker-compose.yml
yaml (docker-compose.yml)
# Run the GRR stack with container images fetched from the GitHub container
# registry.
#
# See https://github.com/google/grr/pkgs/container/grr
# See https://github.com/google/fleetspeak/pkgs/container/fleetspeak
#
# To run the stack follow
# https://grr-doc.readthedocs.io/en/latest/installing-and-running-grr/via-docker-compose.html
#
# To run the stack from source code, use compose.watch.yaml instead.

version: "3.8"
services:
  db:
    image: mysql:8.4
    env_file: docker_config_files/mysql/.env
    container_name: grr-db
    hostname: mysql-host
    command: [
      --max_allowed_packet=40M,
      --log_bin_trust_function_creators=1,
      --innodb_redo_log_capacity=167772160,
      --innodb_log_file_size=2500M,
      --restrict-fk-on-non-standard-key=OFF
    ]
    restart: always
    volumes:
      - ./docker_config_files/mysql/init.sh:/docker-entrypoint-initdb.d/init.sh
      - db_data:/var/lib/mysql:rw
    ports:
      - "3306:3306"
    expose:
      - "3306"
    networks:
      - server-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 5s
      retries: 10

  grr-admin-ui:
    image: ghcr.io/google/grr:latest
    container_name: grr-admin-ui
    hostname: admin-ui
    depends_on:
      db:
        condition: service_healthy
      fleetspeak-admin:
        condition: service_started
    volumes:
      - ./docker_config_files:/configs/
      # Mount a directory for the repacked client installers, so they
      # can be used in the grr-client container which mounts the same volume.
      - client_installers:/client_installers
    ports:
      - "8000:8000"
    expose:
      - "8000"
    networks:
      - server-network
    entrypoint: [
      "/bin/bash",
      "-c",
      "/configs/server/repack_clients.sh && grr_server -component admin_ui -config /configs/server/grr.server.yaml --verbose"
    ]
    healthcheck:
      # As soon as any files have been written to the /client_installer we
      # assume the service is healthy.
      test: "/configs/healthchecks/grr-admin-ui.sh"
      timeout: 10s
      retries: 10

  grr-fleetspeak-frontend:
    image: ghcr.io/google/grr:latest
    container_name: grr-fleetspeak-frontend
    hostname: grr-fleetspeak-frontend
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./docker_config_files:/configs
    expose:
      - "11111"
    restart: always
    networks:
      - server-network
    command:
      - -component
      - frontend
      - -config
      - /configs/server/grr.server.yaml
      - --verbose

  fleetspeak-admin:
    image: ghcr.io/google/fleetspeak:latest
    container_name: fleetspeak-admin
    hostname: fleetspeak-admin
    depends_on:
      db:
        condition: service_healthy
    networks:
      - server-network
    expose:
      - "4444"
    volumes:
      - ./docker_config_files:/configs
    entrypoint: [
      "server",
      "-components_config",
      "/configs/server/textservices/admin.components.config",
      "-services_config",
      "/configs/server/grr_frontend.service",
      "-alsologtostderr",
      "-v",
      "1000"
    ]

  fleetspeak-frontend:
    image: ghcr.io/google/fleetspeak:latest
    container_name: fleetspeak-frontend
    hostname: fleetspeak-frontend
    depends_on:
      db:
        condition: service_healthy
    networks:
      - server-network
    expose:
      - "4443"
      - "10000"
    volumes:
      - ./docker_config_files:/configs
    entrypoint: [
      "server",
      "-components_config",
      "/configs/server/textservices/frontend.components.config",
      "-services_config",
      "/configs/server/grr_frontend.service",
      "-alsologtostderr",
      "-v",
      "1000"
    ]

  grr-worker:
    image: ghcr.io/google/grr:latest
    container_name: grr-worker
    volumes:
      - ./docker_config_files:/configs
    hostname: grr-worker
    depends_on:
      db:
        condition: service_healthy
    restart: always
    networks:
      - server-network
    command:
      - -component
      - worker
      - -config
      - /configs/server/grr.server.yaml
      - --verbose

  grr-client:
    image: ubuntu:22.04
    container_name: grr-client
    depends_on:
      db:
        condition: service_healthy
      fleetspeak-frontend:
        condition: service_started
      grr-admin-ui:
        # Service is healthy as soon as client installers are repacked.
        condition: service_healthy
    volumes:
      - ./docker_config_files:/configs
      # Mount the client_installers folder which contains the
      # repacked templates written by the grr-admin-ui container
      - client_installers:/client_installers
      # Mount the client_state volume to preserve the clients state
      # including the client_id across restarts.
      - client_state:/client_state
    networks:
      - server-network
    entrypoint: [
      "/bin/bash",
      "-c",
      "/configs/client/install_client.sh && fleetspeak-client -config /configs/client/client.config"
    ]
    healthcheck:
      test: "/configs/healthchecks/grr-client.sh"
      timeout: 10s
      retries: 10

volumes:
  db_data:
  client_installers:
  client_state:
networks:
  server-network:

Technical Documentation: google/grr

โ„น๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference

Overview (`README.md`)

GRR Rapid Response is an incident response framework focused on remote live forensics.

GRR is a python client (agent) that is installed on target systems, and
python server infrastructure that can manage and talk to clients.

Documentation

Please visit our documentation website if you want to know more about GRR.

Contact Us

Screenshots




Overview (`api_client/python/README.md`)

GRR API client library

GRR API client library provides an easy way to talk to GRR AdminUI server to
fetch data or trigger actions. It can be used for GRR scripting and automation.

Installation

To install the latest release version from PIP:

bash
pip install grr-api-client

To install the latest dev version from source:

bash
sudo apt-get install -y \
  protobuf-compiler \
  python-dev \
  python-pip

sudo pip install --upgrade pip
sudo pip install virtualenv

git clone https://github.com/google/grr.git
virtualenv GRR_NEW
source GRR_NEW/bin/activate

cd grr/api_client/python
pip install --editable .

Initializing the GRR API object

python
from grr_api_client import api
grrapi = api.InitHttp(api_endpoint="http://localhost:1234",
                      auth=("user", "pwd"))

This creates a root GRR API object that will connect to the
"http://localhost:1234" HTTP API endpoint. This URL should be the same with
GRR's AdminUI URL.

GRR API library uses requests
library under the hood. The auth argument is passed verbatim to the requests
library. In the example above the ("user", "pwd") value will force the
requests library to do HTTP Basic authentication with user name "user" and
password "pwd".

In case your GRR AdminUI server is configured to use any other authentication
scheme, any authentication method supported by requests
library
can be
used (or custom one can be
implemented
).

Example: Collect client IDs for a given hostname

python
from grr_api_client import api
grrapi = api.InitHttp(api_endpoint="http://localhost:1234",
                      auth=("user", "pwd"))

search_result = grrapi.SearchClients("host:suspicious.corp.com")
result = {}
for client in search_result:
  client_id = client.client_id
  client_last_seen_at = client.data.last_seen_at
  result[client_id] = client_last_seen_at
print(result)

Example: add *"suspicious"* label to all clients with a given hostname

python
from grr_api_client import api
grrapi = api.InitHttp(api_endpoint="http://localhost:1234",
                      auth=("user", "pwd"))

search_result = grrapi.SearchClients("host:suspicious.corp.com")
for client in search_result:
  client.AddLabels(["suspicious"])

Example: start a FileFinder hunt

flow_args and hunt_runner_args below are protobufs (see Protobuf library
docs). See
definitions of
FileFinderArgs,
HuntRunnerArgs,
ForemanClientRuleSet.

python
from grr_api_client import api
grrapi = api.InitHttp(api_endpoint="http://localhost:1234",
                      auth=("user", "pwd"))

# Initialize args protobuf for a FileFinder flow: FileFinderArgs.
flow_args = grrapi.types.CreateFlowArgs("FileFinder")
# FileFinderArgs.paths gets initialized with an example value,
# we should get rid of it.
flow_args.ClearField("paths")
flow_args.paths.append("/var/log/*")
flow_args.action.action_type = flow_args.action.DOWNLOAD

# Initialize hunt runner args.
hunt_runner_args = grrapi.types.CreateHuntRunnerArgs()
rule = hunt_runner_args.client_rule_set.rules.add()
rule.rule_type = rule.LABEL
rule.label.label_names.append("suspicious")

# Create a hunt and start it.
hunt = grrapi.CreateHunt(flow_name="FileFinder", flow_args=flow_args,
                         hunt_runner_args=hunt_runner_args)
hunt = hunt.Start()

Using command line API shell

grr_api_shell command provides an IPython shell with a preinitialized grrapi
object (it's installed as part of grr-api-client PIP package).

text
/* Detailed source-code truncated for AI context efficiency. */

API shell command line one-liners

grr_api_shell tool can be used for command line one-liners.

Print client IDs of all the clients known to GRR:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'print("\n".join(c.client_id for c in grrapi.SearchClients("")))' \
  http://localhost:1234

Write all the files downloaded by a specific flow into the "flow_results.zip"
file:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").Flow("F:BB628B23").GetFilesArchive().WriteToFile("./flow_results.zip")' \
  http://localhost:1234

Download an archive of files collected from a GRR client that are stored in
/fs/os/var/log/ VFS folder:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").File("/fs/os/var/log").GetFilesArchive().WriteToFile("./all_client_files.zip")' \
  http://localhost:1234

Download a single file collected from a GRR client (helpful for large files
> 4GB that can't be added to an archive):

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").File("/fs/os/var/log/syslog").GetBlob().WriteToFile("./syslog")' \
  http://localhost:1234

Decode a Crowdstrike encoded file that was fetched via GetBlob:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").File("/fs/os/var/encrypted/file").GetBlob().DecodeCrowdStrikeQuarantineEncoding().WriteToFile("./decoded.file")' \
  http://localhost:1234

Download an archive of all files collected with OS-handler (not TSK/NTFS) from a
GRR client:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").File("/fs/os").
  GetFilesArchive().WriteToFile("./all_client_files.zip")' \
  http://localhost:1234

Print all results of a particular flow in a text-protobuf format:

bash
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'for r in grrapi.Client("C.1234567890ABCDEF").Flow("F:BB628B23").ListResults(): print(str(r.payload))' \
  http://localhost:1234

Decrypt a file from a Collect Large File flow:

bash
cat encrypted_file | \
grr_api_shell --basic_auth_username "user" --basic_auth_password "pwd" \
  --exec_code 'grrapi.Client("C.1234567890ABCDEF").Flow("F:BB628B23").Get().DecryptLargeFile()' \
  http://localhost:1234 > decrypted_file

Overview (`grr/artifacts/README.md`)

This directory is reserved for external artifacts

The Makefile removes *.yaml from this directory when syncing the external
repo located [here] (https://github.com/ForensicArtifacts/artifacts).

Where artifacts go

  • Private artifacts should go in artifacts/local
  • Public artifacts that are non GRR specific should be submitted to the external
    repo.
  • Public artifacts that call GRR functions with LIST_FILES,
    GRR_CLIENT_ACTION, GREP etc. should live in
    artifacts/flow_templates

Overview (`monitoring/grafana/README.md`)

The module grr-grafanalib-dashboards contains sample Grafana dashboards
written using grafanalib,
that will help you get started quickly introducing monitoring capabilities to your GRR server.

Quick Start

Before generating the dashboards on your own, note that you can find the sample
dashboard in importable JSON format inside the folder
grr/monitoring/grafana/grr_grafanalib_dashboards/dashboards_for_use. From
there you can import the sample dashboards without re-generating them to your
Grafana instance. Follow the instructions below if you want to rebuild or
customize the dashboards.

Please note the following edge case: the panel "API Calls Count Rate by other statuses (not
SUCCESS)" inside the AdminUI dashboard will not show a spike in the graph
when there is only one data point present (only a single API call of a given
method was made), where the status of the call is not SUCCESS.
This is due to the way Prometheus' function rate() works.

First, make sure to activate the virtual environment of your GRR installation (if you use one), and have Grafana and Prometheus
running on your GRR deployment. To run Prometheus and Grafana with GRR, check out the monitoring section
of the documentation.
Then, go to the grafana directory using cd grr/moniroing/grafana.
Now use pip install . to install the grr-grafanalib-module package. This will install grafanalib to your environment as well.

You can now visit the given sample dashboards by browsing to cd grr_grafanalib_dashboards/dashboards_to_generate.
This folder will contain all the individual dashboards for each GRR server component. In order to generate these dashboards
to a format that is importable by a Grafana instance, run generate-dashboards <grr_component_name>.dashboard.py,
for example: generate-dashboards frontends.dashboard.py.
After running this command, new files will be created in the folder with the names <grr_component_name>.json. This
JSON file can be imported to your Grafana instance by browsing to the Import page,
clicking the button "Upload .json file" and proceeding with the instructions.

Please note that these dashboards are not exhausitve (by design) as your use case might be unique to you and your GRR
deployment's needs. Use these as general guidelines on how to implement your own dashboards from scratch,
or rather extend these dashboards by introducing new metrics, graphs, alerts etc and fitting them to your individual scenario.


Overview (`grr/artifacts/flow_templates/README.md`)

Flow Templates: GRR specific 'artifacts'

These 'artifacts' are separate from the main repository because they don't
describe digital forensic artifacts, instead they provide a way to call
pre-defined GRR flows from YAML, the working name for which is 'flow templates'.


Overview (`terraform/demo/google/README.md`)

Using Terraform to deploy demo GRR setup on Google Cloud

Installing Terraform

Please follow these
instructions
to
install Terraform binary on your machine.

Setting up a Google Cloud Project

  1. Create a new project in GCP console
    (link). Let's assume it's called
    "grr-terraform-demo".
  2. Enable billing for the project
    (link).
  3. Enable Compute Engine and Cloud SQL APIs
    (link).

Instrumenting Terraform with credentials

  1. In Cloud Platform Console, navigate to the Create service account
    key

    page.
  2. From the Service account dropdown, select Compute Engine default service
    account, and leave JSON selected as the key type.
  3. Click Create, which downloads your credentials as a file named
    [PROJECT_ID]-[UNIQUE_ID].json.
  4. In the same shell where you're going to run Terraform (see below), run the
    following:
bash
export GCLOUD_KEYFILE_JSON=/absolute/path/to/downloaded-file.json

Running Terraform

cd to the folder with Terraform configuration files (and where this README
file is).

If it's the first time you run Terraform with this set of configuration files,
run:

bash
terraform init

Then run (grr-terraform-demo is the name of a project that you've previously
set up):

bash
terraform apply -var 'gce_project=grr-terraform-demo'

Run the following to get the URL of a newly deployed GRR AdminUI:

bash
terraform output

Tip: you can use Terraform variables to specify the number of generated
Windows and Linux clients:

bash
terraform apply -var 'gce_project=grr-terraform-demo' -var 'windows_client_count=4' -var 'linux_client_count=3'

Overview (`grr/core/grr_response_core/artifacts/README.md`)

This directory is reserved for external artifacts

The Makefile removes *.yaml from this directory when syncing the external repo
located here.

Where artifacts go

  • Private artifacts should go in artifacts/local.
  • Public artifacts that are non GRR specific should be submitted to the
    external repo.

Overview (`grr/server/grr_response_server/gui/ui/README.md`)

Frontend

Development server

First make sure grr_admin_ui is up and running.

Run ng serve (or ng s) for a dev server. Navigate to
http://localhost:4200/. The app will automatically reload if you change any of
the source files.

Running unit tests

Run ng test (or ng t) to execute the unit tests. The test will automatically
reload if you change any of the source files.

Further help

To get more help on the Angular CLI use ng help or go check out the
Angular CLI README.


Overview (`grr/server/grr_response_server/gui/ui/components/shared/flow_args_form/osquery_query_helper/osquery_raw_table_specs.README.md`)

The osquery_raw_table_specs.* file holds osquery's table specification as a
single object.

It was generated using a
script
and osquery table specifications,
both taken from the
open-source osquery repository.

High-level instructions for regenerating the file (and updating the
specifications to next osquery versions):

  1. Clone the osquery repository
  2. Run the script for generating table specifications, pointing it to the
    directory with the table specifications. You might need to find a way around
    import errors. Save its output to a file.
  3. The script produces JSON, but the code requires this data to be in a
    typescript .ts file. It should suffice to just prefix the output of the script
    with something like: export const tableSpecs451 = ...old json data....
  4. Update the import statements which use the table specifications inside the
    grr codebase. At the moment of writing this, it is only the file
    grr/server/grr_response_server/gui/ui/components/flow_args_form/osquery_query_helper/osquery_table_specs.ts.
    Make sure that the tests run, there are no import errors, and the model of the
    data is the same as before (or it is adapted appropriately).

--- METRICS ---