带有IdentityServer4认证/ http错误的{@ 44}在Azure Web应用程序容器上部署.net Core 3 linux容器

如何解决带有IdentityServer4认证/ http错误的{@ 44}在Azure Web应用程序容器上部署.net Core 3 linux容器

我正在尝试使用.Net Core Clean Architecture App Template并使其在容器中运行并通过蔚蓝的CI / CD管道进行部署

我的模板的容器化版本在具有5001端口的linux容器中本地运行,并且一切正常。

我的azure管道构建过程正常运行,并且在我的容器注册表中创建了图像。

问题是,一旦我将其部署/发布到容器的Web应用程序,该应用程序将失败并抛出以下错误:

应用程序启动异常 System.InvalidOperationException:在以下位置的“ CurrentUser \ My”上找不到主题为“ CN = localhost”的有效证书 Microsoft.AspNetCore.ApiAuthorization.IdentityServer.SigningKeysLoader.LoadFromStoreCert(String 主题,字符串storeName,StoreLocation storeLocation,DateTimeOffset currentTime)

我所做的:

  1. these docs from MS之后,我创建了本地开发证书:

    dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p { password here }

    dotnet dev-certs https --trust

  2. 然后我将其作为私有.pfx证书导入到Web应用程序中。

  3. 我添加了一个应用设置 WEBSITE_LOAD_CERTIFICATES ,其证书的“ thumb”值为

  4. 我在Identity Server的appSettings.json部分中使用了导入证书的“主机名”。(在我的情况下为hostname = localhost)

