Skip to content

Commit 9279ea1

Browse files
EppOfmonbillard
authored andcommitted
Add support for Azure Workload Identity
1 parent 110245a commit 9279ea1

File tree

4 files changed

+193
-13
lines changed

4 files changed

+193
-13
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pip install prometrix
2626
```
2727

2828

29-
> **⚠️ Note:** For Python **3.8 support**, you must use version **0.2.3 or below** of `prometrix`.
29+
> **⚠️ Note:** For Python **3.8 support**, you must use version **0.2.3 or below** of `prometrix`.
3030
> From `0.2.4` onward, `prometrix` requires **Python ≥ 3.9**.
3131
3232
Usage
@@ -84,6 +84,8 @@ azure_config = AzurePrometheusConfig(
8484
azure_client = get_custom_prometheus_connect(azure_config)
8585
```
8686

87+
prometrix supports Azure Managed Identity and Azure Workload Identity. See [Azure Authentication Setup](/azure-auth-setup.rst) for more details.
88+
8789
Similar configuration and creation can be done for EKS, Thanos, and Victoria Metrics Prometheus.
8890

8991
> **_NOTE:_** You need to replace the placeholder values (e.g., YOUR_CORALOGIX_PROMETHEUS_TOKEN) with your actual credentials and endpoints.

