or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-reviews.mdalerts.mdauth-config.mdcore-rbac.mdindex.mdlegacy-admin.mdmetrics.mdpim.md

metrics.mddocs/

0

# Metrics and Monitoring

1

2

Role assignment metrics and operational monitoring capabilities for analyzing authorization usage patterns and performance. These operations provide insights into RBAC usage, PIM metrics, and overall authorization health across Azure resources.

3

4

## Capabilities

5

6

### Role Assignment Metrics

7

8

Analyze role assignment patterns, usage statistics, and governance metrics across Azure subscriptions and resources.

9

10

```python { .api }

11

def get_metrics_for_subscription(subscription_id: str) -> RoleAssignmentMetrics:

12

"""

13

Get role assignment metrics for a subscription.

14

15

Parameters:

16

- subscription_id: Azure subscription ID to get metrics for

17

18

Returns:

19

RoleAssignmentMetrics object with usage statistics and patterns

20

"""

21

22

def get_metrics_for_management_group(management_group_id: str) -> RoleAssignmentMetrics:

23

"""

24

Get role assignment metrics for a management group.

25

26

Parameters:

27

- management_group_id: Management group ID to get metrics for

28

29

Returns:

30

RoleAssignmentMetrics object with aggregated metrics across the management group

31

"""

32

```

33

34

### Operations Metadata

35

36

Discover and monitor available Azure Authorization operations and their metadata for API usage analysis.

37

38

```python { .api }

39

def list() -> Iterator[Operation]:

40

"""

41

List all available operations in the Azure Authorization resource provider.

42

43

Returns:

44

Iterator of Operation objects describing available authorization operations

45

"""

46

```

47

48

## Usage Examples

49

50

### Analyzing Role Assignment Patterns

51

52

```python

53

from azure.mgmt.authorization import AuthorizationManagementClient

54

from azure.identity import DefaultAzureCredential

55

56

# Initialize client

57

credential = DefaultAzureCredential()

58

client = AuthorizationManagementClient(

59

credential=credential,

60

subscription_id="your-subscription-id"

61

)

62

63

# Get role assignment metrics for subscription

64

metrics = client.role_assignment_metrics.get_metrics_for_subscription(

65

subscription_id="your-subscription-id"

66

)

67

68

print("Role Assignment Metrics:")

69

print(f"Total Assignments: {metrics.total_role_assignments}")

70

print(f"Total Principals: {metrics.total_principals}")

71

print(f"Total Roles: {metrics.total_role_definitions}")

72

print(f"Privileged Assignments: {metrics.privileged_role_assignments}")

73

74

# Analyze assignment distribution

75

if metrics.role_assignment_breakdown:

76

print("\nRole Assignment Breakdown:")

77

for role_name, count in metrics.role_assignment_breakdown.items():

78

print(f" {role_name}: {count} assignments")

79

80

# Check for potential issues

81

if metrics.excessive_permissions_count > 0:

82

print(f"\nWarning: {metrics.excessive_permissions_count} assignments with excessive permissions")

83

84

if metrics.stale_assignments_count > 0:

85

print(f"Warning: {metrics.stale_assignments_count} potentially stale assignments")

86

```

87

88

### Monitoring API Operations Usage

89

90

```python

91

# List all available authorization operations

92

operations = client.operations.list()

93

94

print("Available Authorization Operations:")

95

for operation in operations:

96

print(f"Operation: {operation.name}")

97

print(f"Display Name: {operation.display.operation}")

98

print(f"Resource: {operation.display.resource}")

99

print(f"Provider: {operation.display.provider}")

100

print(f"Description: {operation.display.description}")

101

print("---")

102

103

# Filter operations by category

104

rbac_operations = [op for op in operations if 'roleAssignments' in op.name]

105

pim_operations = [op for op in operations if 'schedule' in op.name.lower()]

106

review_operations = [op for op in operations if 'accessReview' in op.name]

107

108

print(f"\nRBAC Operations: {len(rbac_operations)}")

109

print(f"PIM Operations: {len(pim_operations)}")

110

print(f"Access Review Operations: {len(review_operations)}")

111

```

112

113

### Management Group Metrics Analysis

114

115

