Introduction to the Python CLI

🚧

Open Source Contribution

The python CLI tool is an Open Source project developed and maintained outside of our product engineering teams. For support regarding this tool please visit the Github issues page.

The Python Command Line Interface wraps around the Twingate GraphQL APIs and is designed to automate several administrative functions otherwise available in the Admin Panel including (but not limited to):

  • list / show / add / remove / update for Resources
  • list / show / update trust for Devices
  • list / show / add users / remove users / add resources / remove resources / create / delete for Groups
  • list / show / rename for Connectors
  • list / show for Users
  • list / show / create / delete / add resources / remove resources for Service Accounts
  • show / create / revoke / delete / rename Service Account Keys
  • list / show for Remote Networks

It requires the following:

📘

Finding the Command Line Interface

You can find the latest Python Command Line Interface on Github.

Getting Started

All you need to do in order to get started is to clone the Github repository mentioned above on your own machine.

Once done, open a Terminal window and navigate into the folder containing the CLI and run the following command: python3 ./tgcli.py auth list

If it returns an empty list, you are all set. If it returns an error, it will likely be due to a missing python library. Make sure to install it on your system and retry to command:

python3 ./tgcli.py auth list
['']

CLI Basics

The Command Line Interface is designed for people that have better things to do than memorizing lists of possible parameters.

The most important thing to know is that no matter what parameter(s) you are passing to the CLI, you can always use -h to get a full list of contextual options.

For instance, if you are getting started, you can run the CLI with no option other than -h:

myhost % python3 ./tgcli.py -h       
usage: tgcli.py [-h] [-v] [-s SESSIONNAME] [-f OUTPUTFORMAT]
                {auth,device,connector,user,group,resource,network,account} ...

positional arguments:
  {auth,device,connector,user,group,resource,network,account}

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -s SESSIONNAME, --session SESSIONNAME
                        Session Name
  -f OUTPUTFORMAT, --format OUTPUTFORMAT
                        Output Format <JSON,CSV,DF>

This tells us that the types of objects we can pass to the CLI are, among others:

  • device
  • connector
  • resource
    etc.

So what if we want to figure out what the CLI can do for the resource objects? You guessed it: simply pass the object type ("resource") and -h:

myhost % python3 ./tgcli.py resource -h     
usage: tgcli.py resource [-h] {list,show,create,delete} ...

positional arguments:
  {list,show,create,delete}

optional arguments:
  -h, --help            show this help message and exit

This now tells us that we can use the following operations on the resource object type:

  • list
  • show
  • create
  • delete

Great! Let's take a look at the parameters needed if we want to apply the operation list on the resource object type:

myhost % python3 ./tgcli.py resource list -h
usage: tgcli.py resource list [-h]

optional arguments:
  -h, --help  show this help message and exit

This looks promising: there are no parameter (other than -h) needed for this operation. We should now be able to list all resources in our environment.

Let's try it:

myhost % python3 ./tgcli.py resource list   
usage: tgcli.py [-h] [-v] [-s SESSIONNAME] [-f OUTPUTFORMAT] {auth,device,connector,user,group,resource,network,account} ...
tgcli.py: error: no session name passed

It did not work and the CLI returned an error message complaining about no session name passed. Why? Simply because we have not yet authenticated the CLI against our tenant & API Key so the CLI does not know where to retrieve the information from.

This is where a very special CLI object type comes in: auth

CLI Authentication

Let's apply the same -h logic to our auth object:

myhost % python3 ./tgcli.py auth -h       
usage: tgcli.py auth [-h] {login,logout,list} ...

positional arguments:
  {login,logout,list}

optional arguments:
  -h, --help           show this help message and exit

It looks like we can use three operations on the auth object:

  • login (creates a new session)
  • logout (remove an existing session)
  • list (lists all available sessions)

Let's take a look at the options required for the login operation:

myhost % python3 ./tgcli.py auth login -h
usage: tgcli.py auth login [-h] [-a APIKEY] [-s SESSIONNAME] [-t TENANT]

optional arguments:
  -h, --help            show this help message and exit
  -a APIKEY, --apikey APIKEY
                        API Key
  -s SESSIONNAME, --session SESSIONNAME
                        Session Name (Optional)
  -t TENANT, --tenant TENANT
                        Twingate Network Tenant

It looks like there are 3 parameters to pass, 1 of which is Optional (-s). By now, we already know both our API Key and our Tenant name, so let's run this command with the mandatory parameters (replace mytenant and mytoken with your own values):

myhost % python3 ./tgcli.py auth login -t mytenant -a mytoken
Token Stored in session: OrangeElk

Perfect, we now have a session name we can use for all other CLI calls: this will ensure the CLI uses the right token & tenant name without having to re-authenticate for every single command.

📘

Using a custom session name

You can specify the Session Name you want to use by using the -s option instead of letting it generate a random name for you.

Let's go back to our CLI command to retrieve the list of resources and let's add the -s option with OrangeElk as a value for it:

myhost % python3 ./tgcli.py -s OrangeElk resource list
{
  "data": {
    "resources": {
      "edges": [
        {
          "node": {
            "id": "UmVzb3VyY2U6MjU3Mg==",
            "remoteNetwork": {
              "name": "AWS"
            },
[...]

Excellent! Our CLI now returns the full list of Twingate Resources defined in our environment.

CLI Output Formatting

Since the CLI wraps around the Twingate GraphQL APIs, it returns responses in JSON format by default. JSON is great and easy to process programmatically, unfortunately it isn't very readable for humans and isn't very practical if you want to process the output using an OS Shell scripting language.

This is why the CLI offers 3 separate output formats:

  • JSON (default)
  • CSV (easy to process programmatically with bash or powershell)
  • DF (short for dataframes, a human-readable table format)

Here is the same output in CSV:

myhost % python3 ./tgcli.py -s OrangeElk -f CSV resource list
node.id,node.remoteNetwork.name,node.address.type,node.address.value,node.protocols.allowIcmp,node.protocols.tcp.policy,node.protocols.tcp.ports,node.protocols.udp.policy,node.protocols.udp.ports,node.isActive,node.name,node.createdAt,node.updatedAt
UmVzb3VyY2U6MjU3Mg==,AWS,DNS,twindemo.int,True,ALLOW_ALL,[],ALLOW_ALL,[],True,AWS SSH,2021-01-20T15:54:53.046611+00:00,2022-05-06T21:14:45.766635+00:00
UmVzb3VyY2U6MjkxMw==,AWS,DNS,grafana.twindemo.int,True,ALLOW_ALL,[],ALLOW_ALL,[],True,AWS Grafana Admin,2021-02-09T02:41:48.605518+00:00,2021-10-05T02:08:13.938672+00:00

And here is the same output in DF:

myhost % python3 ./tgcli.py -s OrangeElk -f DF resource list
                     node.id   node.remoteNetwork.name  ...                    node.createdAt                    node.updatedAt
0       UmVzb3VyY2U6MjU3Mg==                       AWS  ...  2021-01-20T15:54:53.046611+00:00  2022-05-06T21:14:45.766635+00:00
1       UmVzb3VyY2U6MjkxMw==                       AWS  ...  2021-02-09T02:41:48.605518+00:00  2021-10-05T02:08:13.938672+00:00

Going Further

You can freely experiment with the various object types supported by the CLI. Remember to periodically pull the latest version of the CLI from its repository.

We will continue to add features to the CLI itself, feel free to make suggestions and reports issues on the repository page itself!


Did this page help you?