如何在ASP.NET Core应用程序中正确安装Docker证书?

8
我已经在网络和Stackoverflow上找了一些资料,但是我遇到了一些问题不能解决。我正在尝试将我的ASP.NET Core应用程序部署到Docker中。我有一个证书,称之为"FooCert.pfx",我也有一个".PEM"文件格式的副本(FooCert.pem)。我试图使我的应用程序在运行时能够找到这个证书。我有一个docker-compose.yml文件来构建和启动容器;我有一些环境变量来链接在Windows主机上证书的位置;最后,我有一个DockerFile来包装我应用程序所需的行为。
当我的应用程序尝试从linux容器的证书存储中读取时,它抛出异常。他说找不到证书并且无法识别存储。以下是我dockerfile中相关的行:
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /src
...

COPY ./FooCert.pem /etc/ssl/certs/FooCert.pem
COPY ./FooCert.pem /usr/local/share/ca-certificates/FooCert.pem
COPY ./FooCert.pfx /usr/local/share/ca-certificates/FooCert.pfx

RUN openssl pkcs12 -in /usr/local/share/ca-certificates/FooCert.pfx -nocerts -nodes | sed -ne '/-BEGIN PRIVATE KEY-/,/-END PRIVATE KEY-/p' > FooCert.key
RUN openssl pkcs12 -in /usr/local/share/ca-certificates/FooCert.pfx -clcerts -nokeys | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > FooCertClientcert.cer
RUN openssl pkcs12 -in /usr/local/share/ca-certificates/FooCert.pfx -cacerts -nokeys -chain | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > FooCertcacerts.cer

COPY ./FooCert.pem /etc/ssl/certs/FooCert.pem
COPY ./FooCert.pem /usr/local/share/ca-certificates/FooCert.pem
RUN ls /usr/local/share/ca-certificates
RUN ls /etc/ssl/certs
RUN update-ca-certificates
...
[code to expose ports, define entrypoint, etc here]

我知道Linux与Windows不同,缺少相同的证书存储库,我已在代码中进行了调整。我已尝试使用CurrentUser和LocalMachine打开根和证书颁发机构存储库,如下所示:var certStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine);但是这会导致Linux容器出现异常,而在Windows上没有问题。
另外,我也了解到为了安全起见,将证书暴露在容器中并不是一个好习惯。
简而言之,存储证书的建议做法是什么?在ASP.NET Core中,如何正确访问/查找Linux容器上存储库中的证书?请注明HTML标签。

回到这个问题后,我了解到通常使用Kubernetes来完成这些工作...但如果有人能提供更多上下文的答案,其他人可以参考,那将非常好;此外,Docker实际上是通往Kubernetes和Pod等的跳板,但同样,能够在这里提供指导的人将是最有帮助的。 - rdelgado-incinc
我传递证书到容器的一种方式是将证书作为嵌入式资源,并在 Program.cs 中从我的资源中读取。我认为这不是一个好的行业最佳实践,特别是对于有专门管理秘密(例如证书)的基础架构团队的组织。我也看到了在 MSFT 的 dockerdocker-compose 示例中传递证书的方式。 - rdelgado-incinc
根据上面的注释,如何在容器内访问这些资源?我们需要编写一个.sh脚本来安装和更新证书,然后通过主题名称(或其他从证书存储中读取的方法)来获取证书吗? - rdelgado-incinc
1
目前Linux仅支持StoreLocation.CurrentUser。请参见https://learn.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography - charlierlee
1个回答

3
我找到的一种解决方案如下:
  1. 在你的 docker-compose.yml 文件中挂载证书目录:
version: '3.6'

services:
  dockertemplate:
    image: ${DOCKER_REGISTRY-}dockertemplate
    build:
        context: .
        dockerfile: DockerTemplate/Dockerfile
    ports:
    #bind [host port]:[container port]
        - 8000:80
        - 5051:443
        - 5050:5050
    environment:
        - "ASPNETCORE_URLS=https://+;http://+"
        - Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
        - Kestrel__Certificates__Default__Password=changeit
    volumes:
      - ~/.aspnet/https:/https:ro #this is very important

我的Dockerfile:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["DockerTemplate/DockerTemplate.csproj", "DockerTemplate/"]
RUN dotnet restore "DockerTemplate/DockerTemplate.csproj"
COPY . .
WORKDIR "/src/DockerTemplate"
RUN dotnet build "DockerTemplate.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "DockerTemplate.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "DockerTemplate.dll"]

在你的 Program.cs 文件中:
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();

                    webBuilder.UseKestrel(options => options.ListenAnyIP(5050, listenOptions => listenOptions.UseHttps(
                        adapterOptions =>
                        {
                            adapterOptions.ServerCertificate = new X509Certificate2("/https/aspnetapp.pfx", "changeit");
                        })));
                });

请确保您已经配置了共享所需的权限,以便共享您选择授权访问的目录。如果您在系统上没有看到配置的目录,请确保重新启动计算机。您可以尝试重新启动Docker实例,但是对我而言,重新启动计算机就可以解决问题。
请注意:您可能想使用Kubernetes来解决问题。这是一个使用docker-compose的最小解决方案。这只是您可以采取的一种方法。
-- 附加编辑
我最近学到,您可以完全删除 .UseKestrel() 部分。ASP.NET会自动为您连接应用程序,并且您可以在容器中的端口:443/:80上运行应用程序。理想情况下,您应该将证书和SSL与容器分离。证书是一个“秘密”,即需要安全存储的东西,因此您可以将80端口转发到您想要的http端口,将443端口转发到您想要的https端口。launchSettings.json(项目中的properties文件夹)是您设置适当的kestrel选项的位置,类似于docker-compose.yml的设置方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接