Find Expired Service Principal
Tags: azure, azurecli
Published: 2020-08-11 00:49:53

My tenant seems to have a quota limit of the Service Principal. 

```bash
$ az ad sp create-for-rbac
The directory object quota limit for the Principal has been exceeded. Please ask your administrator to increase the quota limit or delete objects to reduce the used quota.
```

Since I'm a DevOps guy, I frequently create a service principal. I'd like to find expired service principals on my tenant.

I struggled for a while with [OData](https://docs.microsoft.com/en-us/azure/search/search-query-odata-filter) and [JMESPath](https://jmespath.org/examples.html) that is supported with `az` command. I eventually use `jq` instead. 

# Get the current date with the Azure CLI format. 
We can use `%N` for nanosecond, however, it doesn't match the style of the Azure CLI output. I eventually use this command.

```bash
CURRENT_TIME=`date -u +'%Y-%m-%dT%H:%M:%S.024000+00:00'`
```

# Get Expired Service Principal

The query is only list the service principal that you create with password credentials.

```bash
$ az ad sp list --show-mine | jq ".[] | select(.passwordCredentials[].endDate < \"$CURRENT_TIME\") | { objectId : .objectId, appId: .appId, passwordCredentials : .passwordCredentials, displayName: .displayName, tenantId : .appOwnerTenantId }" 
```
`az ad sp list --show-mine` will show the service principals that you created. `select` will filter the json. The json start with array that has no name. so start with `.[]`. `.[]` returns each element of the array. After filter the result, it project some values. 


## The original structure of the `az ad sp list --show-time`

```
[{
  "appId": "YOUR_APP_ID_HERE",
  "appOwnerTenantId": "YOUR_TENANT_ID_HERE",
  "displayName": "procohapp10",
  "objectId": "YOUR_OBJECT_ID_HERE",
  "passwordCredentials": [
    {
      "additionalProperties": null,
      "customKeyIdentifier": null,
      "endDate": "2019-05-02T20:32:27.908964+00:00",
      "keyId": "YOUR_KEY_ID",
      "startDate": "2018-05-02T20:32:27.908964+00:00",
      "value": null
    }
  ],
             :
},
  :
}
```

## Result

```
{
  "objectId": "YOUR_OBJECT_ID",
  "appId": "YOUR_APP_ID",
  "passwordCredentials": [
    {
      "additionalProperties": null,
      "customKeyIdentifier": null,
      "endDate": "2019-05-02T20:32:27.908964+00:00",
      "keyId": "YOUR_KEY_ID",
      "startDate": "2018-05-02T20:32:27.908964+00:00",
      "value": null
    }
  ],
  "displayName": "procohapp10",
  "tenantId": "YOUR_TENANT_ID"
}
```

# Remove the expired service principal

Please double check if your script works before execute the second last line.

```bash
$ az ad sp list --show-mine | jq ".[] | select(.passwordCredentials[].endDate < \"$CURRENT_TIME\") | .objectId" > sp_list.txt
$ lines=`cat sp_list.txt`
$ for item in $lines; do  echo $item | xargs az ad sp delete --id ; done
$ rm sp_list.txt
```

## Confirm removed

It returns zero result.

```bash
$ az ad sp list --show-mine | jq ".[] | select(.passwordCredentials[].endDate < \"$CURRENT_TIME\") | .objectId" 
```

# Resource

* [jq tutorial](https://stedolan.github.io/jq/tutorial/)
* [Filter json with jq command (Japanese)](https://qiita.com/buntafujikawa/items/a769ebabbdd324ff0d6f)
* [Get an existing service principal](https://docs.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest#get-an-existing-service-principal)
* [How to Use xargs on Linux](https://linuxhint.com/xargs_linux/)