Search code examples
asp.net-coreidentityserver4openid-connectapi-gatewayazure-aks

Run aspnet core 3.1 MVC application in azure kubernetes service with oidc authentication behind azure application gateway and with Identity Server 4


I'm running a aspnet core 3.1 MVC application in kubernetes service from azure. The AKS is behind an application gateway. The Azure Application Gateway Ingress Controller pod is running in AKS and my configurations for deployment, service and ingress looks like follows:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  name: imagename
  namespace: namespacename
spec:
  replicas: 1
  selector:
    matchLabels:
      app: imagename
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: imagename
    spec:
      containers:
      - name: imagename
        image: acrname.azurecr.io/imagename:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          name: http
        readinessProbe:
          httpGet:
            path: /probes  
            port: 80
          periodSeconds: 30
          timeoutSeconds: 3
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "dev"
        resources:
          requests:
            cpu: 150m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 500Mi
status: {}
---
apiVersion: v1
kind: Service
metadata:
  name: imagename
  namespace: namespacename
spec:
  selector:
    app: imagename
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: imagename
  namespace: namespacename
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
    appgw.ingress.kubernetes.io/backend-path-prefix: "/"
    appgw.ingress.kubernetes.io/appgw-ssl-certificate: certificatename
    appgw.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  rules:
  - host: exampledomain.com.br
    http:
      paths:
      - path: /pathapp/*
        backend:
          serviceName: imagename
          servicePort: 80

The identity server pod is already running in AKS and the authentication proccess works fine for the Bearer scheme.

For the Cookies scheme the application is abble to authenticate with azure AD through identity server but on the redirect for /signin-oidc endpoint at the application pod I'm stuck on a 404 error. The logs of the pod for the application says:

An unhandled exception has occurred while executing the request. System.Exception: An error was encountered while handling the remote login. ---> System.Exception: Correlation failed. --- End of inner exception stack trace ---

The instructions present in Configure ASP.NET Core to work with proxy servers and load balancers are already implemented in application.

The complete of the pod for the redirection to /signin-oidc in application can be seen in the image below:

Correlation failed

Here is my startup class:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuracao = configuration;
        }

        public IConfiguration Configuracao { get; }

        public void ConfigureServices(IServiceCollection servicos)
        {
            servicos.AddApplicationInsightsTelemetry(Configuracao.GetValue<string>("ApplicationInsights:InstrumentationKey"));
            //servicos.AddAICustomizado(Configuracao);

            servicos.AddControllersWithViews();
            servicos.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                    ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost;
            });
            servicos.AddRazorPages().AddRazorRuntimeCompilation();
            //servicos.AddMvcCustomizado();

            servicos.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
                            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
                            .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
                            {
                                options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                                options.ResponseType = OpenIdConnectResponseType.Code;
                                options.Authority = Configuracao.GetValue<string>("Autenticacao:IdentityServer:UrlBase");
                                options.ClientId = "clientimplicit";
                                options.ResponseType = "id_token token";
                                options.SaveTokens = true;
                                options.Scope.Clear();
                                options.Scope.Add("openid");
                                options.Scope.Add("Scope2");
                                options.Scope.Add("Scope3");
                                options.UseTokenLifetime = true;
                                options.RequireHttpsMetadata = false;
                                options.Events.OnRedirectToIdentityProvider = async n =>
                                {
                                    n.ProtocolMessage.RedirectUri = $"{Configuracao.GetValue<string>("Autenticacao:RedirectUri:UrlBase")}signin-oidc";
                                    await Task.FromResult(0);
                                };
                                options.Events.OnRedirectToIdentityProviderForSignOut = async n =>
                                {
                                    n.ProtocolMessage.PostLogoutRedirectUri = $"{Configuracao.GetValue<string>("Autenticacao:RedirectUri:UrlBase")}signout-callback-oidc";
                                    await Task.FromResult(0);
                                };
                            });

            servicos.AddAuthorization();
            //servicos.AddAutenticacaoCustomizada(Configuracao);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.Use((context, next) =>
            {
                context.Request.Scheme = "https";
                return next();
            });

            app.UseForwardedHeaders();

            if (env.EnvironmentName.Equals("prd", System.StringComparison.CurrentCultureIgnoreCase))
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            //app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAutenticacaoCustomizada();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=cliente}/{action=index}/");
            });
            //app.UseMvcCustomizado(env);
        }
    }

Could someone lend me some help with Correlation failed error?


Solution

  • So, after some struggle to get it working I was able to find a solution.

    The entirely problem was related with de SSL Certificate Chain of the certificate binded with the my Azure Application Gateway.

    Someone exported it by the wrong way, without including the certificate path:

    enter image description here

    The image above is the checkbox that need to be checked when exporting the certificate on Windows Server.

    To check if the chain of the certificate is complete at your gateway run the command below in git bash when you are in windows and don't have openssl installed:

    openssl s_client -showcerts https://domainbindedwithgateway.com.br:443

    After rebinding the correct certificate with the chain complete the error disappears.

    For a good reference about SSL certificates and load balancers etc refer to:

    [Azure] Application Gateway certificate gotchas