Security Group Tags API

Overview

Security Group Tags (SGTs) enable software-defined segmentation. Endpoints receive SGTs during authorization, and SGACLs enforce policy between groups.

SGT URL

/ers/config/sgt

SGACL URL

/ers/config/sgacl

Mapping URL

/ers/config/sgmapping

Matrix URL

/ers/config/egressmatrixcell

Setup

dsource d000 dev/network
ISE_HOST="${ISE_PAN_IP}"
ISE_AUTH="${ISE_API_USER}:${ISE_API_PASS}"
BASE_URL="https://${ISE_HOST}:9060/ers/config"

Security Group Tags

List All SGTs

netapi
netapi ise get-sgts
curl
# List all SGTs
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Accept: application/json" | jq '.SearchResult.resources[] | {name, id}'

List with Tag Values

# List SGTs with their tag values
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Accept: application/json" | jq -r '.SearchResult.resources[].id' | \
  while read ID; do
    curl -sk -u "${ISE_AUTH}" \
      "${BASE_URL}/sgt/${ID}" \
      -H "Accept: application/json" | jq -r '.Sgt | "\(.value)\t\(.name)\t\(.description // "-")"'
  done | sort -n | column -t -s$'\t'

Get SGT by Name

netapi
netapi ise get-sgt "Employees"
curl
# Get SGT by name
SGT_NAME="Employees"
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt/name/${SGT_NAME}" \
  -H "Accept: application/json" | jq '.Sgt'

Get SGT by Value

# Get SGT by tag value
SGT_VALUE="4"
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Accept: application/json" | jq -r '.SearchResult.resources[].id' | \
  while read ID; do
    SGT=$(curl -sk -u "${ISE_AUTH}" \
      "${BASE_URL}/sgt/${ID}" \
      -H "Accept: application/json")

    VALUE=$(echo "$SGT" | jq -r '.Sgt.value')
    if [ "$VALUE" = "$SGT_VALUE" ]; then
      echo "$SGT" | jq '.Sgt'
      break
    fi
  done

Create SGT

netapi
netapi ise create-sgt "Linux_Workstations" \
  --value 10 \
  --description "Linux workstations with EAP-TLS authentication"
curl
# Create new SGT
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "Sgt": {
      "name": "Linux_Workstations",
      "description": "Linux workstations with EAP-TLS authentication",
      "value": 10,
      "propogateToApic": true
    }
  }'

Create with Reserved Range

# Create SGT with value in custom range
# ISE reserves 0-15 for system use, use 16+ for custom

# Define SGT scheme
# 16-99: Infrastructure (servers, network devices)
# 100-199: Users (employees, contractors, guests)
# 200-254: IoT and special devices
# 255: Quarantine

curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "Sgt": {
      "name": "Domain_Controllers",
      "description": "Active Directory domain controllers",
      "value": 16,
      "propogateToApic": true
    }
  }'

Update SGT

netapi
netapi ise update-sgt "Linux_Workstations" \
  --description "Updated: Linux workstations - production EAP-TLS"
curl
# Update SGT description
SGT_NAME="Linux_Workstations"

# Get current SGT
SGT=$(curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt/name/${SGT_NAME}" \
  -H "Accept: application/json")

SGT_ID=$(echo "$SGT" | jq -r '.Sgt.id')
SGT_VALUE=$(echo "$SGT" | jq -r '.Sgt.value')

curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt/${SGT_ID}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X PUT \
  -d '{
    "Sgt": {
      "id": "'"${SGT_ID}"'",
      "name": "'"${SGT_NAME}"'",
      "description": "Updated: Linux workstations - production EAP-TLS",
      "value": '"${SGT_VALUE}"',
      "propogateToApic": true
    }
  }'

Delete SGT

netapi
netapi ise delete-sgt "Test_SGT"
curl
# Delete SGT (must not be in use)
SGT_ID="abc123-def456"
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt/${SGT_ID}" \
  -X DELETE

Security Group ACLs

List SGACLs

# List Security Group ACLs
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgacl" \
  -H "Accept: application/json" | jq '.SearchResult.resources[] | {name, id}'

Get SGACL

