Cisco Secure Access Resource Groups and Private Resources sample script

Resource Groups and Private Resources API Guide

This guide provides Python client samples for the Cisco Secure Access Private Resources and Groups API.

Note: Your Secure Access API key must have the permissions to read and write on the policies key scope. For more information about the API key scopes, see Secure Access OAuth 2.0 Scopes.

First get your Secure Access API key, set up your environment, and install the Secure Access API client. For more information, see Samples Overview.

Run the Script

  1. Copy the script to a local file called main.py. Locate the script in your environment in a directory above the cisco directory.
  2. Run python3 main.py.

main.py

"""
Copyright (c) 2025 Cisco and/or its affiliates.
This software is licensed to you under the terms of the Cisco Sample
Code License, Version 1.1 (the "License"). You may obtain a copy of the
License at

https://developer.cisco.com/docs/licenses

All use of the material herein must be in accordance with the terms of
the License. All rights not expressly granted by the License are
reserved. Unless required by applicable law or agreed to separately in
writing, software distributed under the License is distributed on an "AS
IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied.
"""

import requests
from requests_toolbelt import MultipartEncoder
import json
import os
from dotenv import load_dotenv

from cisco.secure_access import API
from cisco.secure_access import policies
from cisco.secure_access import GET
from cisco.secure_access import POST
from cisco.secure_access import PUT
from cisco.secure_access import DELETE
from cisco.secure_access import token_url
from cisco.secure_access import client_id
from cisco.secure_access import client_secret

# Private Resources API endpoints
private_resource_groups_endpoint = 'privateResourceGroups'
private_resources_endpoint = 'privateResources'
private_resource_groups_details_endpoint = 'privateResourceGroups/{}'
private_resources_details_endpoint = 'privateResources/{}'

load_dotenv()

# Private Resource Groups
def get_private_resource_groups(api):
    ''' Get Private Resource Groups. '''
    try:
        # Get Private Resource Groups in the organization
        response = api.Query(policies, private_resource_groups_endpoint, GET)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. GET {private_resource_groups_endpoint}, {response.json()}")
            return response.json()
        else:
            print(f"Failed to get the Private Resource Groups. Status code: {response.status_code}, Response: {response.text}.")
            return None
    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}.")

def post_private_resource_groups(api, name=None, description=None, resourceIds=None):
    ''' Create a Private Resource Group. '''
    try:
        if name is None or description is None or resourceIds is None:
            raise ValueError("name, description, or resourceIds are required to create the Private Resource Group.")

        # Prepare the payload
        payload = {
            "name": name,
            "description": description,
            "resourceIds": resourceIds
        }

        # Create a Private Resource Group
        response = api.Query(policies, private_resource_groups_endpoint, POST, payload)

        # Check the response status
        if response.status_code == 201:
            print(f"Success. POST {private_resource_groups_endpoint}, {response.json()}")
            return response.json()
        else:
            print(f"Failed to create the Private Resource Group. Status code: {response.status_code}, Response: {response.text}.")
            return None
    except Exception as e:
        print(f"An error occurred: {e}.")

def get_resource_groups_ids(private_resource_groups_response):
    resourceGroupIds = []
    if 'items' in private_resource_groups_response:
        for i, resource in enumerate(private_resource_groups_response['items']):
            resourceGroupIds.append(resource['resourceGroupId'])
            if i == 5:
                break
    return resourceGroupIds

def get_resources_ids(private_resources_response):
    resourceIds = []
    if 'items' in private_resources_response:
        for i, resource in enumerate(private_resources_response['items']):
            resourceIds.append(resource['resourceId'])
            if i == 4:
                break
    return resourceIds

def get_private_resource_group(api, id):
    ''' Get the properties of the Private Resource Group. '''
    try:
        if id is None:
            raise ValueError("id is required to get the Private Resource Group.")
        url = private_resource_groups_details_endpoint.format(id)

        # Get the properties for the Private Resource Group
        response = api.Query(policies, url, GET)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. GET {url}, {response.json()}.")
            return response.json()
        else:
            print(f"Failed to get the Private Resource Group {id}. Status code: {response.status_code}, Response: {response.text}.")
            return
    except Exception as e:
        print(f"An error occurred: {e}.")

def put_private_resource_group(api, id, name=None, description=None, resourceIds=None):
    ''' Update the properties of the Private Resource Group. '''
    try:
        if id is None:
            raise ValueError("id is required to get the Private Resource Group.")

        if name is None or description is None or resourceIds is None:
            raise ValueError("name, description, or resourceIds are required to create the Private Resource Group.")

        # Prepare the payload
        payload = {
            "name": name,
            "description": description,
            "resourceIds": resourceIds
        }

        url = private_resource_groups_details_endpoint.format(id)

        # Update the properties for the Private Resource Group
        response = api.Query(policies, url, PUT, payload)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. PUT {url}, {response.json()}.")
            return response.json()
        else:
            print(f"Failed to update the Private Resource Group {id}. Status code: {response.status_code}, Response: {response.text}.")
            return
    except Exception as e:
        print(f"An error occurred: {e}.")

def delete_private_resource_group(api, id):
    ''' Delete the Private Resource Group. '''
    try:
        if id is None:
            raise ValueError("id is required to delete the Private Resource Group.")
        url = private_resource_groups_details_endpoint.format(id)

        # Delete the Private Resource Group
        response = api.Query(policies, url, DELETE)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"DELETE {url} Response: {response.text}.")
        else:
            print(f"Failed to delete the Private Resource Group {id}. Status code: {response.status_code}, Response: {response.text}.")
    except Exception as e:
        print(f"An error occurred: {e}.")

