Automation with Python-SDK

The Python Software Development Kit (SDK) is a RESTful client for programmatically using the PrivX API. The SDK supports OAuth2.

The SDK supports the functionalities available via the PrivX REST API. Functionalities that require terminal access are not supported. Also, the SDK does not implement support for connection creation and playback. However, connection metadata and trails can be accessed through the SDK.

Installation

To install the Python-SDK:

  • Install directly from Github. We recommend using a Python virtual environment.

    pip install git+git://github.com/SSHcom/privx-sdk-for-python.git
    

Prerequisites

The SDK authenticates against PrivX as an API client. The API client can be given suitable permissions (via roles) to restrict the scope of access.

To configure the SDK with permissions for connecting to the PrivX API:

  1. Create role(s) for providing permissions. To do this, go to the PrivX GUI at Administration→Roles and click Add Role.
  1. Create an API client and assign the created role(s). To do this, goto Administration→Deployment→Integrate with PrivX Using API Clients and click Add API Client.
  1. Obtain the API client authentication details from PrivX UI. In the following example the information is written to a config.py file for the sake of presentation. Typically the details should be either read from environmental variables or from a secret file.
All required credentials will appear here...All required credentials will appear here...

All required credentials will appear here...

Copy the required authentication details to a file named config.py:

HOSTNAME = "privx.example.com"
HOSTPORT = 443

OAUTH_CLIENT_ID = "privx-external"
OAUTH_CLIENT_SECRET = "NcqjYe1FTnGXIR13qy28GQ"

API_CLIENT_ID = "02974636-a30a-4ef9-46ee-974753170f8c"
API_CLIENT_SECRET = "7TdllN+kwkjqQba6UNABcGIZFKP52g7m2sjraGUwkQl8"

CA_CERT = """
-----BEGIN CERTIFICATE-----
MIIFbzCCA1egAwIBAgIIMpiuYyzal70wDQYJKoZIhvcNAQELBQAwJzEVMBMGA1UE
CxMMUHJpdlggVExTIENBMQ4wDAYDVQQDEwVuZ2lueDAeFw0yMTA3MjYxMTMyMjJa
Fw0zMTA3MjQxMTMyMjJaMCcxFTATBgNVBAsTDFByaXZYIFRMUyBDQTEOMAwGA1UE
AxMFbmdpbngwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDge4d/oLU0
NhQftl/0GT889qPr1ZMKLLHb/xnmptJh5YygcWdCf136yFLDNKT4/VT2vZeT/Qw9
H5N12xKzNNtckp2PfDPTA9WdlmW5xNvf9WAs1qiYiPE4t+IDM8akO3HAhTHsthTE
BJ4+n5/LlCc983eqTQhXkriJNiHief90G05eMQWDMsCemES0reMSQHV8Xu6ycb+u
mT/Z7YrtJYaF89fmJu+ajWiaeEqVXPalGaRbsswFSvzrjcUoJz2M5BAaIhIPd0vv
w20HloAahleCPLaiwCoTO5U5i5LXj03smaVrkgdUGDg20rk3TkkWdKTXJG5TdfA1
xj7M3vjhLOJBtSvKsm+I/PX5nRQp1p7pKyTKroKO1da3/wKZKvUWvXNWsrtWORCt
aVIz85dP1Ezs8TUWPWLMM9zxmY0nBb/JXyoF7Zt2uIIUU5XG4mjYG5IhaARgMmLB
Rk6Ig+29oA4Ee5DGSr4BOoh34z8BdNHQu4moIwEvmYfe/n0FSJWUQOsYVd+PVCd+
HNsHMm22pKD/TY2RtBj/Lk0+GaCvz+uCRw5EZ8BSlCtV3oLNkhBi9MdgQqX2Q9Fo
7mro5PDVeIcXx7RffL//komgQG9tQd3D/GcWwmrw0/3QI+QsQJ7Mqh9PdhvroaIc
LTzmC0hjNw4Oe3mY0oIbbBHJNMNfLI1biwIDAQABo4GeMIGbMA4GA1UdDwEB/wQE
AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTWITP0N/5O+VoX3tkm
ZQszoRqWHzBWBgNVHSMETzBNgBTWITP0N/5O+VoX3tkmZQszoRqWH6ErpCkwJzEV
MBMGA1UECxMMUHJpdlggVExTIENBMQ4wDAYDVQQDEwVuZ2lueIIIMpiuYyzal70w
DQYJKoZIhvcNAQELBQADggIBAJm5gqSRL4xUB5sz3srVnmnmiYwtS3xEfpBCHr9e
HbrYa9P/duwJwTdyhqJhySRDn9x0ze/ePBzje5DWiFSekMXBK4Lyy4nt4k6lPe3A
bGoEZuSCJUGff0mQgRkxNlI1o3mY6tfmUKsft6cu6YAB6WP6gi3JyXzPIhgV81hb
R/Y1/AHGz0Bx+HMZ4Nbiy1PqxPd7gTgDIATfgSEbF6BwhUfICrOWPDXftcUdTR67
E3XFU/OPLkzE+0f9/r07YQ/FA9JfOUsjlMuAxbEg9Bgcyr06ie1k/z0T1sd5P/iK
P7y2EkfbDj9EctoQ4Ov+WbwsJyNLXu2JEfJsaokPx7cIcvP+uPEsKAtoOvuyyBzs
PsGGMytbv3LyYDLnItD/E0auNJD9bAzz/HOsfP3vIe/Rj03jpciV3l4plHDjPCG/
aQKWXYAA1fM64pSi3uzLqzSQPBeskcqSWUlJNN2sSO/Gygif4lW2pZWmaHn/QLr+
bzBabBXqifLrQ299iK2Uq5xqJc6UJHgod+lkJ/pujISEXCM/SBavTm7fdAKdM79V
sCOarpz20h5W5jmTcJkJyuI9vH3HOK4h6pjWSUa+ZK9QwkjiTm6e2fLFwuSeegAD
NeJsfXfPh0uBJnqWB5X5tHQqh0hOQfDg2fQ2eW3CF9hZPL1VuYrkUtqFNocvp1uQ
7xDL
-----END CERTIFICATE-----
"""

