Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Securing AI Apps on Azure: Add User Login to AI...

Securing AI Apps on Azure: Add User Login to AI Apps using Built-in Auth

Building an AI app on Azure and want to know the easiest way to let users sign-in? We'll show you how to setup built-in authentication on Azure App Service and Azure Container Apps. With built-in auth, employees can sign-in to either a workforce tenant or, thanks to Entra External ID, consumers can sign-in with a one-time passcode, username/password, or Google/Facebook login. Then your Azure app can display user details like their name, with minimal code changes. We'll demonstrate how to setup built-in auth to your apps using either the Graph SDK and the newly released Graph Bicep provider, and provide links to samples with full code provided.

Pamela Fox

July 08, 2024
Tweet

More Decks by Pamela Fox

Other Decks in Technology

Transcript

  1. Securing AI Apps on Azure Date Topic Speakers July 2

    5-6PM UTC Using Keyless Auth with Azure AI Services Marlene Mhangami Pamela Fox July 8 5-6PM UTC Add User Login to AI Apps using Built-in Auth James Casey Pamela Fox July 9 7-8PM UTC Add User Login to AI Apps using MSAL SDK Ray Luo Pamela Fox July 10 7-8PM UTC Handling User Auth for a SPA App on Azure Matt Gotteiner July 17 7-8PM UTC Data Access Control for AI RAG Apps on Azure Matt Gotteiner Pamela Fox July 25 11PM-12PM Deploying an AI App to a Private Network on Azure Matt Gotteiner Anthony Shaw https://aka.ms/S-1355
  2. Securing AI Apps on Azure: Add User Login to AI

    Apps using MSAL SDK Pamela Fox Python Cloud Advocacy github.com/pamelafox James Casey Product Manager, Identity Developer Experience github.com/jamesc TODO: new aka
  3. How do Authentication and Authorization Work? Authenticate users through the

    Open ID Connect protocol (OIDC) Authorize users using OAuth 2.0 protocol Terminology: Auth Flow ▪ Authentication / Authorization Exchange Authorization Server ▪ Issues tokens for apps to access protected resources Client ▪ App requesting access to a protected resource Resource Owner ▪ Owns protected resource client is trying to access Resource Server ▪ Provides access to protected data ▪ Relies on authorization server for authentication, uses token for authorization
  4. Securing a web API A secure API requires an “access

    token” that the client must fetch from the authorization server (via OAuth2/OpenID Connect) before calling the API. Client App Microsoft Entra ID​ Client app requests access token Access token returned to client app Resource Server (API endpoint) Call API HTTP Get + access token Data returned to client 1 2 3 4
  5. Before returning data, the resource API must perform authentication and

    authorization checks. Client App Microsoft Entra ID​ Client app requests access token Access token returned to client app Call API HTTP Get + access token Data returned to client 1 2 3 4 Resource Server (API endpoint) Authorization Securing a web API continued
  6. What is an access token? • Commonly a JSON blob

    that contains claims about the subject • Resource API needs to validate these claims, make authorization decisions based on these claims and potentially other information • It is passed to the API inside request headers "Accept": "application/json, text/plain, */*​ " "Accept-Encoding": "gzip,deflate,sdch​ " "Accept-Language": "en-GB, en;g=0,8,en- US;0=6,de;g=0,4​ " "Authorization": "bearer EyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1hiIsImtpZ CI6InU0T2ZORlBId0VCb3NIanRy...​ " "Cache-Control": "no-cache​ " "Connection": "keep-alive​ " "Host": "localhost:8080"​ "..." Request Headers
  7. Access Token Claims "aud": "416684a7-0b52-4fa3-9918-e76d16542be2", "iss": "https://login.microsoftonline.com/c72a295d-d7a5-41ea-a351-b15dd9f67215/v2.0", "iat": 1563883336, "nbf":

    1563883336, "exp": 1563887236, "azp": "bb764c21-49b8-49de-aa24-6c76d7dc800f", "oid": "0e748cd0-5d2a-4918-a351-9549e75fd1dd", "scp": "Catalog.View.Published", "roles": "Catalog.View", "wids": "9c6df0f2-1e7c-4dc3-b195-66dfbd24aa8f", "sub": "0X7PvET4orHRnRYndMvA4CYlYxg_CowsE1BGTIAK6hE", "tid": "c72a295d-d7a5-41ea-a351-b15dd9f67215", "preferred_username": [email protected], "email": [email protected]", "name": "Jane Bowen", Key: Authentication: know the subject Authorization: should subject have access Display-only https://learn.microsoft.com/entra/identity-platform/access-token-claims-reference
  8. Built-in Authentication abstracts away the details https://learn.microsoft.com/azure/app-service/overview-authentication-authorization#how-it-works Azure App Service

    and Container Apps provide built-in authentication and authorization capabilities (sometimes referred to as "Easy Auth"), so you can sign in users and access data by writing minimal or no code in your web app
  9. Registering with the Microsoft identity platform To request tokens from

    the Microsoft identity platform, you need to register a Microsoft Entra application and create a service principal for it. Microsoft Entra Application Object Microsoft Graph Service Principal Microsoft identity platform
  10. Registering Entra applications with Graph SDK graph_client = GraphServiceClient(credentials=credential, scopes=scopes)

    graph_client.applications.post(Application( display_name=f"ChatGPT Sample Client App {identifier}", sign_in_audience="AzureADMyOrg", web=WebApplication( redirect_uris=["http://YOUR-APP-URL/.auth/login/aad/callback"], implicit_grant_settings=ImplicitGrantSettings(enable_id_token_issuance=True)), required_resource_access=[ RequiredResourceAccess( resource_app_id="00000003-0000-0000-c000-000000000000", resource_access=[ ResourceAccess(id="e1fe6dd8-ba31-4d61-89e7-88639da4683d", type="Scope"), # Graph User.Read ResourceAccess(id="7427e0e9-2fba-42fe-b0c0-848c9e6a8182", type="Scope"), # offline_access ResourceAccess(id="37f7f235-527c-4136-accd-4a02d197296e", type="Scope"), # openid ResourceAccess(id="14dad69e-099b-42c9-810b-d002981feec1", type="Scope"), # profile ])])) Graph SDKs available in C#, Go, Java, JavaScript, PHP, Powershell, Python auth_init.py aka.ms/azai/auth-builtin
  11. Setting Entra application credentials with Graph SDK request_password = AddPasswordPostRequestBody(

    password_credential=PasswordCredential(display_name="WebAppSecret"), ) graph_client.applications.by_application_id(app_id) .add_password.post(request_password) Currently, app registrations can use either password or certificate credentials. (Stay tuned for a better way!) auth_init.py aka.ms/azai/auth-builtin
  12. OAuth2 authentication flow with OIDC App backend Microsoft Entra servers

    Browser OAuth2 Leg 1 Initiate the authorization code flow Returns authorization URI User Signs in Returns redirect to redirectURI OAuth2 Leg 2 Exchange authorization code for token Returns redirect to URI Visits webapp Returns access token Render webpage &scope=openid email name and ID token
  13. Implementing the authentication flow Option 1: For auth on Azure

    App Service or Container Apps Option 2: For auth on any host (including local) Use MSAL packages to orchestrate OIDC flow using app registration Configure built-in authentication and authorization with Microsoft identity platform as the provider Join tomorrow for a deep dive session! Today's topic!
  14. Configuring built-in authentication for Container Apps • Set clientID to

    the app ID of the Entra app registration • Store app password in secrets and point clientSecretSettingName to that secret • Set openIdIssuer to the Microsoft idP endpoint var loginEndpoint = environment().authentication.loginEndpoint var openIdIssuer = '${loginEndpoint}${tenant().tenantId}/v2.0' resource auth 'Microsoft.App/containerApps/authConfigs@2023-05-01' = { parent: app name: 'current' properties: { platform: { enabled: true } globalValidation: { redirectToProvider: 'azureactivedirectory' unauthenticatedClientAction: 'RedirectToLoginPage' } identityProviders: { azureActiveDirectory: { registration: { clientId: clientId clientSecretSettingName: clientSecretName openIdIssuer: openIdIssuer } } } } } appauth.bicep aka.ms/azai/auth-builtin
  15. Extracting user details from headers def extract_username(headers, default_username="You"): if "X-MS-CLIENT-PRINCIPAL"

    not in headers: return default_username token = json.loads(base64.b64decode(headers.get("X-MS-CLIENT-PRINCIPAL"))) claims = {claim["typ"]: claim["val"] for claim in token["claims"]} return claims.get("name", default_username) @app.get("/") async def index(): username = extract_username(request.headers) return await render_template("index.html", username=username) https://learn.microsoft.com/azure/app-service/configure-authentication-user-identities The built-in authentication service injects headers into request headers with details about the authenticated user, like their username. app.py aka.ms/azai/auth-builtin
  16. Tenant Architecture – External ID Subscription AppCreator Service Principal App

    Registration User Flow (Sign-in/Sign-up) App Users Entra Tenant (external) Entra Tenant (workforce) App Roles
  17. Tenant Architecture – External ID Subscription > azd auth login

    --tenant-id EXTERNAL-TENANT Get Token (user) Entra Tenant (external) Entra Tenant (workforce)
  18. Tenant Architecture – External ID Subscription > ./scripts/setup_for_external_id.sh Creates AppCreator

    Service Principal Entra Tenant (external) Entra Tenant (workforce) App Roles
  19. Tenant Architecture – External ID Subscription > azd auth login

    --tenant-id AZURE-TENANT-ID AppCreator Service Principal Get Token Entra Tenant (external) Entra Tenant (workforce) App Roles
  20. Tenant Architecture – External ID Subscription > azd up (pre-hook

    – auth_init.py) Creates AppCreator Service Principal App Registration User Flow (Sign-in/Sign-up) Entra Tenant (external) Entra Tenant (workforce) App Roles
  21. Tenant Architecture – External ID Subscription > azd up (infra)

    Configures AppCreator Service Principal App Registration User Flow (Sign-in/Sign-up) Creates Entra Tenant (external) Entra Tenant (workforce) App Roles
  22. Tenant Architecture – External ID Subscription Entra Tenant (workforce) Entra

    Tenant (external) > azd up (post-hook – auth_update.py) AppCreator Service Principal App Registration User Flow (Sign-in/Sign-up) Configure App Roles
  23. Tenant Architecture – External ID Subscription Entra Tenant (workforce) Entra

    Tenant (external) AppCreator Service Principal App Registration User Flow (Sign-in/Sign-up) App Users New Users are now in the external configuration tenant App Roles
  24. Using different credentials in different tenants def get_credential(tenant_id: str) ->

    AsyncTokenCredential: client_id = os.getenv("AZURE_AUTH_EXTID_APP_ID", None) if client_id is None: logger.info(f"Using Azd CLI Credential for tenant_id {tenant_id}") return AzureDeveloperCliCredential(tenant_id=tenant_id) client_secret = os.getenv("AZURE_AUTH_EXTID_APP_SECRET", None) logger.info(f"Using Client Secret Credential for client ID {client_id}") return ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret) We use azd environment variables to use different credentials • AzureDeveloperCliCredential – for workforce tenant (Azure) • ClientSecretCredential – for external configuration tenant auth_init.py aka.ms/azai/auth-builtin
  25. Granting permissions to the App Registration async def get_or_create_permission_grant(graph_client: GraphServiceClient,

    sp_id: str, graph_sp_id: str): permission_scopes = " ".join(["User.Read", "offline_access", "openid", "profile"]) grant_id = await get_permission_grant(graph_client, sp_id, graph_sp_id, permission_scopes) if grant_id: logger.info("Permission grant already exists, not creating new one") else: logger.info("Creating permission grant") await create_permission_grant(graph_client, sp_id, graph_sp_id, permission_scopes) Pre-grant permissions for Entra External ID app registration to request claims auth_init.py aka.ms/azai/auth-builtin https://learn.microsoft.com/entra/identity/enterprise-apps/what-is-access-management
  26. async def get_or_create_userflow_app(graph_client_beta: GraphServiceClientBeta, userflow_id: str, app_id: str) -> bool:

    logger.info(f"Possibly setting up association between userflow {userflow_id} and client app {app_id}...") flow_app_exists = await userflow_has_app(graph_client_beta, userflow_id, app_id) if flow_app_exists: logger.info("User flow is already associated with client app.") else: logger.info("Adding user flow to client app.") await add_app_to_userflow(graph_client_beta, userflow_id, app_id) Configure sign-in and sign-up with a User Flow https://learn.microsoft.com/entra/external-id/customers/how-to-user-flow-sign-up-sign-in-customers Create user flow, and attach it to the application auth_init.py aka.ms/azai/auth-builtin
  27. External ID Pricing Consumption based pricing per Monthly Active User

    (MAU) • Free Tier • Base price per user with add-ons have additional per-MAU pricing https://learn.microsoft.com/entra/external-id/customers/faq-customers for all pricing details
  28. Microsoft Entra External ID - Visual Studio Code extension Create

    a tenant with a guided walkthough Browse your resources in explorer view Public preview https://aka.ms/ciam-hub-vscode-quickstart
  29. Azure Portal - External configuration tenant in App Service Auth

    Create or use existing tenant and application Customize sign-in branding Public preview https://aka.ms/ciam-hub-appservice-docs
  30. Registering Entra applications with Graph Bicep template resource clientApp 'Microsoft.Graph/[email protected]'

    = { uniqueName: clientAppName displayName: clientAppDisplayName signInAudience: 'AzureADMyOrg' web: { redirectUris: ['${webAppEndpoint}/.auth/login/aad/callback'] implicitGrantSettings: {enableIdTokenIssuance: true}} requiredResourceAccess: [{ resourceAppId: '00000003-0000-0000-c000-000000000000' resourceAccess: [ // User.Read {id: 'e1fe6dd8-ba31-4d61-89e7-88639da4683d', type: 'Scope'} // offline_access {id: '7427e0e9-2fba-42fe-b0c0-848c9e6a8182', type: 'Scope'} // openid {id: '37f7f235-527c-4136-accd-4a02d197296e', type: 'Scope'} // profile {id: '14dad69e-099b-42c9-810b-d002981feec1', type: 'Scope'} ]} ]} resource clientSp 'Microsoft.Graph/servicePrincipals@beta' = { appId: clientApp.appId } Create a Graph application and associated service principal in Bicep (vs. SDK) Public preview appreg.bicep https://aka.ms/graphbicep aka.ms/graph-bicep-mi-fic
  31. Using managed identity as federated identity credential var openIdIssuer =

    '${loginEndpoint}${tenant().tenantId}/v2.0' resource webIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { name: '${name}-id' location: location } resource clientAppFic 'federatedIdentityCredentials@beta' = { name: '${clientApp.uniqueName}/msiAsFic' audiences: ['api://AzureADTokenExchange'] issuer: openIdIssuer subject: webIdentity.properties.principalId } App registrations can go password-less! More secure than secrets/certificates since no strings need to be stored securely or rotated. This will be eventually supported by Graph Bicep, MSAL SDKs, and Built-in Auth. appreg.bicep aka.ms/graph-bicep-mi-fic
  32. Configuring built-in authentication for App Service Just change clientSecretSettingName to

    this exact value instead → var loginEndpoint = environment().authentication.loginEndpoint var openIdIssuer = '${loginEndpoint}${tenant().tenantId}/v2.0' resource configAuth 'Microsoft.Web/sites/config@2022-03-01' = { parent: appService name: 'authsettingsV2' properties: { globalValidation: { requireAuthentication: true unauthenticatedClientAction: 'RedirectToLoginPage' redirectToProvider: 'azureactivedirectory' } identityProviders: { azureActiveDirectory: { enabled: true registration: { clientId: clientId clientSecretSettingName: 'OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID' openIdIssuer: openIdIssuer }}} login: { tokenStore: { enabled: true } }}} appauth.bicep aka.ms/graph-bicep-mi-fic
  33. Get started with our samples Azure OpenAI + AI Search

    + Entra + MSAL + App Service Built-in Auth aka.ms/ragchat Azure OpenAI + Entra + Container Apps Built-in Auth aka.ms/azai/auth-builtin Find more samples at: aka.ms/azai Java JavaScript Python .NET OpenAI Assistants Fine-tuning ...and more!
  34. Learn more Microsoft Entra https://entra.microsoft.com Microsoft Entra developer center https://aka.ms/dev/ms-entra

    Microsoft Graph Bicep https://aka.ms/graphbicep Built-in Authentication on Azure Container Apps https://learn.microsoft.com/azure/container-apps/authentication Built-in Authentication on Azure App Service https://learn.microsoft.com/azure/app-service/overview-authentication-authorization
  35. Securing AI Apps on Azure Date Topic Speakers July 2

    5-6PM UTC Using Keyless Auth with Azure AI Services Marlene Mhangami Pamela Fox July 8 5-6PM UTC Add User Login to AI Apps using Built-in Auth James Casey Pamela Fox July 9 7-8PM UTC Add User Login to AI Apps using MSAL SDK Ray Luo Pamela Fox July 10 7-8PM UTC Handling User Auth for a SPA App on Azure Matt Gotteiner July 17 7-8PM UTC Data Access Control for AI RAG Apps on Azure Matt Gotteiner Pamela Fox July 25 11PM-12PM Deploying an AI App to a Private Network on Azure Matt Gotteiner Anthony Shaw https://aka.ms/S-1355