# Private Resources
def get_private_resources(api):
    ''' Get Private Resources. '''
    try:
        # Get Private Resources in the organization
        response = api.Query(policies, private_resources_endpoint, GET)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. GET {private_resources_endpoint}, {response.json()}")
            return response.json()
        else:
            print(f"Failed to get the Private Resources. Status code: {response.status_code}, Response: {response.text}.")
            return None
    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}.")

def post_private_resources(api, name=None, accessTypes=None, resourceAddresses=None):
    ''' Create a Private Resource. '''
    try:
        if name is None or accessTypes is None or resourceAddresses is None:
            raise ValueError("name, accessTypes, or resourceAddresses are required to create the Private Resource.")

        # Prepare the payload
        payload = {
            "name": name,
            "accessTypes": accessTypes,
            "resourceAddresses": resourceAddresses
        }

        # Create a Private Resource Group
        response = api.Query(policies, private_resources_endpoint, POST, payload)

        # Check the response status
        if response.status_code == 201:
            print(f"Success. POST {private_resources_endpoint}, {response.json()}")
            return response.json()
        else:
            print(f"Failed to create the Private Resource. Status code: {response.status_code}, Response: {response.text}.")
            return None
    except Exception as e:
        print(f"An error occurred: {e}.")

def get_private_resource(api, id):
    ''' Get the properties of the Private Resource. '''
    try:
        if id is None:
            raise ValueError("id is required to get the Private Resource.")
        url = private_resources_details_endpoint.format(id)

        # Get the properties for the Private Resource
        response = api.Query(policies, url, GET)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. GET {url}, {response.json()}.")
            return response.json()
        else:
            print(f"Failed to get the Private Resource {id}. Status code: {response.status_code}, Response: {response.text}.")
            return
    except Exception as e:
        print(f"An error occurred: {e}.")

def put_private_resource(api, id, name=None, accessTypes=None, resourceAddresses=None):
    ''' Update the properties of the Private Resource. '''
    try:
        if id is None:
            raise ValueError("id is required to get the Private Resource.")

        if name is None or accessTypes is None or resourceAddresses is None:
            raise ValueError("name, accessTypes, or resourceAddresses are required to create the Private Resource.")

        # Prepare the payload
        payload = {
            "name": name,
            "accessTypes": accessTypes,
            "resourceAddresses": resourceAddresses
        }
        url = private_resources_details_endpoint.format(id)

        # Update the properties for the Private Resource
        response = api.Query(policies, url, PUT, payload)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"Success. PUT {url}, {response.json()}.")
            return response.json()
        else:
            print(f"Failed to update the Private Resource {id}. Status code: {response.status_code}, Response: {response.text}.")
            return
    except Exception as e:
        print(f"An error occurred: {e}.")

def delete_private_resource(api, id):
    ''' Delete the Private Resource. '''
    try:
        if id is None:
            raise ValueError("id is required to delete the Private Resource.")
        url = private_resources_details_endpoint.format(id)

        # Delete the Private Resource
        response = api.Query(policies, url, DELETE)

        # Check if the API request was successful
        if response.status_code == 200:
            print(f"DELETE {url} Response: {response.text}.")
        else:
            print(f"Failed to delete the Private Resource {id}. Status code: {response.status_code}, Response: {response.text}.")
    except Exception as e:
        print(f"An error occurred: {e}.")

def main():
    # Exit out if the required client_id or client_secret is not set
    for var in ['API_KEY', 'API_SECRET', 'OUTPUT_DIR']:
        if os.environ.get(var) == None:
            print("Required environment variable: {} not set".format(var))
            exit()

    # Get an API token
    api = API(token_url, client_id, client_secret)

    try:
        # get the private resources in the organization
        json_data = get_private_resources(api)
        resourceIds = get_resources_ids(json_data)

        # get the private resource groups in the organization
        json_data = get_private_resource_groups(api)
        #resourceGroupIds = get_resource_groups_ids(json_data)

        # create a private resource
        accessTypes = [
            {
                "type": "network"
            }
        ]
        resourceAddresses = [
            {
                "destinationAddr": [ "example.com" ],
                "protocolPorts": [
                    {
                        "protocol":  "HTTP/HTTPS",
                        "ports": "80"
                    }
                ]
            }
        ]
        name = 'tesy38zresourcea'
        json_data = post_private_resources(api, name, accessTypes, resourceAddresses)
        resourceId = json_data['resourceId']

        # create a private resource group
        group_name = 'tes25ayty'
        description = "description for private resource group"
        json_data = post_private_resource_groups(api, group_name, description, resourceIds)

        resourceGroupId = 0
        if 'resourceGroupId' in json_data:
            resourceGroupId = json_data['resourceGroupId']

        # get a private resource group
        json_data = get_private_resource_group(api, resourceGroupId)

        # update a private resource group
        # only delete the one that is created as part of this workflow
        resourceIds = []
        resourceIds.append(resourceId)
        group_name = "test45tz"
        json_data = put_private_resource_group(api, resourceGroupId, group_name, resourceIds)

        # get a private resource        
        json_data = get_private_resource(api, resourceId)

        # update a private resource
        resource_name = 'test25newnamey'
        json_data = put_private_resource(api, resourceId, resource_name, accessTypes, resourceAddresses)

        # delete a private resource
        delete_private_resource(api, resourceId)

        # delete a private resource group
        # This should fail with 404 Client Error: NOT FOUND. The resource group was deleted when the private resource was deleted in the previous request.
        delete_private_resource_group(api, resourceGroupId)
    except Exception as e:
        print(e)

# main
if __name__ == "__main__":
    main()