```python

116

# Analyze metrics across a management group hierarchy

117

management_group_id = "your-management-group-id"

118

119

try:

120

mg_metrics = client.role_assignment_metrics.get_metrics_for_management_group(

121

management_group_id=management_group_id

122

)

123

124

print(f"Management Group Metrics for: {management_group_id}")

125

print(f"Total Child Subscriptions: {mg_metrics.subscription_count}")

126

print(f"Total Role Assignments: {mg_metrics.total_role_assignments}")

127

print(f"Inherited Assignments: {mg_metrics.inherited_assignments}")

128

print(f"Direct Assignments: {mg_metrics.direct_assignments}")

129

130

# Analyze consistency across subscriptions

131

if mg_metrics.subscription_metrics:

132

print("\nPer-Subscription Breakdown:")

133

for sub_metric in mg_metrics.subscription_metrics:

134

print(f" Subscription {sub_metric.subscription_id}:")

135

print(f" Assignments: {sub_metric.assignment_count}")

136

print(f" Unique Principals: {sub_metric.principal_count}")

137

138

except Exception as e:

139

print(f"Error retrieving management group metrics: {e}")

140

```

141

142

### Governance and Compliance Reporting

143

144

```python

145

from datetime import datetime, timedelta

146

147

# Generate a comprehensive governance report

148

def generate_governance_report(subscription_id):

149

"""Generate a comprehensive governance report for a subscription."""

150

151

# Get metrics

152

metrics = client.role_assignment_metrics.get_metrics_for_subscription(subscription_id)

153

154

# Get current assignments for detailed analysis

155

assignments = list(client.role_assignments.list_for_subscription())

156

157

# Analyze assignment age and patterns

158

now = datetime.utcnow()

159

old_assignments = []

160

privileged_assignments = []

161

162

privileged_roles = [

163

"Owner", "Contributor", "User Access Administrator",

164

"Security Administrator", "Global Administrator"

165

]

166

167

for assignment in assignments:

168

# Check for old assignments (example: older than 90 days)

169

if assignment.created_on and (now - assignment.created_on) > timedelta(days=90):

170

old_assignments.append(assignment)

171

172

# Check for privileged roles

173

role_name = get_role_name(assignment.role_definition_id) # Helper function

174

if role_name in privileged_roles:

175

privileged_assignments.append(assignment)

176

177

# Generate report

178

report = {

179

"subscription_id": subscription_id,

180

"report_date": now.isoformat(),

181

"summary": {

182

"total_assignments": len(assignments),

183

"old_assignments": len(old_assignments),

184

"privileged_assignments": len(privileged_assignments),

185

"compliance_score": calculate_compliance_score(metrics, assignments)

186

},

187

"recommendations": generate_recommendations(metrics, assignments)

188

}

189

190

return report

191

192

def get_role_name(role_definition_id):

193

"""Helper function to get role name from role definition ID."""

194

try:

195

role_def = client.role_definitions.get_by_id(role_definition_id)

196

return role_def.role_name

197

except:

198

return "Unknown"

199

200

def calculate_compliance_score(metrics, assignments):

201

"""Calculate a simple compliance score based on best practices."""

202

score = 100

203

204

# Deduct points for potential issues

205

if metrics.excessive_permissions_count > 0:

206

score -= min(20, metrics.excessive_permissions_count * 2)

207

208

if metrics.stale_assignments_count > 0:

209

score -= min(15, metrics.stale_assignments_count * 1)

210

211

# Check for too many owners

212

owner_count = len([a for a in assignments if "Owner" in get_role_name(a.role_definition_id)])

213

if owner_count > 5:

214

score -= min(10, (owner_count - 5) * 2)

215

216

return max(0, score)

217

218

def generate_recommendations(metrics, assignments):

219

"""Generate actionable recommendations based on analysis."""

220

recommendations = []

221

222

if metrics.stale_assignments_count > 0:

223

recommendations.append({

224

"priority": "High",

225

"category": "Access Review",

226

"description": f"Review {metrics.stale_assignments_count} stale role assignments",

227

"action": "Conduct access review to remove unused assignments"

228

})

229

230

if metrics.excessive_permissions_count > 0:

231

recommendations.append({

232

"priority": "Medium",

233

"category": "Least Privilege",

234

"description": f"{metrics.excessive_permissions_count} assignments may have excessive permissions",

235

"action": "Review and apply principle of least privilege"

236

})

237

238

return recommendations

239

240

# Generate and display report

241

report = generate_governance_report("your-subscription-id")

242

print(f"Governance Report for {report['subscription_id']}")

243

print(f"Compliance Score: {report['summary']['compliance_score']}/100")

244

print("\nRecommendations:")

245

for rec in report['recommendations']:

246

print(f"- [{rec['priority']}] {rec['description']}")

247

print(f" Action: {rec['action']}")

248

```

