Getting Started with Axonshell

Axonshell is the command line script that comes with our python library. It is just a python script that is using a package called Click: We tried very hard to expose as much of the python library's functionality through axonshell as we could and still have it organized in a way that not only made sense but closely matched how you would use the python library.

Like the python library, axonshell also needs to be configured to talk to the server. This can be skipped if you already have done it for the python library. It only needs to be done once as they both will use the same .env file as long as you are running out of the same location. It supports the following methods of doing so:

  • Add the information into a .env file. The python client will look first in the current working directory.
  • Add the information to the correct environment variables.
  • Add the information as command line parameters. We do not recommend this approach as it has the potential to put sensitive information into plaintext files such as .bash_history, etc.

We showed the first option in the previous section which took advantage of axonshell's built-in tool to generate the .env file.

axonshell's functionality is broken up into 7 groups:

  • adapters - provides functionality for working with adapters
  • devices - provides functionality for querying devices and adding device saved queries
  • help-features - provides information on extra features that can be enabled in axonshell
  • openapi - provides the ability to pull the REST API's JsonAPI spec. file
  • system - provides functionality for working with the Axonius server itself
  • tools - provides useful tools for working with axonshell
  • users - provides functionality for querying users and adding user saved queries

We will not be going into all of these in detail in this article. However we do have detailed documentation on these located here:

axonshell by design has a lot of "documentation" under the hood. Every command and sub-command has a "--help" parameter that will show all of the available options to be used with the command. On top of that, axonshell tries to proactively figure out what you are trying to do. So, for example, if you specify an incorrect field name, axonshell will grab all the fields from the server and fuzzy match against them and ask you if the one you are looking for is on the list. On top of this there is also the "--help-detailed" parameter that will show you more detailed information about some parameters.

Lets take a look at how we might setup a new Axonius server to get a feel for axonshell:

We'll start by signing up. Every new Axonius server needs a default admin account setup for use:

axonshell system signup

This will prompt for a few pieces of information such as your company name, email address and password. It will then return API credentials for this user that you can use with the following command to create your .env file.

axonshell tools write-config

This is the same as we did above and should produce a .env file that contains the server's URL, API key and API secret. It should look something like this:

❯ cat .env

Now as long as we are in this directory, we will not have to enter credentials for every command we want to run.

Let's add an adapter so we can pull in some assets. First let's take a look at what the adapter needs for parameters:

❯ axonshell adapters cnx get --name cisco --export-format table-schemas

This will output all the parameters you can pass into the config options for the cisco adapter. We won't list them all but we are interested in host, protocol, username and password.

