> For the complete documentation index, see [llms.txt](https://cortex-docs.paloaltonetworks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cortex-docs.paloaltonetworks.com/microsoft-azure-manual-onboarding/azure-manual-onboarding-guide/azure-manual-onboarding-management-group-or-tenant-scope/phase-3-create-security-capability-roles.md).

# Phase 3: Create security capability roles

Create the roles in the following sections based on the security capabilities you enabled in the Azure onboarding wizard in Cortex during Phase 1. Since each capability is independent, you only need to apply the permissions for the specific features you selected.

> **Note:** The Azure CLI executes commands against your active default subscription. Always switch your terminal context before deploying each per-child-subscription assignment by running:

> ```bash
> az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
> ```

> Where `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription.

### 3.1 DSPM - Data Security Posture Management (optional)

**Module:** DSPM

Execute the steps in this section if you enabled Data Security Posture Management in the Azure onboarding wizard in Cortex.

#### 3.1.1 Create the Cortex-DSPM custom role

Execute the following command to create the Cortex-DSPM custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-DSPM.json << EOF
{
  "Name": "<DSPM_ROLE_NAME>",
  "IsCustom": true,
  "Description": "DSPM control-plane actions: PE approvals, SQL writes, storage/cosmos/cognitive reads. Data-plane perms are in Cortex-DSPM-Data, assigned per subscription.",
  "Actions": [
    "Microsoft.Storage/storageAccounts/PrivateEndpointConnectionsApproval/action",
    "Microsoft.Sql/servers/databases/write",
    "Microsoft.Sql/managedInstances/databases/write",
    "Microsoft.Storage/storageAccounts/read",
    "Microsoft.Storage/storageAccounts/blobServices/containers/read",
    "Microsoft.Storage/storageAccounts/fileServices/shares/read",
    "Microsoft.Search/searchServices/read",
    "Microsoft.Search/searchServices/indexes/read",
    "Microsoft.Search/searchServices/indexers/read",
    "Microsoft.Search/searchServices/dataSources/read",
    "Microsoft.Search/searchServices/listAdminKeys/action",
    "Microsoft.Search/searchServices/listQueryKeys/action",
    "Microsoft.Search/searchServices/PrivateEndpointConnectionsApproval/action",
    "Microsoft.DocumentDB/databaseAccounts/readOnlyKeys/action"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-DSPM.json
```

{% endcode %}

Where:

* `<DSPM_ROLE_NAME>` is your chosen role name (e.g., `Cortex-DSPM`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.1.2 Assign the Cortex-DSPM custom role at root management group

{% code overflow="wrap" %}

```bash
az role assignment create   --role "<DSPM_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/providers/Microsoft.Management/managementGroups/<MG_ID>"
```

{% endcode %}

Where:

* `<DSPM_ROLE_NAME>` is your chosen role name (e.g., `Cortex-DSPM`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.1.3 Create the Cortex-DSPM-Data custom role

Execute the following command to create the Cortex-DSPM-Data custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-DSPM-Data.json << EOF
{
  "Name": "<DSPM_DATA_ROLE_NAME>",
  "IsCustom": true,
  "Description": "DSPM data-plane (storage blob/file read, Cognitive Services read). Defined at MG scope, assigned per child subscription. Paired with Cortex-DSPM control-plane role.",
  "Actions": [],
  "DataActions": [
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
    "Microsoft.Storage/storageAccounts/fileServices/fileshares/files/read",
    "Microsoft.CognitiveServices/accounts/OpenAI/files/read",
    "Microsoft.CognitiveServices/accounts/OpenAI/fine-tunes/read",
    "Microsoft.CognitiveServices/accounts/OpenAI/models/read",
    "Microsoft.CognitiveServices/accounts/AIServices/connections/read",
    "Microsoft.CognitiveServices/accounts/AIServices/fine_tuning/read",
    "Microsoft.CognitiveServices/accounts/AIServices/agents/read",
    "Microsoft.Search/searchServices/indexes/documents/read"
  ],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-DSPM-Data.json
```

{% endcode %}

Where:

* `<DSPM_DATA_ROLE_NAME>` is your chosen role name (e.g., `Cortex-DSPM-Data`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.1.4 Provision the Cortex resource group and the Cortex-DSPM-RG custom role

Use these commands to provision the dedicated `<RG_NAME>` resource group within your child subscription and define the custom role at the root management group scope.

{% code overflow="wrap" %}

```bash
# Per child subscription: create the shared resource group
az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
az group create   --name "<RG_NAME>"   --location "<LOCATION>"   --tags managed_by=paloaltonetworks

# Once at MG scope: define the RG-scoped role
cat > /tmp/Cortex-DSPM-RG.json << EOF
{
  "Name": "<DSPM_RG_ROLE_NAME>",
  "IsCustom": true,
  "Description": "DSPM resource-group-scoped: VNET/subnet/NSG/RouteTable/SQL writes inside the shared resource group. Defined at MG scope, assigned per child RG.",
  "Actions": [
    "*/read",
    "Microsoft.Network/routeTables/write",
    "Microsoft.Network/routeTables/join/action",
    "Microsoft.Network/routeTables/delete",
    "Microsoft.Network/virtualNetworks/delete",
    "Microsoft.Network/virtualNetworks/join/action",
    "Microsoft.Network/virtualNetworks/subnets/delete",
    "Microsoft.Network/virtualNetworks/subnets/join/action",
    "Microsoft.Network/virtualNetworks/subnets/write",
    "Microsoft.Network/virtualNetworks/write",
    "Microsoft.Network/networkSecurityGroups/securityRules/write",
    "Microsoft.Network/networkSecurityGroups/securityRules/delete",
    "Microsoft.Network/networkSecurityGroups/join/action",
    "Microsoft.Network/networkSecurityGroups/delete",
    "Microsoft.Network/networkSecurityGroups/write",
    "Microsoft.Sql/servers/databases/read",
    "Microsoft.Sql/servers/databases/write",
    "Microsoft.Sql/servers/databases/resume/action",
    "Microsoft.Sql/servers/databases/delete",
    "Microsoft.Sql/servers/delete",
    "Microsoft.Sql/servers/write",
    "Microsoft.Sql/servers/virtualNetworkRules/write",
    "Microsoft.Sql/servers/privateEndpointConnectionsApproval/action",
    "Microsoft.Sql/managedInstances/*"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-DSPM-RG.json
```

{% endcode %}

Where:

* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription
* `<RG_NAME>` is your chosen resource group name (e.g. `cortex-dspm-rg`)
* `<LOCATION>` is the Azure region where you want to create your resource group (e.g. `eastus`)
* `<DSPM_RG_ROLE_NAME>` is your chosen role name (e.g. `Cortex-DSPM-RG`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.1.5 Assign the three subscription-level DSPM roles to each child subscription

Execute this script block for every child subscription to target the correct subscription and assign the custom data, resource group, and Key Vault roles to the Cortex service principal:

{% code overflow="wrap" %}

```bash
az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
az role assignment create --role "<DSPM_DATA_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>"

az role assignment create --role "<DSPM_RG_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>/resourceGroups/<RG_NAME>"

az role assignment create --role "Key Vault Crypto Service Encryption User"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>"
```

{% endcode %}

Where:

* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription
* `<DSPM_DATA_ROLE_NAME>` is your chosen role name (e.g., `Cortex-DSPM-Data`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<DSPM_RG_ROLE_NAME>` is your chosen role name (e.g. `Cortex-DSPM-RG`)

***

### 3.2 ADS - Agentless Disk Scanning (optional)

**Module:** ADS

Execute the steps in this section if you enabled Agentless Disk Scanning in the Azure onboarding wizard in Cortex.

#### 3.2.1 Create the Cortex-ADS custom role

Execute the following commands to create the Cortex-ADS custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-ADS.json << EOF
{
  "Name": "<ADS_ROLE_NAME>",
  "IsCustom": true,
  "Description": "ADS subscription-scoped: snapshots, gallery image versions, disks, VM tagging.",
  "Actions": [
    "Microsoft.Compute/virtualMachines/read",
    "Microsoft.Compute/snapshots/read",
    "Microsoft.Compute/snapshots/write",
    "Microsoft.Compute/disks/write",
    "Microsoft.Compute/disks/read",
    "Microsoft.Compute/disks/delete",
    "Microsoft.Compute/galleries/images/read",
    "Microsoft.Compute/galleries/images/versions/read",
    "Microsoft.Compute/disks/beginGetAccess/action"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-ADS.json
```

{% endcode %}

Where:

* `<ADS_ROLE_NAME>` is your chosen role name (e.g., `Cortex-ADS`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.2.2 Assign the Cortex-ADS custom role at root management group

{% code overflow="wrap" %}

```bash
az role assignment create   --role "<ADS_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/providers/Microsoft.Management/managementGroups/<MG_ID>"
```

{% endcode %}

Where:

* `<ADS_ROLE_NAME>` is your chosen role name (e.g., `Cortex-ADS`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.2.3 Create the shared image gallery

Repeat this step for each child subscription. Note that the specific host subscription's gallery resource ID is the value you will report back to Cortex during Phase 5.

{% code overflow="wrap" %}

```bash
az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
az group create --name "<RG_NAME>" --location "<LOCATION>"   --tags managed_by=paloaltonetworks

az sig create   --resource-group "<RG_NAME>"   --gallery-name "<ADS_GALLERY_NAME>"   --location "<LOCATION>"   --tags managed_by=paloaltonetworks

# On the host subscription, store the gallery ID to report back to Cortex
export ADS_IMAGE_GALLERY_RESOURCE_ID=$(az sig show   --resource-group "<RG_NAME>"   --gallery-name "<ADS_GALLERY_NAME>"   --query id -o tsv)
echo "ADS_IMAGE_GALLERY_RESOURCE_ID=${ADS_IMAGE_GALLERY_RESOURCE_ID}"
```

{% endcode %}

Where:

* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription
* `<RG_NAME>` is your chosen resource group name (e.g. `cortex-ads-rg`)
* `<LOCATION>` is the Azure region where you want to create your resource group (e.g. `eastus`)
* `<ADS_GALLERY_NAME>` is your chosen gallery name (e.g. `cortex_ads_gallery`)

#### 3.2.4 Create the Cortex-ADS-RG custom role

Execute the following command to create the Cortex-ADS-RG custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-ADS-RG.json << EOF
{
  "Name": "<ADS_RG_ROLE_NAME>",
  "IsCustom": true,
  "Description": "ADS resource-group-scoped: snapshot operations and gallery write inside the shared resource group. Defined at MG scope, assigned per child RG.",
  "Actions": [
    "Microsoft.Compute/snapshots/write",
    "Microsoft.Compute/snapshots/delete",
    "Microsoft.Compute/galleries/images/write",
    "Microsoft.Compute/galleries/images/delete",
    "Microsoft.Compute/galleries/images/versions/read",
    "Microsoft.Compute/galleries/images/versions/write",
    "Microsoft.Compute/galleries/images/versions/delete"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-ADS-RG.json
```

{% endcode %}

Where:

* `<ADS_RG_ROLE_NAME>` is your chosen role name (e.g., `Cortex-ADS-RG`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.2.5 Assign Cortex-ADS-RG custom role at the resource group scope

Execute the following commands for all child subscriptions to update your active subscription context and create the required resource group assignment:

{% code overflow="wrap" %}

```bash
az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
az role assignment create --role "<ADS_RG_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>/resourceGroups/<RG_NAME>"
```

{% endcode %}

Where:

* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription
* `<ADS_RG_ROLE_NAME>` is your chosen role name (e.g., `Cortex-ADS-RG`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<RG_NAME>` is your chosen resource group name (e.g. `cortex-ads-rg`)

***

### 3.3 Registry Scanning (optional)

**Module:** REGISTRY

Execute the steps in this section if you enabled Registry Scanning in the Azure onboarding wizard in Cortex.

#### 3.3.1 Create the Cortex-Registry custom role

Execute the following commands to create the Cortex-Registry custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-Registry.json << EOF
{
  "Name": "<REGISTRY_ROLE_NAME>",
  "IsCustom": true,
  "Description": "Registry scanning (public + private endpoints).",
  "Actions": [
    "Microsoft.ContainerRegistry/registries/pull/read",
    "Microsoft.ContainerRegistry/registries/read",
    "Microsoft.ContainerRegistry/registries/PrivateEndpointConnectionsApproval/action"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-Registry.json
```

{% endcode %}

Where:

* `<REGISTRY_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Registry`)

#### 3.3.2 Assign the Cortex-Registry custom role at the root management group scope

Execute this command once at the management group scope to assign the registry role globally across all inherited child subscriptions:

{% code overflow="wrap" %}

```bash
az role assignment create   --role "<REGISTRY_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/providers/Microsoft.Management/managementGroups/<MG_ID>"
```

{% endcode %}

Where:

* `<REGISTRY_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Registry`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

***

### 3.4 Automation (optional)

**Module:** AUTOMATION

Execute the steps in this section if you enabled Automation in the Azure onboarding wizard in Cortex.

#### 3.4.1 Create the Cortex-Automation custom role for the control plane only

Azure prevents roles with data-plane permissions from being assigned at the management group scope, so the data-plane permissions must be separated into a distinct subscription-level role (detailed in section 3.4.3). Note that while the data-plane permissions are made per subscription, you define the Cortex-Automation custom role for the control plane only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-Automation.json << EOF
{
  "Name": "<AUTOMATION_ROLE_NAME>",
  "IsCustom": true,
  "Description": "Automation control-plane actions (MG-assignable). Data-plane perms are in Cortex-Automation-Data, assigned per subscription.",
  "Actions": [
    "Microsoft.Network/networkSecurityGroups/read",
    "Microsoft.Network/networkSecurityGroups/securityRules/read",
    "Microsoft.Network/networkSecurityGroups/securityRules/write",
    "Microsoft.Network/networkSecurityGroups/securityRules/delete",
    "Microsoft.Network/networkInterfaces/read",
    "Microsoft.Network/publicIPAddresses/read",
    "Microsoft.Storage/storageAccounts/read",
    "Microsoft.Storage/storageAccounts/write",
    "Microsoft.Storage/storageAccounts/blobServices/read",
    "Microsoft.Storage/storageAccounts/blobServices/write",
    "Microsoft.Storage/storageAccounts/blobServices/containers/delete",
    "Microsoft.Storage/storageAccounts/blobServices/containers/write",
    "Microsoft.Storage/storageAccounts/blobServices/containers/read",
    "Microsoft.Storage/storageAccounts/blobServices/containers/setAcl/action",
    "Microsoft.Authorization/policyAssignments/read",
    "Microsoft.Authorization/policyAssignments/write",
    "Microsoft.Web/sites/config/read",
    "Microsoft.Web/sites/config/write",
    "Microsoft.Web/sites/read",
    "Microsoft.Web/sites/write",
    "Microsoft.DBforMySQL/flexibleServers/configurations/read",
    "Microsoft.DBforMySQL/flexibleServers/configurations/write",
    "Microsoft.Insights/logprofiles/read",
    "Microsoft.Insights/logprofiles/write",
    "Microsoft.Compute/disks/read",
    "Microsoft.Compute/disks/write",
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/powerOff/action",
    "Microsoft.Compute/virtualMachines/read",
    "Microsoft.ContainerRegistry/registries/read",
    "Microsoft.ContainerRegistry/registries/write",
    "Microsoft.KeyVault/vaults/read",
    "Microsoft.KeyVault/vaults/write",
    "Microsoft.Sql/servers/databases/securityAlertPolicies/read",
    "Microsoft.Sql/servers/databases/securityAlertPolicies/write",
    "Microsoft.DocumentDB/databaseAccounts/read",
    "Microsoft.DocumentDB/databaseAccounts/write",
    "Microsoft.Sql/servers/databases/transparentDataEncryption/read",
    "Microsoft.Sql/servers/databases/transparentDataEncryption/write",
    "Microsoft.Resources/subscriptions/read",
    "Microsoft.Resources/subscriptions/resourceGroups/read",
    "Microsoft.Consumption/usageDetails/read",
    "Microsoft.Consumption/budgets/read",
    "Microsoft.CostManagement/forecast/read",
    "Microsoft.Network/networkSecurityGroups/write",
    "Microsoft.Network/networkInterfaces/write",
    "Microsoft.Network/virtualNetworks/subnets/join/action",
    "Microsoft.Network/publicIPAddresses/join/action",
    "Microsoft.Network/networkSecurityGroups/join/action",
    "Microsoft.Network/loadBalancers/backendAddressPools/join/action"
  ],
  "DataActions": [],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-Automation.json
```

{% endcode %}

Where:

* `<AUTOMATION_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Automation`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.4.2 Assign the Cortex-Automation custom role at the root management group scope

{% code overflow="wrap" %}

```bash
az role assignment create   --role "<AUTOMATION_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/providers/Microsoft.Management/managementGroups/<MG_ID>"
```

{% endcode %}

Where:

* `<AUTOMATION_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Automation`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.4.3 Create the Cortex-Automation-Data custom role

Execute the following commands to create the Cortex-Automation-Data custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-Automation-Data.json << EOF
{
  "Name": "<AUTOMATION_DATA_ROLE_NAME>",
  "IsCustom": true,
  "Description": "Automation data-plane (blob read/write/tags). Defined at MG scope, assigned per child subscription. Paired with Cortex-Automation control-plane role.",
  "Actions": [],
  "DataActions": [
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags/read",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags/write",
    "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write"
  ],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-Automation-Data.json
```

{% endcode %}

Where:

* `<AUTOMATION_DATA_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Automation-Data`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.4.4 Assign the Cortex-Automation-Data custom role to each child subscription

{% code overflow="wrap" %}

```bash
az account set --subscription "<CHILD_SUBSCRIPTION_ID>"
az role assignment create --role "<AUTOMATION_DATA_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>"
```

{% endcode %}

Where:

* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription
* `<AUTOMATION_DATA_ROLE_NAME>` is your chosen role name (e.g., `Cortex-Automation-Data`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant

***

### 3.5 Serverless Scanning (optional)

**Module:** SERVERLESS

The permissions required for serverless scanning are already covered by the Cortex-Platform-Base role created in Phase 2.

***

### 3.6 Kubernetes Security (optional)

**Module:** KUBERNETES

Execute the steps in this section if you enabled Kubernetes Security in the Azure onboarding wizard in Cortex. Enable this section if you have Kubernetes Security enabled in the Cortex Console. Because this custom role contains data-plane actions (`DataActions`), the role definition must be created and assigned individually within each child subscription.

#### 3.6.1 Create the Cortex-KSPM custom role

Execute the following commands to create the Cortex-KSPM custom role. This step is performed only once at the root management group level.

{% code overflow="wrap" %}

```bash
cat > /tmp/Cortex-KSPM.json << EOF
{
  "Name": "<KSPM_ROLE_NAME>",
  "IsCustom": true,
  "Description": "KSPM Agentless K8s Reader: lists AKS cluster-user credentials and reads Kubernetes data-plane resources via Azure RBAC for Kubernetes Authorization. Defined at MG scope, assigned per child subscription.",
  "Actions": [
    "Microsoft.ContainerService/managedClusters/listClusterUserCredential/action"
  ],
  "DataActions": [
    "Microsoft.ContainerService/managedClusters/namespaces/read",
    "Microsoft.ContainerService/managedClusters/pods/read",
    "Microsoft.ContainerService/managedClusters/services/read",
    "Microsoft.ContainerService/managedClusters/endpoints/read",
    "Microsoft.ContainerService/managedClusters/configmaps/read",
    "Microsoft.ContainerService/managedClusters/serviceaccounts/read",
    "Microsoft.ContainerService/managedClusters/nodes/read",
    "Microsoft.ContainerService/managedClusters/secrets/read",
    "Microsoft.ContainerService/managedClusters/apps/deployments/read",
    "Microsoft.ContainerService/managedClusters/apps/replicasets/read",
    "Microsoft.ContainerService/managedClusters/apps/statefulsets/read",
    "Microsoft.ContainerService/managedClusters/apps/daemonsets/read",
    "Microsoft.ContainerService/managedClusters/batch/jobs/read",
    "Microsoft.ContainerService/managedClusters/batch/cronjobs/read",
    "Microsoft.ContainerService/managedClusters/networking.k8s.io/ingresses/read",
    "Microsoft.ContainerService/managedClusters/networking.k8s.io/networkpolicies/read",
    "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/roles/read",
    "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/clusterroles/read",
    "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/rolebindings/read",
    "Microsoft.ContainerService/managedClusters/rbac.authorization.k8s.io/clusterrolebindings/read",
    "Microsoft.ContainerService/managedClusters/discovery.k8s.io/endpointslices/read"
  ],
  "NotActions": [],
  "NotDataActions": [],
  "AssignableScopes": [
    "/providers/Microsoft.Management/managementGroups/<MG_ID>"
  ]
}
EOF
az role definition create --role-definition /tmp/Cortex-KSPM.json
```

{% endcode %}

Where:

* `<KSPM_ROLE_NAME>` is your chosen role name (e.g., `Cortex-KSPM`)
* `<MG_ID>` is the root management group name (or tenant ID for tenant root management group scope)

#### 3.6.2 Assign the Cortex-KSPM custom role to each child subscription

{% code overflow="wrap" %}

```bash
az role assignment create --role "<KSPM_ROLE_NAME>"   --assignee-object-id "<CORTEX_OBJECT_ID>" --assignee-principal-type ServicePrincipal   --scope "/subscriptions/<CHILD_SUBSCRIPTION_ID>"
```

{% endcode %}

Where:

* `<KSPM_ROLE_NAME>` is your chosen role name (e.g., `Cortex-KSPM`)
* `<CORTEX_OBJECT_ID>` is the Cortex service principal object ID in your tenant
* `<CHILD_SUBSCRIPTION_ID>` is the ID of the child subscription


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://cortex-docs.paloaltonetworks.com/microsoft-azure-manual-onboarding/azure-manual-onboarding-guide/azure-manual-onboarding-management-group-or-tenant-scope/phase-3-create-security-capability-roles.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
