skip to content

How do you drive a Greenbone scan from a script over GMP with gvm-tools, and when would you pick gvm-cli over gvm-script?

level: middleimportance: nice to knowfreq 12%

answer

  1. XML commands to the manager
  2. target, task, start, poll, report
  3. start returns a report ID
  4. raw XML versus Python

basics

~20 s

gvm-tools clients speak GMP, gvmd's XML protocol: create a target, create a task with a scan config and scanner, start it, poll get_tasks, then fetch the report. gvm-cli sends raw XML for simple shell jobs; gvm-script runs Python for anything with logic.

solid answer

~40 s

Everything the web interface does is a GMP command to `gvmd`, so a script can do the same through **gvm-tools** over a `socket`, `tls` or `ssh` connection. The sequence is `create_target` with the hosts, `create_task` with that target plus a scan config such as Full and fast and the OpenVAS scanner, `start_task`, which returns a report ID at once while the scan runs, `get_tasks` to poll status and progress, and `get_reports` to fetch the result in a chosen report format. I use `gvm-cli` for a few fixed XML commands from shell or CI, since it exits non-zero when `gvmd` rejects a command. As soon as I must parse responses, loop or handle errors, I write a `*.gmp.py` script for `gvm-script`, which hands me a connected python-gvm `gmp` object.

code

bash · 11 lines
bash
gvm-cli socket --xml \
  "<create_target><name>web-01 $(date +%s)</name><hosts>192.0.2.10</hosts></create_target>"

gvm-cli socket --xml \
  "<create_task><name>Scan web-01</name><target id=\"$TARGET_ID\"/><config id=\"daba56c8-73ec-11df-a475-002264764cea\"/><scanner id=\"08b69003-5fc2-4037-a479-93b440211c73\"/></create_task>"

gvm-cli socket --xml \
  "<start_task task_id=\"$TASK_ID\"/>"

gvm-cli socket --xml \
  "<get_tasks task_id=\"$TASK_ID\"/>"

go deeper

for a junior

Recall that gvm-tools talks GMP to gvmd and that gvm-cli, gvm-script and gvm-pyshell are its three clients.

for a middle

Walk through target, task, start, poll and report, and explain why start_task returns a report ID before the scan is done.

for a senior

Make it run unattended: a non-root service account, credentials in a protected config file, timeouts sized for report downloads, and exit codes checked.

for a principal

Decide where scan orchestration lives: thin gvm-cli calls in CI against python-gvm scripts with real error handling and ownership.

## GMP is the way in Everything a user does in the Greenbone web interface is a **GMP** command to `gvmd`. The **Greenbone Management Protocol** is XML-based and offers create, read, update and delete operations on targets, tasks, reports and the rest. Because the web server `gsad` itself speaks GMP to `gvmd`, any client that speaks GMP can drive the whole stack, and **gvm-tools** is Greenbone's set of such clients. ## The three gvm-tools clients | Tool | What you write | Best for | |---|---|---| | `gvm-cli` | Raw GMP or OSP XML, passed with `--xml` or read from a file | Shell scripts and one-off commands | | `gvm-script` | A Python script (by convention `*.gmp.py`) that receives a connected `gmp` object from the python-gvm library | Anything with logic: loops, parsing responses, CSV imports | | `gvm-pyshell` | Interactive Python with the same `gmp` object | Exploring the API by hand | All three connect by one of three **connection types**: `socket` (a Unix domain socket on the same host as `gvmd`; for Community Edition 21.4 and 22.4 the docs give `/run/gvmd/gvmd.sock`), `tls`, or `ssh`. Defaults such as the GMP username and password, the socket path or the timeout can live in `~/.config/gvm-tools.conf`. ## A scan, command by command The gvm-tools scripting guide walks through the same sequence the web interface performs: 1. **`create_target`** with a name and the hosts; the response carries the new target's ID. Target names must be unique. 2. **`create_task`** with the target ID, a scan config ID (the docs use **Full and fast**, `daba56c8-73ec-11df-a475-002264764cea`) and a scanner ID (the docs use the OpenVAS scanner, `08b69003-5fc2-4037-a479-93b440211c73`). 3. **`start_task`** with the task ID. It returns at once with status 202 and a **report ID**; the scan runs in the background. 4. **`get_tasks`** with the task ID to poll `status` and `progress`. 5. **`get_reports`** with the report ID, optionally with a `format_id` for a report format; a PDF comes back base64-encoded inside the XML. In a `gvm-script` file the same steps are method calls on the python-gvm `gmp` object, and the script body runs under `if __name__ == '__gmp__':`. A minimal shape, following the gvm-tools scripting guide: ```python def main(gmp, args): ipaddress = args.argv[1] target = gmp.create_target(name=f"Host {ipaddress}", hosts=[ipaddress]) task = gmp.create_task( name=f"Scan {ipaddress}", config_id="daba56c8-73ec-11df-a475-002264764cea", target_id=target.get("id"), scanner_id="08b69003-5fc2-4037-a479-93b440211c73", ) report_id = gmp.start_task(task.get("id"))[0].text print(report_id) if __name__ == "__gmp__": main(gmp, args) ``` It is run as `gvm-script --gmp-username scanbot socket scan-host.gmp.py 192.0.2.10`, with the password taken from the `[gmp]` section of the config file; `args.argv[0]` holds the script name and the host follows it. ## When to pick which - **gvm-cli** when the job is a handful of fixed commands from shell, cron or CI. It prints the response, and by default exits non-zero with an error when `gvmd` rejects a command, so the shell can test it; `--raw` returns the unparsed XML instead. - **gvm-script** as soon as you need to read one response to build the next request, loop over many targets, or handle errors in code. The docs themselves recommend scripts over raw XML for anything beyond simple use. - **gvm-pyshell** to discover what a response looks like before writing the script. ## Running it unattended without surprises - **Do not run it as root.** `gvm-cli`, `gvm-script` and `gvm-pyshell` refuse with "This tool MUST NOT be run as root user." The docs say to fix socket access with `gvmd`'s `--listen-owner`, `--listen-group` or `--listen-mode` rather than with `sudo`. - **Give gvm-cli credentials.** With no GMP username or password from the flags or the config file, `gvm-cli` falls back to prompting on the terminal, which a cron job cannot answer. A config file readable only by the service account also keeps the password off the process list. - **Mind the timeout.** The response timeout defaults to 60 seconds; `--timeout -1` waits indefinitely, which matters for slow report downloads. - **Poll, do not block.** `start_task` does not wait for the scan; a pipeline that reads the report straight after starting the task reads an unfinished one.

  • A nightly cron job runs gvm-cli and fails before sending anything. What do you check?
    First the user: gvm-tools refuses to run as root, so a root crontab fails at once. Then credentials: without a GMP username and password from flags or `~/.config/gvm-tools.conf`, `gvm-cli` prompts on the terminal, which cron cannot answer. Then socket permissions, fixed with gvmd's listen options rather than `sudo`.
  • How does gvm-cli signal that gvmd rejected a command, and how do you change that?
    By default it prints an error message and exits with a non-zero code, which a shell or CI step can test. Passing `--raw` makes it print the unparsed XML response instead, leaving the status attribute for your own code to check.

saying these in an interview costs you the question

  • start_task blocks until the scan finishes and returns the results.
  • GMP is a JSON REST API served on gsad's port 9392.
  • Run gvm-cli with sudo so it can open the gvmd socket.
  • gvm-cli exits 0 even when gvmd rejects the command.
  • gvm-tools can only talk to a commercial Greenbone appliance.