Docker ASP.NET核心Web API客户端不信任Identity Server实例使用的自签名证书
这是我们的后续行动 我已使用以下脚本生成并信任自签名证书:Docker ASP.NET核心Web API客户端不信任Identity Server实例使用的自签名证书,docker,asp.net-core,ssl-certificate,identityserver4,Docker,Asp.net Core,Ssl Certificate,Identityserver4,这是我们的后续行动 我已使用以下脚本生成并信任自签名证书: #create a SAN cert for both host.docker.internal and localhost #$cert = New-SelfSignedCertificate -DnsName "host.docker.internal", "localhost" -CertStoreLocation "cert:\LocalMachine\Root" #
#create a SAN cert for both host.docker.internal and localhost
#$cert = New-SelfSignedCertificate -DnsName "host.docker.internal", "localhost" -CertStoreLocation "cert:\LocalMachine\Root"
# does not work: New-SelfSignedCertificate : A new certificate can only be installed into MY store.
$cert = New-SelfSignedCertificate -DnsName "host.docker.internal", "localhost" -CertStoreLocation cert:\localmachine\my
#export it for docker container to pick up later
$password = ConvertTo-SecureString -String "password_here" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "$env:USERPROFILE\.aspnet\https\aspnetapp.pfx" -Password $password
# trust it on your host machine
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store [System.Security.Cryptography.X509Certificates.StoreName]::Root,"LocalMachine"
$store.Open("ReadWrite")
$store.Add($cert)
$store.Close()
访问https://host.docker.internal:5500/.well-已知/openid配置
和https://localhost:5500/.well-已知/openid配置
在主机上,它按预期工作(证书正常)
但是,容器中运行的Web API应用程序对此不满意:
web_api | System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://host.docker.internal:5500/.well-known/openid-configuration'.
web_api | ---> System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://host.docker.internal:5500/.well-known/openid-configuration'.
web_api | ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
web_api | ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
web_api | at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
API的docker compose文件如下(仅限相关部分):
我怎样才能做到这一点
对identity server的调用是通过在API客户端中设置安全性以使用它来完成的(无显式HTTPS调用):
//
///配置身份验证和授权
///
///
///
公共静态无效配置安全性(此IServiceCollection服务,IConfiguration配置)
{
字符串baseUrl=configuration.GetSection(“Idam”).GetValue(“baseUrl”);
WriteLine($“身份验证服务器基本URL={baseUrl}”);
services.AddAuthentication(选项=>
{
options.DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o=>
{
o、 MetadataAddress=$“{baseUrl}/.well-known/openid配置”;
o、 Authority=“dev\u identity\u server”;
o、 受众=配置.GetSection(“Idam”).GetValue(“受众”);
o、 RequireHttpsMetadata=false;
});
services.AddAuthorization();
}
身份服务器配置
public void配置服务(IServiceCollection服务)
{
字符串connectionStr=Configuration.GetConnectionString(“默认”);
WriteLine($“[Identity server]连接字符串={connectionStr}”);
services.AddDbContext(options=>options.UseSqlServer(connectionStr));
services.AddTransient();
服务.额外性()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();
服务。AddIdentityServer(act=>
{
act.IssuerUri=“开发标识服务器”;
})
.AddDeveloperSigningCredential()
//这将添加来自DB的操作数据(代码、令牌、同意)
.addStore(选项=>
{
options.ConfigureDbContext=builder=>builder.UseSqlServer(Configuration.GetConnectionString(“默认”));
//这将启用自动令牌清理。这是可选的。
options.EnableTokenCleanup=true;
options.TokenCleanupInterval=30;//以秒为单位的间隔
})
//.AddInMemoryStedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients(配置))
.addAsNetIdentity();
services.AddDataProtection()
.persistenkeystem(新目录信息(@“\\UNC-PATH”);
services.AddTransient();
services.AddCors(options=>options.AddPolicy(“AllowAll”,p=>p.AllowAnyOrigin())
.AllowAnyMethod()
.AllowAnyHeader());
services.AddMvc(选项=>
{
options.EnableEndpointRouting=false;
}).SetCompatibilityVersion(CompatibilityVersion.Latest);
}
//此方法由运行时调用。使用此方法配置HTTP请求管道。
公共静态无效配置(IApplicationBuilder应用程序、IWebHostEnvironment环境、,
iLogger工厂日志工厂,AppIdentityDBContextSeeder数据播种机)
{
seeder.SeedTestUsers();
IdentityModelEventSource.ShowPII=true;
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseExceptionHandler(生成器=>
{
运行(异步上下文=>
{
context.Response.StatusCode=(int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add(“访问控制允许源代码”、“*”);
var error=context.Features.Get();
if(错误!=null)
{
context.Response.AddApplicationError(error.error.Message);
wait context.Response.WriteAsync(error.error.Message).ConfigureWait(false);
}
});
});
//app.UseHttpsRedirection();
app.UseStaticFiles();
附录UseCors(“AllowAll”);
app.UseIdentityServer();
app.UseMvc(路由=>
{
routes.MapRoute(
名称:“默认”,
模板:“{controller=Home}/{action=Index}/{id?}”);
});
}
经过几次尝试后,我放弃了让docker容器信任由新自签名证书生成的证书的尝试(您可以尝试让它工作-概念完全相同,只是证书在某种程度上有所不同)。然而,我在以下方面取得了成功:
$certPass=“此处输入密码”
$certsub=“host.docker.internal”
$certAltNames=“DNS:localhost,DNS:host.docker.internal,DNS:identity#u server”#我相信您也可以在此处添加单独的IP地址,如:IP:127.0.0.1
$opensslPath=“path\to\openssl\binaries”#假设您可以下载openssl,我相信无需安装
$workDir=“path\to\your\project”#我假设这将是您的解决方案根目录
$dockerDir=Join Path$workDir“ProjectApi”#您可能需要检查我对您的文件夹结构的假设是否正确
#生成具有多个域的自签名证书
启动进程-nonewindow-Wait-FilePath(加入路径$opensslPath“openssl.exe”)-ArgumentList“req-x509-nodes-days 365-newkey rsa:2048-keyout”,
(加入路径$workDir aspnetapp.key),
“-out”,(加入路径$dockerDir aspnetapp.crt),
“-subj`/CN=$certsub`”-addext`“subjectAltName=$certAltNames`”
#这次我们将PEM格式转换为PKCS#12(又名PFX)so。
web.api:
image: web_api_image
build:
context: .
dockerfile: ProjectApi/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=ContainerDev
container_name: web_api
ports:
- "5600:80"
networks:
- backend
- data_layer
depends_on:
- identity.server
- mssqlserver
- web.cache
identity.server:
image: identity_server_image
build:
context: .
dockerfile: MyProject.IdentityServer/Dockerfile
environment:
- ASPNETCORE_ENVIRONMENT=ContainerDev
- ASPNETCORE_URLS=https://+:443;http://+:80
- ASPNETCORE_Kestrel__Certificates__Default__Password=password_here
- ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
volumes:
- ~/.aspnet/https:/https:ro
container_name: identity_server
ports:
- "5500:443"
- "5501:80"
networks:
- backend
- data_layer
depends_on:
- mssqlserver
/// <summary>
/// configures authentication and authorization
/// </summary>
/// <param name="services"></param>
/// <param name="configuration"></param>
public static void ConfigureSecurity(this IServiceCollection services, IConfiguration configuration)
{
string baseUrl = configuration.GetSection("Idam").GetValue<string>("BaseUrl");
Console.WriteLine($"Authentication server base URL = {baseUrl}");
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.MetadataAddress = $"{baseUrl}/.well-known/openid-configuration";
o.Authority = "dev_identity_server";
o.Audience = configuration.GetSection("Idam").GetValue<string>("Audience");
o.RequireHttpsMetadata = false;
});
services.AddAuthorization();
}
public void ConfigureServices(IServiceCollection services)
{
string connectionStr = Configuration.GetConnectionString("Default");
Console.WriteLine($"[Identity server] Connection string = {connectionStr}");
services.AddDbContext<AppIdentityDbContext>(options => options.UseSqlServer(connectionStr));
services.AddTransient<AppIdentityDbContextSeedData>();
services.AddIdentity<AppUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer(act =>
{
act.IssuerUri = "dev_identity_server";
})
.AddDeveloperSigningCredential()
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("Default"));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30; // interval in seconds
})
//.AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients(Configuration))
.AddAspNetIdentity<AppUser>();
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\UNC-PATH"));
services.AddTransient<IProfileService, IdentityClaimsProfileService>();
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
services.AddMvc(options =>
{
options.EnableEndpointRouting = false;
}).SetCompatibilityVersion(CompatibilityVersion.Latest);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env,
ILoggerFactory loggerFactory, AppIdentityDbContextSeedData seeder)
{
seeder.SeedTestUsers();
IdentityModelEventSource.ShowPII = true;
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message).ConfigureAwait(false);
}
});
});
// app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCors("AllowAll");
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
FROM ubuntu:14.04
RUN apt-get update \
&& apt-get install -y wget \
&& rm -rf /var/lib/apt/lists/*
USER root
###### you probably only care about the following three lines
ADD ./aspnetapp.crt /usr/local/share/ca-certificates/asp_dev/
RUN chmod -R 644 /usr/local/share/ca-certificates/asp_dev/
RUN update-ca-certificates --fresh
######
ENTRYPOINT tail -f /dev/null