服务器错误 502 - 使用 OAuth 2.0 身份验证在 GCloud 的 GKE 上进行 .net core web 应用程序部署时出现问题

服务器错误 502 - 使用 OAuth 2.0 身份验证在 GCloud 的 GKE 上进行 .net core web 应用程序部署时出现问题

我有一个使用 Google 的 OAuth2.0 身份验证的 MVC .net core 6 Web 应用程序,但我无法使用 Kubernetes 发布它。

项目背景:

在本地进行编译并正常运行,包括创建 docker 映像和运行容器,但要在本地运行 docker 容器并拥有具有有效证书的 https 端口(我需要它才能使 Google 的 OAuth 工作),我需要运行以下步骤。

使本地证书值得信赖的命令和程序序列(您只需要在 docker 容器中运行即可,无需直接运行项目):

  1. 创建本地证书 pfx:dotnet dev-certs https -ep $env:USERPROFILE\.aspnet\https\Apresentacao.Web.pfx -p pa55w0rd!

  2. 在应用程序的 .csproj 中创建一个 UserScretsId 配置行:{SomeGuidIdHere}

  3. 在本地user-secrets中输入证书密码:dotnet user-secrets set "Kestrel:Certificates:Development:Password" "pa55w0rd!"

  4. 使证书“受信任” dotnet dev-certs https --trust

  5. 运行docker容器,但传递一些必要的参数(在项目文件夹外的powershell或bash中运行):

docker run -p 8080:80 -p 8081:443 -e ASPNETCORE\_URLS="https://+;http://+" -e ASPNETCORE\_HTTPS\_PORT="8081" -e ASPNETCORE\_ENVIRONMENT=Development - v $env:APPDATA\microsoft\UserSecrets\\:/root/.microsoft/usersecrets -v $env:USERPROFILE\\.aspnet\https:/root/.aspnet/https/ admin

如果我不执行上述步骤,或者执行“Docker run”时没有传递使用 https 端口和证书所需的参数,则在运行容器时我会收到以下返回:

warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3] Failed to determine the https port for redirect.

我的问题是: 在本地,我找到了处理 docker 容器、https 端口和 localhost 的 ssl 证书的解决方案,但是我正在使用 Git Hub 操作在 Google Cloud 上发布相同的应用程序以运行我的部署管道,在云中,我将镜像 docker 保存在存储桶中并使用 kubernetes 创建服务。我们已经有其他应用程序在使用 Kubernetes 的 Google 云基础架构上运行,并且我们在使用 Ingress 公开 URL 和使用 Google 提供的证书时没有遇到任何问题。

我做了几次测试使用不同的配置进行发布,直到我怀疑可能是应用程序中的问题,我决定通过不带 Google 身份验证配置进行发布进行测试,令我惊讶的是,该应用程序在 Kubernetes 中处于健康状态,并可以通过 https 正确在 URL 上提供。当我在项目的 Startup.cs 中再次包含 Google 身份验证时,我的问题再次出现在 Kuberntes 容器中,当访问 URL 时,我得到的返回是 502。

以下是我使用 Google 配置身份验证的方法: 在 Startup.cs 上

ConfigureServices 方法:

public void ConfigureServices(IServiceCollection services)
        {
            //Auth config google
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddGoogle(options =>
            {
                options.ClientId = "{my_ClientId}";
                options.ClientSecret = "{my_ClientSecret}";
            });
            ...
}

配置方法:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/PaginaNaoEncontrada");
                app.UseHsts();
            }
            app.Use(async (context, next) =>
            {
                await next();
                if (context.Response.StatusCode == 404)
                {
                    context.Request.Path = "/Home/PaginaNaoEncontrada";
                    await next();
                }
            });
            app.UseHttpsRedirection();

            app.UseStaticFiles(new StaticFileOptions
            {
                OnPrepareResponse = o => { o.Context.Response.Headers.Append("Cache-Control", $"public, max-age=10800"); }
            });
            app.UseUnobtrusiveAjax();
            app.UseRouting();
            app.UseAuthorization();
            app.UseAuthentication();            //Important  
}

在我的 HomeController.cs 中(我第一次访问应用程序时的第一个请求命中,以及我验证用户是否已经过身份验证的地方),控制器上方的 [Authorize] 注释对于我在 Startup to work .cs 中添加的内容是绝对必要的:

[Authorize]
public class HomeController : Controller
{ ...}

我的家庭行动指数:

[HttpGet]
return View();

通过索引调用 LoginGoogle:

public ActionResult LoginGoogle(){
    return Challenge(new AuthenticationProperties { RedirectUri = "/" }, "Google");}

要发布到 Kubernetes,我有以下文件(我突出显示其中三个,因为我认为其中包含了网站最重要的设置):

我的部署如下:

apiVersion: apps/v1