# Get SGACL content
SGACL_NAME="Permit_IP"
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgacl/name/${SGACL_NAME}" \
  -H "Accept: application/json" | jq '.Sgacl'

Create SGACL

# Create SGACL
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgacl" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "Sgacl": {
      "name": "Linux_to_Servers",
      "description": "Allow Linux to access servers",
      "aclcontent": "permit tcp dst eq 22\npermit tcp dst eq 443\npermit tcp dst eq 3389\ndeny ip"
    }
  }'

IP-SGT Mappings

List Mappings

# List IP-to-SGT static mappings
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgmapping" \
  -H "Accept: application/json" | jq '.SearchResult.resources[] | {name, id}'

Create Mapping

# Create static IP-to-SGT mapping
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgmapping" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "SGMapping": {
      "name": "Server_Subnet",
      "sgt": "Servers",
      "deployType": "ALL",
      "hostIp": "10.50.20.0",
      "hostName": "server-subnet"
    }
  }'

Egress Matrix

# Get egress matrix cells (source -> destination policies)
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/egressmatrixcell" \
  -H "Accept: application/json" | jq '.SearchResult.resources[] | {id}'

# Get specific cell
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/egressmatrixcell?filter=sourceSgtId.EQ.4&filter=destinationSgtId.EQ.6" \
  -H "Accept: application/json" | jq '.SearchResult.resources[0]'

Common Patterns

SGT Assignment in AuthZ Profile

# Create authz profile that assigns SGT
SGT_VALUE="10"  # Linux_Workstations

curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/authorizationprofile" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "AuthorizationProfile": {
      "name": "Linux-EAP-TLS-TrustSec",
      "description": "EAP-TLS with SGT assignment",
      "accessType": "ACCESS_ACCEPT",
      "authzProfileType": "SWITCH",
      "vlan": {"nameID": "DATA", "tagID": 10},
      "advancedAttributes": [
        {
          "leftHandSideDictionaryAttribue": {
            "AdvancedAttributeValueType": "AdvancedDictionaryAttribute",
            "dictionaryName": "Cisco",
            "attributeName": "cisco-av-pair"
          },
          "rightHandSideAttribueValue": {
            "AdvancedAttributeValueType": "AttributeValue",
            "value": "cts:security-group-tag='"${SGT_VALUE}"'-00"
          }
        }
      ]
    }
  }'

Export TrustSec Config

# Export full TrustSec configuration
mkdir -p trustsec-backup

echo "Exporting SGTs..."
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgt" \
  -H "Accept: application/json" | jq -r '.SearchResult.resources[].id' | \
  while read ID; do
    curl -sk -u "${ISE_AUTH}" \
      "${BASE_URL}/sgt/${ID}" \
      -H "Accept: application/json"
  done | jq -s '.' > trustsec-backup/sgts.json

echo "Exporting SGACLs..."
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgacl" \
  -H "Accept: application/json" | jq -r '.SearchResult.resources[].id' | \
  while read ID; do
    curl -sk -u "${ISE_AUTH}" \
      "${BASE_URL}/sgacl/${ID}" \
      -H "Accept: application/json"
  done | jq -s '.' > trustsec-backup/sgacls.json

echo "Exporting IP-SGT Mappings..."
curl -sk -u "${ISE_AUTH}" \
  "${BASE_URL}/sgmapping" \
  -H "Accept: application/json" | jq -r '.SearchResult.resources[].id' | \
  while read ID; do
    curl -sk -u "${ISE_AUTH}" \
      "${BASE_URL}/sgmapping/${ID}" \
      -H "Accept: application/json"
  done | jq -s '.' > trustsec-backup/mappings.json

echo "TrustSec configuration exported to trustsec-backup/"

SGT Usage Report

# Generate SGT usage report from active sessions
echo "SGT Usage Report"
echo "================"

# Get SGT assignments from active sessions (via MnT)
curl -sk -u "${ISE_AUTH}" \
  "https://${ISE_HOST}/admin/API/mnt/Session/ActiveList" \
  -H "Accept: application/xml" | \
  grep -oP '(?<=<security_group>)[^<]+' | sort | uniq -c | sort -rn