This is the demo reference for a Cisco Identity Services Engine (ISE) webinar delivered on October 4, 2022. You may find the recording in the CiscoISE YouTube Channel.
The basic curl commands for REST operations with ISE
The --data option may be used with a local file beginning with @ or use inline JSON:
curl --include --insecure --location \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request POST {URL} \
--data @filename.json
--data '
{
...JSON Data...
}'curl --include --insecure --location \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request GET {URL}curl --include --insecure --location \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request PUT {URL}Available in ISE 3.2+
curl --include --insecure --location \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request PATCH {URL}curl --include --insecure --location \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request DELETE {URL}- ☰ > Administration > System > Settings > API Settings
- Select API Service Settings tab
- ✅ ERS (Read/Write)
- ✅ Open API (Read/Write)
- Save
Download ERS OpenAPI file to local computer for use with Postman later!
- Reveiw the swagger ui
- Create a Repository
{
"name": "FTP",
"protocol": "FTP",
"serverName": "198.18.133.36",
"path": "/",
"userName": "ise",
"password": "C1sco12345"
}- Perform a backup with the repository
- ☰ > Administration > System > Admin Access > Administrators > Admin Groups
- ERS Admin : Full access permission to External RESTful Services (ERS) APIs. Admins assigned to this admin group can perform CRUD (POST, PUT, DELETE, and GET) operations.
- ERS Operator : Read-only access permission to the External RESTful Services (ERS) APIs.
- ☰ > Administration > System > Admin Access > Administrators > Admin Users
- + Add > Create an Admin User
Name:
ers-adminPassword:ISEisC00LAdmin Groups: ERS Admin Submit - + Add > Create an Admin User
Name:
ers-operatorPassword:ISEisC00LAdmin Groups:ERS AdminSubmit
curl is a tool for transfering data from or to a server. It supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET or TFTP. The command is designed to work without user interaction.
curl has many options!
- there is a short option format
-and a long--option format:
curl --help
curl --help allThese are the most popular options that I use:
--head: retrieve headers only--include: include the response headers in the output--insecure: disable certificate validation--location: follow redirects--silent: disable progress meter/bar--output <file>: Write output to<file>instead of stdout--styled-output: Enables the automatic use of bold font styles when writing HTTP headers--verbose: Makes curl verbose during the operation
Basic HTTP GET request:
curl http://ise.securitydemo.netThis returns 301 Moved Permanently 8-(
Use the --include the response headers to make more sense of this:
Include the HTTP response headers in the output
curl --include http://ise.securitydemo.net Update the redirect Location again and again and again!
curl --include https://ise.securitydemo.net
curl --include https://ise.securitydemo.net:443/admin/
curl --include https://ise.securitydemo.net:443/admin/login.jspAnd that is why I like to always use the --location option to automatically follow redirects!
curl --include --location http://ise.securitydemo.net Allow insecure connections with demo or lab instances that do not have a signed certificate:
curl --include --location http://ise.trust0.net
curl --include --insecure --location http://ise.trust0.net Now it is time to try an actual ISE API! See all of the ISE API endpoints/resources @ https://cs.co/ise-api
Also note the resources for Managing APIs via APIs:
- OpenAPI
- ERS API Refer to Versioning for When a specific API endpoint was first supported by ISE. You may need to upgrade to perform some of the things you see here today.
curl --include --location --insecure https://ise.securitydemo.net/ers/config/networkdeviceresults in a 401 Unauthorized because we are not authorized API users.
curl --include --location --insecure --user admin:ISEisC00L https://ise.securitydemo.net/ers/config/networkdeviceResponse:
HTTP/1.1 415 (Unsupported Media Type)
...
<?xml version="1.0" encoding="utf-8" standalone="yes"?><ns3:ersResponse operation="GET-getAll-networkdevice" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns3="ers.ise.cisco.com"><link rel="related" href="https://ise.securitydemo.net/ers/config/networkdevice" type="application/xml"/><messages><message type="ERROR" code="Resource media type exception"><title>Illegal Request Header: one or more of 'accept' / 'content-type' / 'ers-media-type' headers is not supported.</title></message></messages></ns3:ersResponse>
Request XML output with the Accept: header:
curl --insecure --silent \
--user admin:ISEisC00L \
--header 'Accept: application/xml' \
https://ise.securitydemo.net/ers/config/networkdevice \XML in a long, concatenated string is not easy to read. You may use the Unix pipe (|) to redirect it to the xmllint program for pretty printing. A linter is a static code analysis tool for syntax checking.
⚠ You must remove
--includeor the linting will fail!
💡 Use
--silentto remove the progress table
💡 The final
-at the end of the command tells xmllint to usestdinfor the input
curl --insecure --silent \
--user admin:ISEisC00L \
--header 'Accept: application/xml' \
https://ise.securitydemo.net/ers/config/networkdevice \
| xmllint --pretty 1 -Request JSON output instead of XML with the Accept: header:
curl --include --location --insecure --user admin:ISEisC00L --header 'Accept: application/json' https://ise.securitydemo.net/ers/config/networkdeviceYAY! Finally we got a JSON result from ISE!
For ISE versions before ISE 3.1, you will need to specify port 9060 when invoking the ERS APIs:
curl --include --location --insecure --user admin:ISEisC00L --header 'Accept: application/json' https://ise.securitydemo.net:9060/ers/config/networkdeviceIf you are expecting JSON data and you get HTML instead, you either have not enabled APIs or you need to specify the port.
Are these command lines looking long? It's time to break them up so they are easier to read. In the Unix bash shell, the backslash character \ may be used to remove any special meaning for the next character read and for line continuation bash manual. For line continuation, the backslash must be the last character on the line.
curl --include --insecure --location \
--user admin:ISEisC00L \
--header 'Accept: application/json' \
https://ise.securitydemo.net/ers/config/networkdeviceYou may also make JSON data pretty by piping the data through jq, a command line utility for performing JSON queries :
⚠ You must remove
--includeor the linting will fail!
curl --insecure --location --silent \
--user admin:ISEisC00L \
--header 'Accept: application/json' \
https://ise.securitydemo.net/ers/config/networkdevice \
| jqjq is very powerful in extracting JSON data. If you only wanted the network device names, you could do:
curl --insecure --location --silent \
--user admin:ISEisC00L \
--header 'Accept: application/json' \
https://ise.securitydemo.net/ers/config/networkdevice \
| jq '.SearchResult.resources[].name'It's not very interesting with only 1 network device but if you query against endpointgroup or sgt then you can begin to see the power.
Environmental variables are variables that are defined for the current shell and are inherited by any child shells or processes. Environmental variables are used to pass information into processes that are spawned from the shell. Use environment variables to securely load and use your credentials without showing anyone looking over your shoulder or in your terminal history.
You may view all current environment variables with the env command and individual variables with printenv.
env
env | grep ISE
printenv ISE_REST_PASSWORD💡 Environment variables traditionally are named in UPPERCASE while shell variables are lowercase
Define environment variables using the export command:
export ISE_REST_USERNAME=admin
export ISE_REST_PASSWORD=ISEisC00L
export ISE_HOSTNAME=ise.securitydemo.net
env | grep ISEUse environment variables by referencing them with a $. You may show them individually using the echo command :
echo $ISE_REST_USERNAME $ISE_REST_PASSWORD $ISE_HOSTNAMENow try a previous curl command using environment variables:
curl --insecure --location --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
https://$ISE_HOSTNAME/ers/config/networkdeviceSave your environment variables in a text file in ~/.secrets/ directory for fast and easy loading later using the source command:
ls -1 ~/.secrets
cat ~/.secrets/ise_azure.sh
cat ~/.secrets/ise_dcloud.sh
source ~/.secrets/ise_dcloud.sh
env | grep ISEWe previously got information from the ISE ERS API for a network device :
curl --insecure --location --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
https://$ISE_HOSTNAME/ers/config/networkdevicebut this only contains 4 attributes:
idnamedescriptionlink
To get all of the configuration for a specific network device, you must use the name or id attributes which is what the link attribute was showing you:
curl --insecure --location --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
https://$ISE_HOSTNAME/ers/config/networkdevice/{id}GET profilerprofile (>600)
curl --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
https://ise.securitydemo.net/ers/config/profilerprofile \
| jqGET the end of the profilerprofile list
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
"https://ise.securitydemo.net/ers/config/profilerprofile?size=100\&page=7" \
| jq🐞 Filter does not return all of the matching resources! The matching result count is 4 but it only shows 1!
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
https://ise.securitydemo.net/ers/config/profilerprofile?filter=name.STARTSW.iFind endpointgroup
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
https://ise.securitydemo.net:9060/ers/config/endpointgroup \
| jq -c .SearchResult.resources[] \
| grep Meraki -Create a new endpoint
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
https://ise.securitydemo.net:9060/ers/config/endpoint \
--data '
{
"ERSEndPoint" : {
"name" : "New Endpoint",
"description" : "My Endpoint",
"mac" : "FE:ED:DA:DD:BE:EF",
"staticGroupAssignment" : true,
"groupId" : "1e2700a0-8c00-11e6-996c-525400b48521"
}
}'Response Header :
HTTP/1.1 201
Location: https://ise.securitydemo.net:9060/ers/config/endpoint/0bd811b0-892f-11eb-b0e1-b2ca5a4c3815
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
https://ise.securitydemo.net:9060/ers/config/endpoint \
--data @AC17C80C17A2.jsoncurl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Content-Type:application/json' \
--header 'Accept: application/json' \
https://$ISE_HOSTNAME:9060/ers/config/internaluser \
--data '
{
"InternalUser" : {
"name" : "thomas",
"password" : "ISEisC00L",
"changePassword" : false
}
}'Do it again to get a 500 Error because the resource already exists!
⚠ Requires guestapi user!
curl --include --insecure --silent \
--user $guestapi_username:$guestapi_password \
--header 'Content-Type:application/json' \
--header 'Accept: application/json' \
https://$ISE_HOSTNAME:9060/ers/config/guestuser \
--data '
{
"GuestUser": {
"guestType": "Daily (default)",
"portalId" : "bd48c1a1-9477-4746-8e40-e43d20c9f429",
"guestInfo": {
"enabled": "true",
"userName": "rigo",
"password": "ISEisC00L"
},
"guestAccessInfo": {
"validDays": 1,
"fromDate": "03/27/2021 17:40",
"toDate": "03/28/2021 17:40",
"location": "San Jose"
}
}
}'Cisco IP Phone
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--request PUT https://ise.securitydemo.net:9060/ers/config/endpoint \
--data '
{
"ERSEndPoint" : {
"name" : "IP Phone",
"description" : "Thomas IP Phone",
"mac" : "FE:ED:DA:DD:BE:EF",
"staticGroupAssignment" : true,
"groupId" : "14f5cac0-8c00-11e6-996c-525400b48521"
}
}'Response:
HTTP/1.1 200
{
"UpdatedFieldsList" : {
"updatedField" : [ {
"field" : "groupId",
"oldValue" : "1e2700a0-8c00-11e6-996c-525400b48521",
"newValue" : "14f5cac0-8c00-11e6-996c-525400b48521"
}, {
"field" : "description",
"oldValue" : "My Endpoint",
"newValue" : "Thomas IP Phone"
} ]
}
}Change network device name or password
GET hotspotportal (only 1) and look at the detail
curl --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
https://ise.securitydemo.net/ers/config/hotspotportal \
| jqcurl --include --insecure --location \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request GET https://$ISE_HOSTNAME/ers/config/hotspotportal/{id}
curl --include --insecure --location \
--header 'Content-Type:application/json' \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request PATCH https://$ISE_HOSTNAME/ers/config/hotspotportal/{id}} \
--data '
{
"HotspotPortal": {
"settings": {
"aupSettings": {
"requireAccessCode": true,
"accessCode": "ISEisC00L"
}
}
}
}'
curl --include --insecure --location \
--header 'Content-Type:application/json' \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request PATCH https://$ISE_HOSTNAME/ers/config/hotspotportal/{id} \
--data '
{
"HotspotPortal": {
"settings": {
"aupSettings": {
"accessCode": "ISEisC00LerNow"
}
}
}
}'curl --include --insecure --location \
--header 'Content-Type:application/json' \
--header 'Accept: application/json' \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--request DELETE https://$ISE_HOSTNAME/ers/config/networkdevice/{id}
curl --include --insecure --silent \
--user $ISE_REST_USERNAME:$ISE_REST_PASSWORD \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--request DELETE https://ise.securitydemo.net:9060/ers/config/endpoint/{id}ISE 2.7+ portal responds with HTTP/1.1 200 instead of HTTP/1.1 200 OK!
curl --include https://ise.securitydemo.net:8443/portal/PortalSetup.action?portal={id}
- New Workspace
- Workspace Name : give your workspace a name
- Collections : your requests for an API
- APIs : Collections & environments with schemas
- Environments : sets of variables for use in context with requests
Install specific Python version and activate virtual environment
pipenv install --python 3.7
pipenv shell
pipenv install requestsSet a RADIUS secondary shared secret on all network devices
./second_radius_shared_secret.py