我的 Ingress 如下所示:

apiVersion: networking.k8s.io/v1

我的服务如下所示:

apiVersion: v1

在我最近对 ​​Kubernetes 的 .yaml 文件所做的更改后,我开始从该服务接收更多日志,类似于如果我运行不带参数的“Docker run”命令以使用本地证书时在本地收到的日志:最新容器日志: https://drive.google.com/file/d/1VcmiBe0LBuMr5B0VC5YivrvZdygZtEf5/view?usp=drive_link

在进行这些更改之前(主要是在部署文件中),我在日志中收到以下返回:以前的日志:https://drive.google.com/file/d/16NoN1fhhmoGk2bZRWTY0oxqFBY3xH4Kj/view?usp=drive_link

上面所示的日志下方只是有关 ResponseCoockies 的信息的无限循环,并且有关 https 端口的信息直到进行新的部署时才会重复。

当我们发布配置了 Google 身份验证的内容时,访问 URL 时服务如何响应: https://drive.google.com/file/d/1jDCmZNFPvzRvnq2VeOr7yC79A9Cba1rf/view?usp=drive_link

我的问题是我正在配置 Kubernetes 还是缺少某些东西导致证书无法信任?为什么当我从应用程序中删除 Google 身份验证配置时,部署仍能正常进行?(我删除了启动配置和控制器注释)

需要注意的是,我的 OAuth 客户端 ID 凭证是正确的,因为我能够通过添加 https localhost URL 作为授权来进行测试,所以这也不是问题。我将我在 Kubernetes 中配置的 URL 添加到授权使用客户端 ID OAuth 的 URL 列表中,如下所示: https://drive.google.com/file/d/1Hzi74jJ6sZ7za5D3rFZcyDQRaIoW4jOS/view?usp=drive_link

其他信息。

当我发布没有 Google 身份验证配置的应用程序时,该应用程序保持运行,并且证书似乎已链接到 URL 且安全:

https://drive.google.com/file/d/1RLocACa-TaCsmZo1S74sQoKrzvFgcfyx/view?usp=drive_link

当使用 Ingress.yaml 部署时,它会在基础架构中创建负载平衡,并自动配置链接到静态 IP 的前端端点:

https://drive.google.com/file/d/1f1LyIzcDqUbEUEpPTh6VQqdwyshMeUVA/view?usp=drive_link

我们使用 AWS 服务购买和托管域名,这样当访问我配置的 URL 时,我的 DNS 将被解析为我的前端的 IP,我配置了一个“记录名称”以重定向到 IP。这已经为其他应用程序完成了,并且有效,甚至当我们在未经身份验证的情况下发布此应用程序时它也能正常工作...

以下是我在AWS托管区域进行的注册: https://drive.google.com/file/d/1y8BIeK7RYywP95jPzpCGYkgZ7Lv-w7KG/view?usp=drive_link

还有由 Google 提供的证书的详细信息,由于我对 IP 进行了映射,因此只有在与 AWS 建立通信后,该证书才会变为“活动”状态,如上所述。 https://drive.google.com/file/d/1Y9wLH_DDX-93iMY5eNwBN0VcDFbId5I1/view?usp=drive_link

预先感谢您的帮助

答案1

我们找到了上述问题的解决方案。基本上,Kubernetes 中的容器除了需要健康检查端点之外,还需要应用程序的基本 URL 处于启动状态,也就是说,我无法尝试将 [Authorize] 注释直接添加到我的 HomeController,因为它是应用程序首先显示的。我定义应用程序的“默认”端点如下:

app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}");
            });

但是,HomeController 完全被 [Authorize] 覆盖,并且该应用程序在 Kubernetes 后端被视为不健康。因此,解决关键问题的方法是创建一个登录屏幕(不应用 [Authorize])来调用 Google 的登录并更改其默认端点:

app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Login}/{action=Index}/");
            });

因此后端变得健康并且应用程序启动了,首先调用登录屏幕,然后单击“使用 Google 登录”,我们称之为 Google 的 OAuth 2.0,这里又出现了另一个问题...... 该应用程序使用 HTTP 重定向到 OAuth,但我们需要纠正这个问题,以便它重定向到 HTTPS。我们尝试了所有建议的解决方案,但在我们的案例中有效的是:

public void ConfigureServices(IServiceCollection services)
        {
 services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                // Only loopback proxies are allowed by default. Clear that restriction because forwarders are
                // being enabled by explicit configuration.
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });
....
}

我们使用的 Microsoft 文档是:https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-6.0 然而,这个文档对我们来说变得很困惑,我们尝试了所有的建议,但在我们的案例中没有任何效果……直到 KnownNetworks 和 KnownProxies 的清除设置使我们的应用程序最终使用我们的重定向进行 HTPPS。

相关内容