加载Web应用程序时,它会显示:(应用程序错误,并且docker日志显示了我上面引用的错误。

我非常确定这与身份服务器设置和此处的appSettings.json值有关:

  "IdentityServer": {
    "Key": {
      "Type": "Store","StoreName": "My","StoreLocation": "CurrentUser","Name": "CN=localhost"
    }
  }

有人可以帮我弄清楚如何解决此错误吗?

编辑1-手动为IdentityServer密钥指定文件

这肯定与身份服务器有关。我试图像这样在appSettings.json中手动将证书设置为文件:

  "IdentityServer": {
    "Key": {
      "Type": "File","FilePath": "aspnetapp.pfx","Password": "Your_password123"
    }
  }

现在我收到此错误:

将证书文件加载到带有存储标志的“ /app/aspnetapp.pfx” ”。应用程序启动异常System.InvalidOperationException: 加载证书时出错。文件 找不到'/app/aspnetapp.pfx'。 Microsoft.AspNetCore.ApiAuthorization.IdentityServer.SigningKeysLoader.LoadFromFile

我将其添加到了dockerfile中:

WORKDIR /app
COPY ["/aspnetapp.pfx","/app"]
RUN find /app

从下图可以看到,文件显示在应用程序的构建目录中:

enter image description here

我还确保.gitignore或.dockerignore文件不会忽略aspnetapp.pfx。

我不知道为什么它不能加载该文件。看来它应该在应该存在的地方存在。

使用证书拇指和更新的路径进行编辑2

所以我使用了tnc1977建议,并将其作为我的身份密钥设置

  "IdentityServer": {
    "Key": {
      "Type": "File","FilePath": "/var/ssl/private/<thumb_value>.p12","Password": "Your_password123"
    }
  }

但是,这又产生了一个错误:

加载证书时出错。密码是 错误或进程没有权限将密钥存储在 键集“ EphemeralKeySet” Interop + Crypto + OpenSslCryptographicException:错误:23076071:PKCS12 例程:PKCS12_parse:mac验证失败

编辑3:有效的Azure应用证书

我购买了Azure应用证书,并添加了具有TSL设置的自定义域,并且出现了相同的错误

编辑4:在代码startup.cs中加载证书-新错误:

我现在知道我不能使用证书存储库CurrentUser / My,因为它用于Windows。 Linux容器必须手动在代码中加载证书。

我正在使用已添加到azure Web应用程序中的应用程序证书的指纹。这是私有的Azure应用证书,已针对自定义域进行了验证。

我将此代码添加到了statup.cs configureservices中(我知道对这些值进行硬编码不是最佳实践,但我只想看看它是否可以加载证书,我会尝试使用env变量和密钥库):

        // linux file path for private keys
        var cryptBytes = File.ReadAllBytes("/var/ssl/private/<thumbprint>.p12");
        var cert = new X509Certificate2(cryptBytes,"");

        services.AddIdentityServer().AddSigningCredential(cert);

我输入一个空密码,因为我认为这是您应该做的。我现在在docker日志中遇到以下错误,这使我相信证书已加载,并且现在使用 services.AddIdentityServer()。AddSigningCredential(cert); 都与我有关在startup.cs configureservices app.UseIdentityServer() 在startup.cs configure 中:

未处理的异常。 System.InvalidOperationException:装饰器已经注册为类型:IAuthenticationService。

我不确定如何将证书添加到应用程序。UseIdentityServer();线。

编辑5

经过更多的挖掘,不幸的是@ tnc1997答案无效。 在asp.net核心3中,我的 satrtup.cs 中的 app.UseIdentityServer 调用会在内部使用一种寻找身份服务器密钥的方法, appsetting(environment).json文件中的File,Pass等。

因此,即使我以tnc1997所示的代码加载了证书,该应用程序仍会在设置文件中查找。因此,设置文件必须包含IS4密钥的核心详细信息。

此外,azure不会将证书放置在linux容器中的典型受信任位置。根据我的阅读,看来唯一的方法是挂载卷(在这种情况下为Azure存储文件共享),并使用上载到该文件共享的证书。

我可以确认它在本地可以运行,但是现在我仍然在运行容器时遇到问题,前端加载,并且看来Web api项目无法启动。我将发布另一个问题来解决该问题。

解决方法

原始答案

我认为问题可能是您正在尝试使用Windows证书存储区在Linux容器中加载证书。

文档here很好地概述了如何在Linux托管的应用程序中使用应用程序服务私有证书:

  1. 在Azure门户的左侧菜单中,选择“应用程序服务”>“ ”。
  2. 从应用程序的左侧导航中,选择TLS / SSL设置,然后选择私钥证书(.pfx)或公钥证书(.cer)。
  3. 找到您要使用的证书并复制指纹。
  4. 要在您的应用程序代码中访问证书,请将其指纹添加到WEBSITE_LOAD_CERTIFICATES应用程序设置中。
  5. WEBSITE_LOAD_CERTIFICATES应用程序设置使指定的证书可作为文件供Linux托管应用程序(包括自定义容器应用程序)访问。这些文件位于以下目录中:
    • 私人证书-/var/ssl/private(.p12文件)
    • 公共证书-/var/ssl/certs(.der文件)
  6. 使用下面的代码示例将指定的证书加载到Linux托管的应用程序(包括自定义容器应用程序)中:
    using System;
    using System.IO;
    using System.Security.Cryptography.X509Certificates;
    
    var bytes = File.ReadAllBytes($"/var/ssl/private/{Configuration["WEBSITE_LOAD_CERTIFICATES"]}.p12");
    var cert = new X509Certificate2(bytes);
    

签名证书

以下是我用来生成签名凭证的步骤:

  1. 安装OpenSSL
  2. 生成私钥和公共证书。
    1. 运行openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout example.com.key -out example.com.crt -subj "/CN=example.com" -days 365用站点名称替换example.com
  3. 将以上内容合并为一个PFX文件。
    1. 运行openssl pkcs12 -export -out example.com.pfx -inkey example.com.key -in example.com.crt,将example.com替换为网站名称。
  4. 将PFX文件上传到Azure。
    1. 在Azure门户的左侧菜单中,选择“应用程序服务”>“ ”。
    2. 从应用程序的左侧导航中,选择TLS / SSL设置,然后选择私钥证书(.pfx),然后上传上述PFX文件。
  5. 配置应用程序设置。
    1. 将上述PFX文件的指纹添加到App Service中的WEBSITE_LOAD_CERTIFICATES应用程序设置中。

IdentityServer

下面的代码示例显示了完整的Startup.cs配置,可用于启动和运行IdentityServer应用程序:

namespace IdentityServer
{
    public class Startup
    {
        public Startup(IConfiguration configuration,IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public IConfiguration Configuration { get; }

        public IWebHostEnvironment Environment { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application,visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            void ConfigureDbContext(DbContextOptionsBuilder builder)
            {
                builder.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"));
            }

            var builder = services.AddIdentityServer()
                .AddConfigurationStore(options => { options.ConfigureDbContext = ConfigureDbContext; })
                .AddOperationalStore(options => { options.ConfigureDbContext = ConfigureDbContext; });

            if (Environment.IsDevelopment())
            {
                builder.AddDeveloperSigningCredential();
            }
            else
            {
                try
                {
                    var bytes = File.ReadAllBytes($"/var/ssl/private/{Configuration["WEBSITE_LOAD_CERTIFICATES"]}.p12");
                    var certificate = new X509Certificate2(bytes);
                    builder.AddSigningCredential(certificate);
                }
                catch (FileNotFoundException)
                {
                    throw new Exception($"The certificate with the thumbprint \"{Configuration["WEBSITE_LOAD_CERTIFICATES"].Substring(0,8)}...\" could not be found.");
                }
            }
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
        {
            if (env.IsDevelopment()) app.UseDeveloperExceptionPage();

            app.UseIdentityServer();
        }
    }
}

清洁架构

以下代码示例显示了完整的DependencyInjection.cs配置,可用于启动和运行Clean Architecture应用程序:

namespace CleanArchitecture.Infrastructure
{
    public static class DependencyInjection
    {
        public static IServiceCollection AddInfrastructure(this IServiceCollection services,IConfiguration configuration)
        {
            void ConfigureDbContext(DbContextOptionsBuilder builder)
            {
                if (configuration.GetValue<bool>("UseInMemoryDatabase"))
                {
                    builder.UseInMemoryDatabase("CleanArchitectureDb");
                }
                else
                {
                    builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName));
                }
            }

            services.AddDbContext<ApplicationDbContext>(ConfigureDbContext);

            services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());

            services.AddScoped<IDomainEventService,DomainEventService>();

            services.AddDefaultIdentity<ApplicationUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            var builder = services.AddIdentityServer()
                .AddConfigurationStore(options => { options.ConfigureDbContext = ConfigureDbContext; })
                .AddOperationalStore(options => { options.ConfigureDbContext = ConfigureDbContext; })
                .AddAspNetIdentity<ApplicationUser>();

            var bytes = File.ReadAllBytes($"/var/ssl/private/{Configuration["WEBSITE_LOAD_CERTIFICATES"]}.p12");
            var certificate = new X509Certificate2(bytes);
            builder.AddSigningCredential(certificate);

            services.AddTransient<IDateTime,DateTimeService>();
            services.AddTransient<IIdentityService,IdentityService>();
            services.AddTransient<ICsvFileBuilder,CsvFileBuilder>();

            services.AddAuthentication()
                .AddIdentityServerJwt();

            return services;
        }
    }
}
,

