How to use AAD/AADB2C with Kubernetes?

Siegfried Heintze 1,861 Reputation points
2020-06-22T23:25:18.14+00:00

(1) Can someone please point me to a (Microsoft supported) example that demonstrates using AAD B2C with Kubernetes with the OAuthAuthCodeFlow/OpenIDConnect on ASP.NET Core?

I had a assumed I would implemented AAD B2C on an ASP.NET webapp in a container in a Kubernetes POD and expose that POD(s) thru the the load balancer.

(2) Is this a viable approach?

(3) I'm now reading about deploying Ingress and registering Ingress in an AAD (instead of an AADB2C) tenant. Is this the preferred approach? Why?

(4) Then what? I believe I create an OAUTH2_PROXY as a service to be used by ingress. Is this correct? Is using OAUTH2_PROXY the recommend approach? Are there alternatives I might consider?

(5) Please help me understand how OAUTH2_PROXY works. Does it implement Implicit grant flow, OAuth Authorization Code Flow or the OpenIDConnect flow (assuming I am using AAD or AADB2C). I'm looking at auth-configuration and it is not clear to me if I can use OpenIDConnect with AAD (auth-configuration).

(6) After looking at links above, It looks like I can use OAUTH2_PROXY with AAD (and not AADB2C) and I can still accommodate multiple Auth Providers like Facebook and Github. This seems strange .... Is it correct? In other words, what is the recommended approach when accommodating multiple auth providers with OAUTH2_PROXY: use AAD or AADB2C? That SUSI flow in AADB2C is pretty nice. Will it work with OAUTH2_PROXY?

(7) So if we install OAUTH2_PROXY as a service for Ingress, how does my front end WebApp get all that nice information about the user like the custom user attributes that I defined in AADB2C and the OID that I need for RLS (row level security)?

Fri Jun 26 2020 Update

Since you are using asp.net core app to integrate with AAD B2C, you can refer microsoft-identity-web. In the readme section, you will find link to official samples which covers most of the common scenario. Though I am not sure about the specific scenario you have, but here is a generic asp.net core sample for B2C.

Please explain why you believe this approach of implementing Authentication (and Authorization) with a normal web app is a viable approach with Kubernetes (and specifically Kubernetes load balancers). (I assume you are familiar with the Kubernetes replica set feature that will create new instances of a web app on demand to deal with increasing web traffic and the kubernetes load balancer that distribute the traffic accordingly). Suppose I point my browser at a WebApp behind a load balancer and successfully become authenticated and I now have a cookie or (more likely) a JWT that contains my OID from AAD and then I click on a link local to that URL and I the load balancer shuffles me off to different instance of that WebApp with which I do not have a session? How will this other instance of the WebApp know my OID and that I have already authenticated?

Please(!) correct me if I am wrong but I don't think this approach is viable because there is no way for the other instance of the authenticating webapp to know that I am already authenticated.

This is why we use the OAUTH2_PROXY which is a plug-in to the Ingress/NGINX load balancer.

I assume you would expose a public endpoint for the Kubernetes service using ingress controllers? There is also Application Gateway Ingress Controller which is native in Azure. I don't think you would need OAUTH2_PROXY, however if you are specifically looking for leveraging OAUTH2_PROXY, please let us know and we will try to find answer which might take us some time.

Well I was assuming that Microsoft Azure had a preferred (and supported) solution to this problem of using AADB2C to authenticate public users to access Kubernetes clusters.
I also assumed it was not OAUTH2_PROXY because OAUTH2_PROXY does not use AADB2C (only AAD) so I cannot use my AADB2C signin-signup (and other) flows.

As per your link to ingress-controller-overview I assumed that AGIC was the official Microsoft Solution but when I visited tutorial-ingress-controller-add-on-new I could find no instructions or tutorial on using AADB2C with AGIC. Please point me to these tutorials and instructions.

Again: How do I implement OAuth Authentication Code Flow/OPENIDConnect using AAD (preferably with AADB2C) with a Kuberetes Cluster so that the Ingress load balancer passes along the OID to the back end so I can use it for row level authentication? Can this be done with AGIC? Can this be done with OAUTH2_Proxy? (Judging by the OAUTH2_PROXY documentation, it looks like I have to make a choice between AAD and OPENIDConnect but it is not clear and I could not find an example). Do I use something else? Where are the instructions, tutorials and examples?

I'm thinking that surely I'm not the only developer to want to do this. It must be extremely common.

Tue Jun 30 2020 Update

OK, that idea to cache sounds like it would work with an exposed K8 replica set. What options do I have? REDIS? MSQLSVR? Any others?

I'm trying it out now and having some difficulties enhancing 4-2-B2C. Here is my attempt to cache with MS SQL SVR/LocalDB:

The original startup.cs code looks like this:

services.AddWebAppCallsProtectedWebApi(Configuration, new string[] {  
            Configuration["TodoList:TodoListScope"] },  
            configSectionName: "AzureAdB2C")  
            .AddInMemoryTokenCaches()  
            ;  

This works (but of course, does not implement caching suitable for a K8 replica set).

This latest attempt is not crashing:

services.AddWebAppCallsProtectedWebApi(Configuration, new string[] {  
            Configuration["TodoList:TodoListScope"] },  
            configSectionName: "AzureAdB2C")  
            .AddDistributedSqlServerCache(options => { options.ConnectionString = Configuration["DistCache_ConnectionString"]; options.SchemaName = "dbo"; options.TableName = "Tokens"; })  
            .AddSessionTokenCaches()  
            .AddSessionAppTokenCache()  
            .AddInMemoryTokenCaches()  
            ;  