You have now configured the SDK with permissions for connecting to the PrivX API.

Quick example

Let's create another file test_sdk.py in the same directory as config.py:

import json
import config

import privx_api

api = privx_api.PrivXAPI(
    config.HOSTNAME,
    config.HOSTPORT,
    config.CA_CERT,
    config.OAUTH_CLIENT_ID,
    config.OAUTH_CLIENT_SECRET,
)

resp = api.get_role_store_status()

print(resp.ok)
print(json.dumps(resp.data, indent=3))

Running test_sdk.py should produce a response similar to the following:

True
{
   "version": "99-0 (8aa5ade842f0a8d65d6f332b25d2d532cf72c8a6)",
   "api_version": "v1",
   "status": "RUNNING",
   "status_message": "OK",
   "app_id": "7ffcdea4-68c4-4bc4-4416-84f267627591",
   "server-mode": "",
   "start_time": "2021-07-27T11:36:59.614101032Z"
}

The PrivXAPI class is the backbone of the SDK through which all interaction with PrivX are done.

Note that in the previous example we did not authenticate against PrivX before getting role-store service status. The service status endpoint does not require authentication and would output less information than usual.

Most interactions require authentication using api.authenticate. For example, when creating a PrivX local user:

# skipping imports and initialization of PrivXAPI instance

# authenticated as py-sdk-api client
api.authenticate(config.API_CLIENT_ID, config.API_CLIENT_SECRET)

# required data for user creation
user = {
    "username": "test_user",
    "full_name": "TEST USER",
    "email": "[email protected]",
    "password": {"password": "1234567890"},
    "password_change_required": True,
}

# call the PrivX API endpoint in order to create a user
resp = api.create_user(user)

print(json.dumps(resp.data, indent=3))

After running the previous example, you should get the new user's ID, similar to the following:

{
   "id": "f7568c03-d0e5-465d-44e7-92a159203f72"
}

Now, let`s check the list of PrivX uses via the GUI.

test_user was successfully added via Python-SDK.

Examples

You can find additional SDK examples from the examples directory.

├── examples
│     ├── add-role.py
│     ├── create-secret.py
│     ├── config.py
│     ├── example-host-creation.py
│     ├── example-host-import-json.py
│     ................
├── privx_api
│     ................

Responses

PrivX API returns responses almost always in pure JSON, however, Python-SDK handles those responses a bit for convenience. There are two types of responses in the SDK: REST responses and Stream responses.

All Python-SDK methods return an object of PrivXAPIResponse or PrivXStreamResponse, which has two properties ok type of bool and data type of Dict.

resp = api.create_user(user)

resp.ok // bool
resp.data // dict

REST Response

REST responses are used for operations that do not return files. You can display the response data similar to the following:

response = api.create_user(user)

print(response.data)
{
   "status": 400,
   "details": {
      "error_code": "BAD_REQUEST",
      "details": [
         {
            "property": "username",
            "error_code": "VALUE_DUPLICATE",
            "error_message": "username exists"
         }
      ]
   }
}

Stream Response

Stream response is used when PrivX returns a file. It basically iterates the response chunk by chunk, very handy for writing to a file.

Method download_trail will return a file-object response, which could be written to a file.

resp = api.download_trail(...)

with open("trail.txt", "w") as file:
        for char in resp.iter_content(chunk_size):
            file.write(char.decode("utf-8"))

Now, the file from PrivX was chunked and written to a file in an optimal way.

📘

Note:

When StreamResponse is used, accessing the data property will raise an error. All the response data will be chunked and accessible through iter_content property instead.

Error handling

All handled errors are currently represented with InternalAPIException.

from privx_api import InternalAPIException


resp = api.download_trail(...)
try:
    parse_resp_data(resp.data)
except InternalAPIException:
    logging.error("Response is file-based")
    with open("trail.txt", "w") as file:
        for char in resp.iter_content(chunk_size):
            file.write(char.decode("utf-8"))

🚧

WIP

The Python-SDK is still in the early stage of development, meaning that some functionalities could be changed.


Did this page help you?