Skip to content

Commit 0c57056

Browse files
committed
PoC: Managed Identity for App Service and Azure Automation
1 parent 62bf49f commit 0c57056

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

msal/imds.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# This code is licensed under the MIT License.
55
import json
66
import logging
7+
import os
8+
import time
79
try: # Python 2
810
from urlparse import urlparse
911
except: # Python 3
@@ -17,8 +19,18 @@ def _scope_to_resource(scope): # This is an experimental reasonable-effort appr
1719
return "{}://{}".format(u.scheme, u.netloc)
1820
return scope # There is no much else we can do here
1921

22+
2023
def _obtain_token(http_client, resource, client_id=None):
24+
if "IDENTITY_ENDPOINT" in os.environ and "IDENTITY_HEADER" in os.environ:
25+
return _obtain_token_on_app_service(
26+
http_client, os.environ["IDENTITY_ENDPOINT"], os.environ["IDENTITY_HEADER"],
27+
resource, client_id=client_id)
28+
return _obtain_token_on_azure_vm(http_client, resource, client_id=client_id)
29+
30+
31+
def _obtain_token_on_azure_vm(http_client, resource, client_id=None):
2132
# Based on https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
33+
logger.debug("Obtaining token via managed identity on Azure VM")
2234
params = {
2335
"api-version": "2018-02-01",
2436
"resource": resource,
@@ -44,3 +56,42 @@ def _obtain_token(http_client, resource, client_id=None):
4456
logger.debug("IMDS emits unexpected payload: %s", resp.text)
4557
raise
4658

59+
def _obtain_token_on_app_service(http_client, endpoint, identity_header, resource, client_id=None):
60+
# Prerequisite: Create your app service https://docs.microsoft.com/en-us/azure/app-service/quickstart-python
61+
# Assign it a managed identity https://docs.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Chttp
62+
# SSH into your container for testing https://docs.microsoft.com/en-us/azure/app-service/configure-linux-open-ssh-session
63+
logger.debug("Obtaining token via managed identity on Azure App Service")
64+
params = {
65+
"api-version": "2019-08-01",
66+
"resource": resource,
67+
}
68+
if client_id:
69+
params["client_id"] = client_id
70+
resp = http_client.get(
71+
endpoint,
72+
params=params,
73+
headers={
74+
"X-IDENTITY-HEADER": identity_header,
75+
"Metadata": "true", # Unnecessary yet harmless for App Service,
76+
# It will be needed by Azure Automation
77+
# https://docs.microsoft.com/en-us/azure/automation/enable-managed-identity-for-automation#get-access-token-for-system-assigned-managed-identity-using-http-get
78+
},
79+
)
80+
try:
81+
payload = json.loads(resp.text)
82+
if payload.get("access_token") and payload.get("expires_on"):
83+
return { # Normalizing the payload into OAuth2 format
84+
"access_token": payload["access_token"],
85+
"expires_in": int(payload["expires_on"]) - int(time.time()),
86+
"resource": payload.get("resource"),
87+
"token_type": payload.get("token_type", "Bearer"),
88+
}
89+
return {
90+
"error": "invalid_scope", # Empirically, wrong resource ends up with a vague statusCode=500
91+
"error_description": "{}, {}".format(
92+
payload.get("statusCode"), payload.get("message")),
93+
}
94+
except ValueError:
95+
logger.debug("IMDS emits unexpected payload: %s", resp.text)
96+
raise
97+

tests/msaltest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def main():
161161
{"client_id": AZURE_CLI, "name": "Azure CLI (Correctly configured for MSA-PT)"},
162162
{"client_id": VISUAL_STUDIO, "name": "Visual Studio (Correctly configured for MSA-PT)"},
163163
{"client_id": "95de633a-083e-42f5-b444-a4295d8e9314", "name": "Whiteboard Services (Non MSA-PT app. Accepts AAD & MSA accounts.)"},
164-
{"client_id": None, "client_secret": None, "name": "System-assigned Managed Identity (Only works when running inside a supported environment, such as Azure VM)"},
164+
{"client_id": None, "client_secret": None, "name": "System-assigned Managed Identity (Only works when running inside a supported environment, such as Azure VM, Azure App Service, Azure Automation)"},
165165
],
166166
option_renderer=lambda a: a["name"],
167167
header="Impersonate this app (or you can type in the client_id of your own app)",

0 commit comments

Comments
 (0)