Some of these calls looked redundant and experimented with removing the redundancies but no success. I was surprised that it crashed in startup whenever I removed the call to AddInMemoryTokenCaches.

I have added this to the appsettings.json:

"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\MSSQLLocalDB;Database=DistCacheToDoList; MultipleActiveResultSets=true"
},

I have created a database in localdb called DistCacheToDoList.

I have executed the following commands:

pushd ${SRCROOT}/active-directory-aspnetcore-webapp-openidconnect-v2/4-WebApp-your-API/4-2-B2C/Client  
dotnet add package Microsoft.Extensions.Caching.SqlServer --version 3.0.0  
dotnet tool uninstall --global dotnet-sql-cache  
dotnet tool install --global dotnet-sql-cache --version 3.0.0  
dotnet sql-cache create "Server=(localdb)\MSSQLLocalDB;Database=DistCacheToDoList" "dbo" "Tokens"  

(I borrowed these from another tutorial on Session Caching).

So now I log out of my web site at https://localhost:5000 and log in again and use SSMS to dump my localdb table called tokens and nothing appears.

Should it not be creating entries in there when I log in?
Should I be able to see them with SSMS SQL queries?

Azure Kubernetes Service (AKS)
Azure Kubernetes Service (AKS)
An Azure service that provides serverless Kubernetes, an integrated continuous integration and continuous delivery experience, and enterprise-grade security and governance.
1,992 questions
Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
20,596 questions
{count} votes

Accepted answer
  1. Siegfried Heintze 1,861 Reputation points
    2021-02-09T19:50:12.707+00:00

    I think it is finally working with some help resulting from creating a ticket via portal.azure.com.

    (1) The ASP.NET team guided me to this helpful page: msal-net-token-cache-serialization. I wish I had discovered this much sooner...

    (2) I hope someone will update this page (again) because I could not get "new DefaultAzureCredential()" to work. I think it might work if one is using Azure App Config but there is no mention of Azure App Config on that page . Please update that page with Krishnendu's suggestion of using ClientSecretCredential (with an ordinary service principle in place of DefaultAzureCredential). (However, even after correctly using ClientSecretCredential I could not get the web app to work because I had a bad URL for my Bitnami Redis Kubernetes Stateful Set and assumed the problem was that ClientSecretCredential still not working or I was using the wrong kind of service principal (there are several to choose from including service identities. The problem was that the stack trace resulting from the bad REDIS URL was not appearing the the kubernetes pod logs)...

    Thanks for everyone's help.

    Siegfried

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Krish G 2,331 Reputation points
    2020-06-23T12:54:58.057+00:00

    Hello @SiegfriedHeintze-9929 ,

    Since you are using asp.net core app to integrate with AAD B2C, you can refer microsoft-identity-web. In the readme section, you will find link to official samples which covers most of the common scenario. Though I am not sure about the specific scenario you have, but here is a generic asp.net core sample for B2C.

    I assume you would expose a public endpoint for the Kubernetes service using ingress controllers? There is also Application Gateway Ingress Controller which is native in Azure. I don't think you would need OAUTH2_PROXY, however if you are specifically looking for leveraging OAUTH2_PROXY, please let us know and we will try to find answer which might take us some time.

    June 26, 2020 Update (adding response for follow up questions)

    Multiple instances for scalability and load balancing is not something new. It exists for quite long time since the age of classic web app when it used to be multiple physical servers or VMs instead of modern age containers. So, the fundamental challenge of maintaining the user session awareness was the same so that it does not get lost when http requests jumps across different instances due to load balancing. The way to solve that problem has been to have external session store. When you are into Kubernetes, the challenge and solution are still the same like before which is "externalizing" the session store/token cache using some distributed cache like Redis (or any external store). Only change with k8s is each instance is a now pod instead of VM which does not make much of a difference in terms of auth flow. There is nothing special you need to do. We already have reusable framework called Microsoft Identity Web, samples and wiki where you need to write very little code to wire up OAUTH 2.0+OIDC flow with either AAD or AAD B2C (I provided it also in my previous reply). Please go through the link. It has extensive documentation, steps, getting started, sample. Please keep in mind, you do not need to worry about whether you deploy your app to Kubernetes or somewhere else as long as you have distributed token cache (which is also provided out of the box in the Microsoft Identity Web framework itself).

    Regarding ingress, it is meant to open up entry point to your cluster and let flow the network traffic to your load balancer which further distributes it across pods. To be clear, it does not have to deal with your auth provider, be it B2C or AAD or anything else. AGIC acts similarly (the added benefit here is the same service also provides you an integrated load balancer too). Let's not confuse OAUTH 2.0+OIDC flow with the role of the ingress/load balancer since both are separate.

    I would reiterate that when we are talking about auth flow (OAuth 2.0+OIDC), we should think the web application deployed in Kubernetes similar to any other distributed multi-instance web application scenario (let's say Azure app service or Service fabric for example). Thinking it otherwise would be like trying to solve a problem which does not exist.

    As a reminder, Microsoft Identity Web project is built to enable developers integrating AAD + B2C with theirs apps with little effort. I do encourage you to go through that. Please feel free to come up with any follow up.