❯ axonshell adapters cnx add --name CISCO \
--config host= \
--config protocol=ssh \
--config username=root \
--config password=password
** Connected to '' version DEMO (RELEASE DATE: 2021-10-20) API Client v4.10.8
Client Id:
Uuid: 619d29ff454716e8ddb686cd
Status: success
    "auth_passphrase": null,
    "auth_protocol": "hmac_md5",
    "host": "",
    "password": [
    "port": 22,
    "priv_passphrase": null,
    "priv_protocol": "aescfb128",
    "protocol": "ssh",
    "secure_level": "authPriv",
    "username": "root"

Now that we have an adapter added we need to have Axonius pull in all assets. We can do this by triggering a discovery cycle to run. This will have each adapter pull in their data and update things accordingly.

❯ axonshell system discover start

If you want to check the progress of the discovery cycle:

❯ axonshell system discover get
** Connected to '' version DEMO (RELEASE DATE: 2021-10-20) API Client v4.10.8
- Is Running: True
- Is Correlation Finished: False
- Status: running
- Current Run Duration In Minutes: 0.78
- Last Run Finish Date: 2021-11-20 20:33:34+00:00
- Last Run Start Date: 2021-11-23 18:01:35+00:00
- Last Run Duration In Minutes: None
- Last Run Minutes Ago: 4168.79
- Next Run Start Date: 2021-11-23 20:30:06.676894+00:00
- Next Run Starts In Minutes: 147.75

Phase Status:
- Fetch Stage 1: running
- Fetch Stage 2: pending
- Clean Assets: pending
- Correlation Pre: pending
- Correlation Run: pending
- Correlation Post: pending
- Calculate Queries: pending
- Save History Snapshot: pending

You can see here that the discovery cycle is running and it is currently in Fetch Stage 1. Depending on how many adapters are configured and how much data is getting pulled in this could any amount of time. Once completed though, we are ready to start querying!

Lets see how many devices we pulled in:

❯ axonshell devices count
** Connected to '' version DEMO (RELEASE DATE: 2021-10-20) API Client v4.10.8

Perfect! Now lets see if we can find any devices using axonshell to search with specific criteria:

❯ axonshell devices get --wiz simple "hostname contains test" --max-rows 1 --max-pages 1
** Connected to '' version DEMO (RELEASE DATE: 2021-10-20) API Client v4.10.8
Wizard built a query: ( == regex("test", "i"))
** Starting JSON processor
** Configuration:
- Exclude fields: ()
- Flatten complex fields: False
- Explode field: None
- Rename fields to titles: False
- Shorten field names: False
- Replace characters in field names: ()
- Join field values: False
- Join field values using: '\n'
- Join field character limit: 32000
- Add missing fields: False
- Missing field value: None
- Missing complex field value: []
- Add tags: ()
- Remove tags: ()
- Report Missing Adapters: False
- Report Missing Software: None
- Echo page progress every N assets: 10000
- Echo messages to console: True
- Custom callbacks to perform on assets: []
- Enable logging of time taken for each callback: False
- Export to file: ''
- Export file to path: '/Users/'
- Export overwrite file: False
- Export schema of fields: False
- Export to a file descriptor: None
- Close the file descriptor when done: True
- Produce flat JSON: False
** Get Arguments:
- query: '( == regex("test", "i"))'
- fields: 'adapters,,,,,,, labels'
- include_details: False
- include_notes: False
- sort_field: None
- sort_descending: False
- history_date: None
** Exporting to stdout
** Selected Columns:
- agg:internal_axon_id -> Aggregated: Asset Unique ID
- agg:adapter_list_length -> Aggregated: Distinct Adapter Connections Count
- agg:adapters -> Aggregated: Adapter Connections
- agg:name -> Aggregated: Asset Name
- agg:hostname -> Aggregated: Host Name
- agg:last_seen -> Aggregated: Last Seen
- agg:network_interfaces.ips -> Aggregated: Network Interfaces: IPs
- agg:network_interfaces.mac -> Aggregated: Network Interfaces: MAC
- agg:os.type -> Aggregated: OS: Type
- agg:labels -> Aggregated: Tags
** Final Columns:
- internal_axon_id
- adapter_list_length
- adapters
- labels
** PROGRESS: 0.65% [ROWS: 1 / 155] [PAGES: 1 / 155] in 0.97 seconds so far
    "adapter_list_length": 5,
    "adapters": [
    "internal_axon_id": "623de6fad018809afa2f07e4305c90c0",
    "": [
    "": "Tue, 23 Nov 2021 18:02:08 GMT",
    "": [
    "": [
    "": [
    "": [
  }** Stopping JSON processor


There is a lot going on here so let's break it down. First is our command. Just as the UI has a wizard, so does axonshell. We are invoking axonshell's wizard search via "--wiz". We tell it we are doing a "simple" search and then that we want assets who's "hostname contains test". That's one of the reasons I really like using the wizard search in axonshell. It's much nicer to read than AQL and helps avoiding any issues with needing to use shell escapes. We have a good article about this here: Since we are just testing we limit the number of records returned using "--max-pages 1 --max-rows 1".

After our command, you can see a bunch of information echo'd to the screen to show you what the client is doing, how it's interpreting our command and the AQL it generated from our wizard statements. This can be controlled with the echo parameter:

--echo / --no-echo Print out details during fetch [env var:
AX_DO_ECHO; default: True]

Finally you see our returned asset. The default format is JSON but there are other options available.




Please sign in to leave a comment.

Didn't find what you were looking for?

New post