249

250

## Types

251

252

### Metrics Types

253

254

```python { .api }

255

class RoleAssignmentMetrics:

256

subscription_id: Optional[str]

257

management_group_id: Optional[str]

258

total_role_assignments: Optional[int]

259

total_principals: Optional[int]

260

total_role_definitions: Optional[int]

261

privileged_role_assignments: Optional[int]

262

excessive_permissions_count: Optional[int]

263

stale_assignments_count: Optional[int]

264

role_assignment_breakdown: Optional[Dict[str, int]]

265

principal_type_breakdown: Optional[Dict[str, int]]

266

created_date: Optional[datetime]

267

last_updated: Optional[datetime]

268

269

class ManagementGroupMetrics(RoleAssignmentMetrics):

270

subscription_count: Optional[int]

271

inherited_assignments: Optional[int]

272

direct_assignments: Optional[int]

273

subscription_metrics: Optional[List[SubscriptionMetric]]

274

275

class SubscriptionMetric:

276

subscription_id: Optional[str]

277

assignment_count: Optional[int]

278

principal_count: Optional[int]

279

role_count: Optional[int]

280

last_modified: Optional[datetime]

281

```

282

283

### Operations Types

284

285

```python { .api }

286

class Operation:

287

name: Optional[str]

288

display: Optional[OperationDisplay]

289

origin: Optional[str]

290

is_data_action: Optional[bool]

291

292

class OperationDisplay:

293

provider: Optional[str]

294

resource: Optional[str]

295

operation: Optional[str]

296

description: Optional[str]

297

298

class OperationListResult:

299

value: Optional[List[Operation]]

300

next_link: Optional[str]

301

```

302

303

## Constants

304

305

### Metrics Categories

306

307

```python { .api }

308

class MetricCategory:

309

ROLE_ASSIGNMENTS = "RoleAssignments"

310

PRINCIPALS = "Principals"

311

ROLE_DEFINITIONS = "RoleDefinitions"

312

PERMISSIONS = "Permissions"

313

COMPLIANCE = "Compliance"

314

315

class AssignmentStatus:

316

ACTIVE = "Active"

317

STALE = "Stale"

318

EXCESSIVE = "Excessive"

319

COMPLIANT = "Compliant"

320

321

class PrincipalTypeBreakdown:

322

USER = "User"

323

GROUP = "Group"

324

SERVICE_PRINCIPAL = "ServicePrincipal"

325

MANAGED_IDENTITY = "ManagedIdentity"

326

```

327

328

### Operation Origins

329

330

```python { .api }

331

class OperationOrigin:

332

USER = "user"

333

SYSTEM = "system"

334

USER_SYSTEM = "user,system"

335

336

class OperationCategory:

337

RBAC = "rbac"

338

PIM = "pim"

339

ACCESS_REVIEWS = "accessReviews"

340

ALERTS = "alerts"

341

METRICS = "metrics"

342

```

343

344

## API Version Support

345

346

### Role Assignment Metrics

347

- **API Version**: 2019-08-01-preview

348

- **Status**: Preview

349

- **Scope**: Subscription and Management Group levels

350

351

### Operations

352

- **API Versions**: 2018-05-01-preview, 2021-01-01-preview, 2021-03-01-preview, 2021-07-01-preview, 2021-12-01-preview

353

- **Status**: Generally Available (latest versions)

354

- **Scope**: Resource provider level

355

356

## Performance Considerations

357

358

### Metrics Collection

359

360

Role assignment metrics can be resource-intensive for large environments:

361

362

