Skip to content

Commit

Permalink
Merge pull request #2 from dodevops/feature/dpr/spcreds
Browse files Browse the repository at this point in the history
feat: Support service principal credentials for apps as well
  • Loading branch information
dploeger authored Jun 10, 2024
2 parents 3ed25ee + be5221d commit c52da33
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 10 deletions.
4 changes: 2 additions & 2 deletions charts/azure-app-exporter/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ apiVersion: v2
name: azure-app-exporter
description: Exposing Prometheus Metrics for Azure Service Principals
type: application
version: 0.2.0
appVersion: "0.1.35"
version: 0.3.0
appVersion: "0.1.36"
keywords:
- azure
- prometheus
Expand Down
37 changes: 29 additions & 8 deletions src/services/azure_app_service.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from datetime import datetime
from typing import List, Optional

from msgraph.graph_service_client import GraphServiceClient
from msgraph.generated.models.application import Application
from msgraph.generated.models.key_credential import KeyCredential
from msgraph.generated.models.password_credential import PasswordCredential
from msgraph.generated.service_principals.service_principals_request_builder import ServicePrincipalsRequestBuilder
from msgraph.graph_service_client import GraphServiceClient
from prometheus_client import Gauge
from prometheus_client import REGISTRY

from models import AppRegistration
from models.app_registration import Credential
Expand All @@ -33,7 +33,7 @@ async def get_all(self) -> List[AppRegistration]:
result = await self.client.applications.get()
apps = []
while result is not None:
apps += [AzureAppService._map_app(a) for a in result.value]
apps += [await self._map_app(a) for a in result.value]
if result.odata_next_link is None:
break
result = await self.client.applications.with_url(result.odata_next_link).get()
Expand All @@ -44,17 +44,34 @@ async def get_all(self) -> List[AppRegistration]:
async def get_by(self, app_id: str) -> AppRegistration:
result = await self.client.applications.by_application_id(app_id).get()
if result is not None:
return AzureAppService._map_app(result)
return await self._map_app(result)
else:
raise "Application with app id %s not found." % app_id

@staticmethod
def _map_app(app: Application) -> AppRegistration:
async def _map_app(self, app: Application) -> AppRegistration:
app_id = app.app_id
name = app.display_name
creds = [AzureAppService._map_cred(c) for c in app.password_credentials + app.key_credentials]
sp_creds = await self._fetch_sp_creds(app_id)
creds = []
for cred in app.password_credentials + app.key_credentials + sp_creds:
if len([c for c in creds if c.name == cred.display_name]) == 0:
creds.append(self._map_cred(cred))
return AppRegistration(id=app_id, name=name, credentials=creds)

async def _fetch_sp_creds(self, app_id):
query_params = ServicePrincipalsRequestBuilder.ServicePrincipalsRequestBuilderGetQueryParameters(
search=f'\"appId:{app_id}\"'
)
request_configuration = ServicePrincipalsRequestBuilder.ServicePrincipalsRequestBuilderGetRequestConfiguration(
query_parameters=query_params,
)
request_configuration.headers.add("ConsistencyLevel", "eventual")
response = await self.client.service_principals.get(request_configuration=request_configuration)
sp_creds = []
if len(response.value) > 0:
sp_creds = response.value[0].key_credentials + response.value[0].password_credentials
return sp_creds

@staticmethod
def _map_cred(cred: KeyCredential | PasswordCredential) -> Credential:
return Credential(
Expand All @@ -73,4 +90,8 @@ def observe(apps: List[AppRegistration]):
if expiry:
APP_EXPIRY.labels(app_id=app.id, app_name=app.name).set(int(expiry.timestamp()))
for cred in app.credentials:
APP_CREDS_EXPIRY.labels(app_id=app.id, app_name=app.name, credential_name=cred.name).set(int(cred.expires.timestamp()))
(
APP_CREDS_EXPIRY
.labels(app_id=app.id, app_name=app.name, credential_name=cred.name)
.set(int(cred.expires.timestamp()))
)

0 comments on commit c52da33

Please sign in to comment.