我认为问题在于容器中的应用程序不信任本地创建的开发人员证书。您只能在计算机上使用它,因为您的计算机上已安装了开发者根证书。

容器永远不会信任dotnet dev-certs创建的证书。

您需要获得一个适当可信的证书,例如从LetsEncrypt获得。

,

.Net Clean Architecture正在services.AddIdentityServer() .AddApiAuthorization<ApplicationUser,ApplicationDbContext>();中调用DependencyInjection.cs,这是扩展方法。此方法在内部调用其他方法,其中一堆是.AddSigningCredentials()。不幸的是,此默认方法在Linux环境中将失败,因为它无法读取裸露的私钥。根据此issue,您需要在Linux中自己构建PFX。

我认为解决方案:

  1. 删除.AddApiAuthorization<ApplicationUser,ApplicationDbContext>();
  2. 编写自己的方法
var bytes = File.ReadAllBytes($"/var/ssl/private/{thump_print_goes_here}.p12");
var certificate = new X509Certificate2(bytes);
var builder = services.AddIdentityServer()
                .AddAspNetIdentity<ApplicationUser>()
                .AddOperationalStore<ApplicationDbContext>()
                .AddIdentityResources()
                .AddApiResources()
                .AddClients()
                .AddSigningCredential(certificate);
,

我遇到了在Linux应用程序服务上运行.net core spa模板的问题。我还创建了一个自签名的.pfx,如tnc1997的答案中所述。尽管答案可以拼凑,但对我来说,陷阱是:

  • 引用证书路径时,请勿使用上载的.pfx文件名。相反,如前所述,您的证书文件获得了一个新名称“ .p12”,并且在Linux容器中的“ / var / ssl / private /”下找到了。
  • 指定空白密码。不要为上传的.pfx文件指定密码。而是将appsetting的“ IdentityServer__Key__Password”设置为“”(空)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-