```python

363

# For large subscriptions, consider pagination and filtering

364

def get_metrics_efficiently(subscription_id, max_assignments=1000):

365

"""Get metrics efficiently for large subscriptions."""

366

367

# First, get a sample of assignments to estimate scope

368

sample_assignments = list(client.role_assignments.list_for_subscription(

369

filter=f"$top={min(100, max_assignments)}"

370

))

371

372

if len(sample_assignments) < 100:

373

# Small subscription, get full metrics

374

return client.role_assignment_metrics.get_metrics_for_subscription(subscription_id)

375

else:

376

# Large subscription, get metrics with sampling

377

print(f"Large subscription detected ({len(sample_assignments)}+ assignments)")

378

print("Using sampling approach for metrics collection...")

379

380

# Custom metrics calculation with sampling

381

return calculate_sampled_metrics(subscription_id, sample_assignments)

382

383

def calculate_sampled_metrics(subscription_id, sample_assignments):

384

"""Calculate approximate metrics using sampling."""

385

# Implementation would extrapolate from sample data

386

# This is a simplified example

387

estimated_total = len(sample_assignments) * 10 # Rough estimate

388

389

return {

390

"subscription_id": subscription_id,

391

"estimated_total_assignments": estimated_total,

392

"sample_size": len(sample_assignments),

393

"note": "Metrics calculated using sampling due to large dataset"

394

}

395

```

396

397

## Error Handling

398

399

Common exceptions with metrics operations:

400

401

```python

402

from azure.core.exceptions import ResourceNotFoundError, BadRequestError

403

404

try:

405

metrics = client.role_assignment_metrics.get_metrics_for_subscription(subscription_id)

406

except ResourceNotFoundError:

407

print("Subscription not found or no metrics available")

408

except BadRequestError:

409

print("Invalid subscription ID or request parameters")

410

except Exception as e:

411

print(f"Unexpected error retrieving metrics: {e}")

412

413

try:

414

operations = list(client.operations.list())

415

except Exception as e:

416

print(f"Error listing operations: {e}")

417

```

418

419

## Integration with Monitoring Tools

420

421

### Azure Monitor Integration

422

423

```python

424

# Example: Send metrics to Azure Monitor (requires azure-monitor-ingestion)

425

def send_metrics_to_monitor(metrics):

426

"""Send role assignment metrics to Azure Monitor."""

427

428

from azure.monitor.ingestion import LogsIngestionClient

429

430

# This is a conceptual example

431

monitor_client = LogsIngestionClient(endpoint="...", credential=credential)

432

433

# Prepare metrics for ingestion

434

log_data = {

435

"TimeGenerated": datetime.utcnow().isoformat(),

436

"SubscriptionId": metrics.subscription_id,

437

"TotalAssignments": metrics.total_role_assignments,

438

"PrivilegedAssignments": metrics.privileged_role_assignments,

439

"ComplianceScore": calculate_compliance_score(metrics, [])

440

}

441

442

# Send to custom log table

443

monitor_client.upload(

444

rule_id="your-data-collection-rule",

445

stream_name="Custom-AuthorizationMetrics_CL",

446

logs=[log_data]

447

)

448

```

449

450

### Power BI Integration

451

452

Metrics can be exported for Power BI reporting:

453

454

```python

455

import json

456

import pandas as pd

457

458

def export_metrics_for_powerbi(subscription_ids):

459

"""Export metrics in format suitable for Power BI."""

460

461

all_metrics = []

462

463

for sub_id in subscription_ids:

464

try:

465

metrics = client.role_assignment_metrics.get_metrics_for_subscription(sub_id)

466

all_metrics.append({

467

"SubscriptionId": sub_id,

468

"TotalAssignments": metrics.total_role_assignments,

469

"TotalPrincipals": metrics.total_principals,

470

"PrivilegedAssignments": metrics.privileged_role_assignments,

471

"StaleAssignments": metrics.stale_assignments_count,

472

"LastUpdated": metrics.last_updated.isoformat() if metrics.last_updated else None

473

})

474

except Exception as e:

475

print(f"Error getting metrics for {sub_id}: {e}")

476

477

# Convert to DataFrame and export

478

df = pd.DataFrame(all_metrics)

479

df.to_csv("authorization_metrics.csv", index=False)

480

df.to_json("authorization_metrics.json", orient="records", indent=2)

481

482

return df

483

```