Skip to content

Commit

Permalink
Merge pull request #200 from 0x41424142/cert
Browse files Browse the repository at this point in the history
Add qualysdk-cert CLI tool
  • Loading branch information
0x41424142 authored Nov 27, 2024
2 parents 1d8359c + 502ac78 commit c696588
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 12 deletions.
36 changes: 36 additions & 0 deletions docs/cert.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,40 @@ certs = list_certs(auth, hash='1234', hash_operator='CONTAINS', validFromDate='2
),
...
]
```

## ```qualysdk-cert``` CLI tool

The ```qualysdk-cert``` CLI tool is a command-line interface for the Certificate View portion of the SDK. It allows you to quickly pull down results from Certificate View APIs and save them to an XLSX file.

### Usage

```bash
usage: qualysdk-cert [-h] -u USERNAME -p PASSWORD [-P {qg1,qg2,qg3,qg4}] {list_certs} ...

CLI script to quickly perform Certificate View (CERT) operations using qualysdk

positional arguments:
{list_certs} Action to perform
list_certs Get a list of certificates according to kwargs.

options:
-h, --help show this help message and exit
-u, --username USERNAME
Qualys username
-p, --password PASSWORD
Qualys password
-P, --platform {qg1,qg2,qg3,qg4}
Qualys platform
```

### List Certificates

```bash
usage: qualysdk-cert list_certs [-h] [-o OUTPUT] [--kwarg key value]

options:
-h, --help show this help message and exit
-o, --output OUTPUT Output xlsx file to write results to
--kwarg key value Specify a keyword argument to pass to the action. Can be used multiple times
```
17 changes: 7 additions & 10 deletions docs/patch.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ runs = get_job_runs(auth, job.id)
| ```additionalDynamicQQLType``` | ```Literal[1,2]``` | 1 = Use patch QQL, 2 = Use vulnerability QQL ||


There are a few ways to pass in certain assets. If you have very particular assets in mind, you can make a GAV API call to get the agentIds of the assets you want to target:

### Example 1 with GAV Query


Expand All @@ -198,9 +200,7 @@ from qualysdk.auth import TokenAuth
from qualysdk.pm import create_job
from qualysdk.gav import query_assets

# There are a few ways to pass in certain assets. If you have
# very particular assets in mind, you can make a GAV API
# call to get the agentIds of the assets you want to target:
auth = TokenAuth(<username>, <password>, platform='qg1')

windows_assets = query_assets(
auth,
Expand All @@ -212,8 +212,6 @@ windows_assets = query_assets(
# to extract the GUIDs from the assets:
windows_assets_ids = [asset.agentId for asset in windows_assets]

auth = TokenAuth(<username>, <password>, platform='qg1')

# Create a new job for Windows servers. Let's
# focus on critical patches only:
job = create_job(
Expand All @@ -231,17 +229,16 @@ job = create_job(
>>>"Job 11111111-2222-3333-4444-555555555555 (My Job) created successfully."
```

Or you can use asset tags to dynamically target assets.

Using PM tag GUIDs is a bit more cumbersome since Qualys does not provide an easy way to look up tag GUIDs, but this method is much more flexible since new assets are picked up automatically by the job:

### Example 2 with Tag GUIDs

```py
from qualysdk.auth import TokenAuth
from qualysdk.pm import create_job

# Using PM tag GUIDs is a bit more cumbersome since
# Qualys does not provide an easy way to look up tag GUIDs,
# but this method is much more flexible since new assets are
# picked up automatically by the job:

auth = TokenAuth(<username>, <password>, platform='qg1')

# Create a new job for Windows servers. Let's
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "qualysdk"
version = "0.1.80"
version = "0.1.81"
description = "SDK for interacting with Qualys APIs, across most modules the platform offers."
authors = ["0x41424142 <jake@jakelindsay.uk>", "0x4A616B65 <jake.lindsay@thermofisher.com>"]
maintainers = ["Jake Lindsay <jake@jakelindsay.uk>"]
Expand Down Expand Up @@ -55,6 +55,7 @@ qualysdk-updater = 'qualysdk.cli.cli_updater:main'
qualysdk-was = 'qualysdk.cli.qualysdk_was:main'
qualysdk-gav = 'qualysdk.cli.qualysdk_gav:main'
qualysdk-pm = 'qualysdk.cli.qualysdk_pm:main'
qualysdk-cert = 'qualysdk.cli.qualysdk_cert:main'

[build-system]
requires = ["poetry-core"]
Expand Down
91 changes: 91 additions & 0 deletions qualysdk/cli/qualysdk_cert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""
CLI script to quickly perform Certificate View
(CERT) operations using qualysdk.
"""

from argparse import ArgumentParser, Namespace

from qualysdk import TokenAuth, write_excel, BaseList
from qualysdk.cert import *


def cli_fn(auth: TokenAuth, args: Namespace, endpoint: str) -> None:
kwargs = dict(args.kwarg) if args.kwarg else {}
if "page_count" in kwargs:
kwargs["page_count"] = int(kwargs["page_count"])
for kwarg in kwargs:
if str(kwargs[kwarg]).lower() == "true":
kwargs[kwarg] = True
elif str(kwargs[kwarg]).lower() == "false":
kwargs[kwarg] = False

match endpoint:
case "list_certs":
result = list_certs(auth, **kwargs)
case _:
raise ValueError(f"Invalid endpoint: {endpoint}.")

# If the result object does NOT have the len() method available,
# we need to wrap it in a BaseList:
if not hasattr(result, "__len__"):
bl = BaseList()
bl.append(result)
result = bl

write_excel(result, args.output)


def main():
parser = ArgumentParser(
description="CLI script to quickly perform Certificate View (CERT) operations using qualysdk"
)
parser.add_argument(
"-u", "--username", required=True, help="Qualys username", type=str
)
parser.add_argument(
"-p", "--password", required=True, help="Qualys password", type=str
)
parser.add_argument(
"-P",
"--platform",
help="Qualys platform",
default="qg3",
choices=["qg1", "qg2", "qg3", "qg4"],
)

# subparser for action:
subparsers = parser.add_subparsers(dest="action", help="Action to perform")

list_certs_parser = subparsers.add_parser(
"list_certs", help="Get a list of certificates according to kwargs."
)
list_certs_parser.add_argument(
"-o",
"--output",
help="Output xlsx file to write results to",
type=str,
default="qualysdk-certview-certs.xlsx",
)
list_certs_parser.add_argument(
"--kwarg",
help="Specify a keyword argument to pass to the action. Can be used multiple times",
action="append",
nargs=2,
metavar=("key", "value"),
)

args = parser.parse_args()

# create TokenAuth object
auth = TokenAuth(args.username, args.password, platform=args.platform)

match args.action:
case "list_certs":
cli_fn(auth=auth, args=args, endpoint="list_certs")
case _:
parser.print_help()
exit(1)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion qualysdk/cli/qualysdk_pm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from argparse import ArgumentParser, Namespace

from qualysdk import TokenAuth, write_excel, BaseList, write_json
from qualysdk import TokenAuth, write_excel, BaseList
from qualysdk.pm import *


Expand Down

0 comments on commit c696588

Please sign in to comment.