azure-auth-setup.rst

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
Azure managed Prometheus
2+
*************************
3+
4+
In order to authenticate against the Azure Monitor Workspace Query endpoint, you have multiple options:
5+
6+
- Create an Azure Active Directory authentication app (Option #1)
7+
8+
- Pros:
9+
10+
- Quick setup. Just need to create an app, get the credentials and add them to the manifests
11+
- Other pods can't use the Service Principal without having the secret
12+
13+
- Cons:
14+
15+
- Requires a service principal (Azure AD permission)
16+
- Need the client secret in the kubernetes manifests
17+
- Client secret expires, you need to manage its rotation
18+
19+
- Use Kubelet's Managed Identity (Option #2)
20+
21+
- Pros:
22+
23+
- Quick setup. Get the Managed Identity Client ID and add them to the manifests
24+
- No need to manage secrets. Removing the password element decreases the risk of the credentials being compromised
25+
26+
- Cons:
27+
28+
- Managed Identity is bound to the AKS nodepool, so any pods can use it if they know/get the client ID
29+
30+
- Use Azure AD Workload Identity (Option #3)
31+
32+
- Pros:
33+
34+
- Most secure option as Managed Identity is only bound to the pod. No other pods can use it
35+
- No need to manage secrets. Removing the password element decreases the risk of the credentials being compromised
36+
37+
- Cons:
38+
39+
- Extra setup needed: need AKS cluster with Workload Identity add-on enabled, get the OIDC issuer URL and add it to the manifests
40+
41+
Get the Azure prometheus query endpoint
42+
=========================================
43+
44+
1. Go to `Azure Monitor workspaces <https://portal.azure.com/#view/HubsExtension/BrowseResource/resourceType/microsoft.monitor%2Faccounts>`_ and choose your monitored workspace.
45+
2. In your monitored workspace, `overview`, find the ``Query endpoint`` and copy it.
46+
47+
Option #1: Create an Azure authentication app
48+
==============================================
49+
50+
We will now create an Azure authentication app and get the necesssary credentials so Robusta can access Prometheus data.
51+
52+
1. Follow this Azure guide to `Register an app with Azure Active Directory <https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/prometheus-self-managed-grafana-azure-active-directory#register-an-app-with-azure-active-directory>`_
53+
54+
.. code-block:: python
55+
56+
# Create a custom Prometheus client for Azure Prometheus using Service Principal Authentication
57+
azure_config = AzurePrometheusConfig(
58+
url="https://azure-prometheus.example.com", # Replace with your Azure Monitor workspace query endpoint
59+
disable_ssl=False,
60+
azure_resource="https://prometheus.monitor.azure.com", # Default resource for Azure Monitor
61+
azure_token_endpoint="https://azure-token.example.com",
62+
azure_client_id="YOUR_AZURE_CLIENT_ID",
63+
azure_tenant_id="YOUR_AZURE_TENANT_ID",
64+
azure_client_secret="YOUR_AZURE_CLIENT_SECRET",
65+
additional_labels={"job": "azure-prometheus"},
66+
)
67+
azure_client = get_custom_prometheus_connect(azure_config)
68+
69+
3. Complete the `Allow your app access to your workspace <https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/prometheus-self-managed-grafana-azure-active-directory#allow-your-app-access-to-your-workspace>`_ step, so your app can query data from your Azure Monitor workspace.
70+
71+
Option #2: Use Kubelet's Managed Identity
72+
==============================================
73+
74+
1. Get the AKS kubelet's Managed Identity Client ID:
75+
76+
.. code-block:: bash
77+
78+
az aks show -g <resource-group> -n <cluster-name> --query identityProfile.kubeletidentity.clientId -o tsv
79+
80+
2. Set the following settings based from the previous step.
81+
82+
.. code-block:: python
83+
84+
# Create a custom Prometheus client for Azure Prometheus using Azure Managed Identity
85+
azure_config = AzurePrometheusConfig(
86+
url="https://azure-prometheus.example.com", # Replace with your Azure Monitor workspace query endpoint
87+
disable_ssl=False,
88+
azure_use_managed_id=True,
89+
azure_resource="https://prometheus.monitor.azure.com", # Default resource for Azure Monitor
90+
azure_metadata_endpoint="http://169.254.169.254/metadata/identity/oauth2/token", # Default endpoint for Managed Identity
91+
azure_client_id="YOUR_AZURE_CLIENT_ID", # Client ID from step 1
92+
azure_tenant_id="YOUR_AZURE_TENANT_ID",
93+
additional_labels={"job": "azure-prometheus"},
94+
)
95+
azure_client = get_custom_prometheus_connect(azure_config)
96+
97+
3. Give access to your Managed Identity on your Azure Monitor Workspace:
98+
99+
#. Open the Access Control (IAM) page for your Azure Monitor workspace in the Azure portal.
100+
#. Select Add role assignment.
101+
#. Select Monitoring Data Reader and select Next.
102+
#. For Assign access to, select Managed identity.
103+
#. Select + Select members.
104+
#. Select the Managed Identity you got from step 1
105+
#. Select Review + assign to save the configuration.
106+
107+
Option #3: Use Azure Workload Identity (Recommended)
108+
==============================================
109+
110+
1. Requirements
111+
112+
AKS cluster needs to have Workload Identity add-on and OIDC issuer enabled. You can use `--enable-oidc-issuer --enable-workload-identity` with `az aks create` or `az aks update` to enable them.
113+
114+
2. Create a new Managed Identity. Change the Identity name, resource group and location to match your environment.
115+
116+
.. code-block:: bash
117+
118+
export SUBSCRIPTION="$(az account show --query id --output tsv)"
119+
az identity create --name <identity-name> --resource-group <resource-group> --location "eastus" --subscription "${SUBSCRIPTION}"
120+
az identity show --name <identity-name> --resource-group <resource-group> -query clientId -o tsv # keep this value for the step #3
121+
122+
3. Set the following settings based from the previous step.
123+
124+
.. code-block:: python
125+
126+
# Create a custom Prometheus client for Azure Prometheus using Azure Managed Identity
127+
azure_config = AzurePrometheusConfig(
128+
url="https://azure-prometheus.example.com", # Replace with your Azure Monitor workspace query endpoint
129+
disable_ssl=False,
130+
azure_use_workload_id=True,
131+
azure_resource="https://prometheus.monitor.azure.com", # Default resource for Azure Monitor
132+
azure_token_endpoint="https://azure-token.example.com",
133+
azure_client_id="YOUR_AZURE_CLIENT_ID", # Client ID from step 1
134+
azure_tenant_id="YOUR_AZURE_TENANT_ID",
135+
additional_labels={"job": "azure-prometheus"},
136+
)
137+
azure_client = get_custom_prometheus_connect(azure_config)
138+
139+
4. Federate the Service Account with the Managed Identity. Replace the values with the ones from the step #1.
140+
141+
.. code-block:: bash
142+
143+
export AKS_OIDC_ISSUER="$(az aks show -g <resource-group> -n <cluster-name> --query "oidcIssuerProfile.issuerUrl" -otsv)" # Replace with the corresponding values of your AKS clusters.
144+
MY_NAMESPACE="mynamespace" # Replace with the namespace where your application is deployed
145+
MY_SERVICE_ACCOUNT="my-service-account" # Replace with the service account name used by your application
146+
az identity federated-credential create --name <federated-identity-name> --identity-name "robusta-id" --resource-group <resource-group> --issuer ${AKS_OIDC_ISSUER} --subject system:serviceaccount:$MY_NAMESPACE:$MY_SERVICE_ACCOUNT
147+
148+
5. Give access to your Managed Identity on your workspace:
149+
150+
#. Open the Access Control (IAM) page for your Azure Monitor workspace in the Azure portal.
151+
#. Select Add role assignment.
152+
#. Select Monitoring Data Reader and select Next.
153+
#. For Assign access to, select Managed identity.
154+
#. Select + Select members.
155+
#. Select the Managed Identity you got from step 2
156+
#. Select Review + assign to save the configuration.

prometrix/auth.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ def azure_authorization(cls, config: PrometheusConfig) -> bool:
1616
if not isinstance(config, AzurePrometheusConfig):
1717
return False
1818
return (config.azure_client_id != "" and config.azure_tenant_id != "") and (
19-
config.azure_client_secret != "" or config.azure_use_managed_id != ""
19+
config.azure_client_secret != "" or # Service Principal Auth
20+
config.azure_use_managed_id != False or # Managed Identity Auth
21+
config.azure_use_workload_id != False # Workload Identity Auth
2022
)
2123

2224
@classmethod
@@ -48,15 +50,33 @@ def _get_azure_metadata_endpoint(cls, config: PrometheusConfig):
4850
@no_type_check
4951
@classmethod
5052
def _post_azure_token_endpoint(cls, config: PrometheusConfig):
51-
return requests.post(
52-
url=config.azure_token_endpoint,
53-
headers={"Content-Type": "application/x-www-form-urlencoded"},
54-
data={
53+
# Try Azure Workload Identity
54+
with open("/var/run/secrets/azure/tokens/azure-identity-token", "r") as token_file:
55+
token = token_file.read()
56+
data = {
57+
"grant_type": "client_credentials",
58+
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
59+
"client_assertion": token,
60+
"client_id": config.azure_client_id,
61+
"scope": f"{config.azure_resource}/.default",
62+
}
63+
# Fallback to Azure Service Principal
64+
if not token:
65+
if config.azure_use_workload_id:
66+
return {
67+
"ok": False,
68+
"reason": f"Could not open token file from {token_file}",
69+
}
70+
data = {
5571
"grant_type": "client_credentials",
5672
"client_id": config.azure_client_id,
5773
"client_secret": config.azure_client_secret,
5874
"resource": config.azure_resource,
59-
},
75+
}
76+
return requests.post(
77+
url=config.azure_token_endpoint,
78+
headers={"Content-Type": "application/x-www-form-urlencoded"},
79+
data=data,
6080
)
6181

6282
@classmethod
@@ -67,7 +87,7 @@ def request_new_token(cls, config: PrometheusConfig) -> bool:
6787
try:
6888
if config.azure_use_managed_id:
6989
res = cls._get_azure_metadata_endpoint(config)
70-
else:
90+
else: # Service Principal and Workload Identity
7191
res = cls._post_azure_token_endpoint(config)
7292
except Exception:
7393
logging.exception(

prometrix/models/prometheus_config.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from enum import Enum
2+
import os
23
from typing import Dict, List, Optional
34

45
try:
@@ -69,12 +70,13 @@ class VictoriaMetricsPrometheusConfig(PrometheusConfig):
6970
# Does not support labels according to the docs, See below for apis
7071
# https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/prometheus-api-promql#supported-apis
7172
class AzurePrometheusConfig(PrometheusConfig):
72-
azure_resource: str
73-
azure_metadata_endpoint: str
74-
azure_token_endpoint: str
75-
azure_use_managed_id: Optional[str] = None
73+
azure_resource: str = "https://prometheus.monitor.azure.com"
74+
azure_metadata_endpoint: str = "http://169.254.169.254/metadata/identity/oauth2/token"
75+
azure_token_endpoint: str = f"https://login.microsoftonline.com/{os.environ.get('AZURE_TENANT_ID')}/oauth2/token"
76+
azure_use_managed_id: Optional[bool] = False
77+
azure_use_workload_id: Optional[bool] = False
7678
azure_client_id: Optional[str] = None
77-
azure_tenant_id: Optional[str] = None
79+
azure_tenant_id: Optional[str] = os.environ.get('AZURE_TENANT_ID', '')
7880
azure_client_secret: Optional[str] = None
7981
supported_apis: List[PrometheusApis] = [
8082
PrometheusApis.QUERY,

0 commit comments

Comments
 (0)