首页 > 解决方案 > Net Core Docker 容器 API。无法使用 System.Security.Cryptography.CryptographicException 处提供的密码读取证书数据

问题描述

使用 HTTPS 的 docker 容器中的 Web App Document Manager 和 Web API Document Uploader 之间的通信不起作用。我遵循以下关于如何在 docker 容器中使用 https 的建议。我假设我只需要在 API 中整理 SSL 证书。

https://github.com/dotnet/AspNetCore.Docs/issues/6199

有趣的一点是,Web App Document Manager 中的 https 可以正常工作,当我在浏览器中打开 Web App 时,https 很好。我很困扰。

我按照此链接https://github.com/dotnet/dotnet-docker/blob/main/samples/run-aspnetcore-https-development.md中的说明创建了 documentuploader.pfx 文件

但是我得到了响应“一个有效的 HTTPS 证书已经存在。”,因此我导出了一个已经存在的名为 localhost.pfx 的证书,但它没有用。我检查了密码,但它是正确的。

当我使用 docker compose 运行容器时,出现以下错误。

System.Security.Cryptography.CryptographicException
  HResult=0x80070056
  Message=The certificate data cannot be read with the provided password, the password may be incorrect.
  Source=System.Security.Cryptography.X509Certificates
  StackTrace:
   at Internal.Cryptography.Pal.UnixPkcs12Reader.Decrypt(SafePasswordHandle password)
   at Internal.Cryptography.Pal.PkcsFormatReader.TryReadPkcs12(OpenSslPkcs12Reader pfx, SafePasswordHandle password, Boolean single, ICertificatePal& readPal, List`1& readCerts)
   at Internal.Cryptography.Pal.PkcsFormatReader.TryReadPkcs12(ReadOnlySpan`1 rawData, SafePasswordHandle password, Boolean single, ICertificatePal& readPal, List`1& readCerts, Exception& openSslException)
   at Internal.Cryptography.Pal.OpenSslX509CertificateReader.FromFile(String fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
   at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Certificates.CertificateConfigLoader.LoadCertificate(CertificateConfig certInfo, String endpointName)
   at Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader.LoadDefaultCert()
   at Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader.Reload()
   at Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader.Load()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<BindAsync>d__32.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.
...

System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at DocumentUploader.Program.Main(String[] args)

  This exception was originally thrown at this call stack:
    Internal.Cryptography.Pal.UnixPkcs12Reader.VerifyAndDecrypt(System.ReadOnlySpan<char>, System.ReadOnlyMemory<byte>)
    Internal.Cryptography.Pal.UnixPkcs12Reader.Decrypt(Microsoft.Win32.SafeHandles.SafePasswordHandle)

Inner Exception 1:
CryptographicException: The certificate data cannot be read with the provided password, the password may be incorrect.

我的码头工人撰写是

version: '3.5'

services:
  documentmanager:
    image: ${DOCKER_REGISTRY-}documentmanager
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://localhost;http://localhost
      - ASPNETCORE_HTTPS_PORT=44349   
      # Do not create development certificate in an environment that will be distributed.
      #- DOTNET_GENERATE_ASPNET_CERTIFICATE=false
    networks:
      - doc_manager
    ports:
      - "51218:80"
      - "44349:443"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets/:/root/.microsoft/usersecrets
      - ${APPDATA}/ASP.NET/Https/:/root/.aspnet/https/
    build:
      context: .
      dockerfile: Document Manager/Dockerfile
  documentuploader:
    image: ${DOCKER_REGISTRY-}documentuploader
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://localhost;http://localhost
      - ASPNETCORE_HTTPS_PORT=44335
      # Do not create development certificate in an environment that will be distributed.
      #- DOTNET_GENERATE_ASPNET_CERTIFICATE=false
    networks:
      - doc_manager
    ports:
      - "51217:80"
      - "44335:443"
    volumes:
      - ${APPDATA}/Microsoft/UserSecrets/:/root/.microsoft/usersecrets
      - ${APPDATA}/ASP.NET/Https/:/root/.aspnet/https/
    build:
      context: .
      dockerfile: DocumentUploader/Dockerfile

networks:
  doc_manager:
    driver: bridge

我在 documentuploader api 项目中的秘密文件是

    "Kestrel": {
      "Certificates": {
        "Default": {
          "Path": "/root/.aspnet/https/documentuploader.pfx",
          "Password": "PASSWORD IS HERE"
        }
      }
    }

我的 DocumentUploader.pfx 被复制到容器中的 /root/.aspnet/https 文件夹中。

当我使用 openssl 程序检查密码是否正确时,显示的内容是

MAC: sha1, Iteration 2000
MAC length: 20, salt length: 20
PKCS7 Data
Shrouded Keybag: <key bag here>, Iteration 2000
PKCS7 Encrypted data: <PKCS7 here>, Iteration 2000
Certificate bag
Bag Attributes
    localKeyID: 01 00 00 00
    friendlyName: IIS Express Development Certificate
subject=CN = localhost

issuer=CN = localhost

---BEGIN CERIFICATE---

有什么帮助吗?

标签: dockerasp.net-coresslhttpsdocker-compose

解决方案


如果您已按照说明https://github.com/dotnet/dotnet-docker/blob/main/samples/run-aspnetcore-https-development.md,则以下 docker compose 适用于我的情况:

版本:'3.5'

服务:

dockerex4:

image: dockerex4image
container_name: DockerEx4
environment:
  - ASPNETCORE_ENVIRONMENT=Development      
  - ASPNETCORE_URLS=http://+:80;https://+:443

  # If you instead choose to copy cert in Dockerfile, you don't need volumes
  #- ASPNETCORE_Kestrel__Certificates__Default__Path=/app/DockerEx4.pfx
  #- ASPNETCORE_Kestrel__Certificates__Default__Password=crypticpassword
ports:
  - 9000:80
  - 9001:443
volumes:   
  - C:\Users\rwilliams\AppData\Roaming\Microsoft\UserSecrets:/root/.microsoft/usersecrets:ro
  - C:\Users\rwilliams\source\repos\slnDragAndDrop\Artifacts\certs:/root/.aspnet/https:ro

注意:这些文档和我的 docker-compose 中的一个差异是:

dotnet user-secrets -p aspnetapp\aspnetapp.csproj 设置“Kestrel:Certificates:Development:Password”“crypticpassword”

暗示在你的秘密中,“默认”应该是“发展”。很抱歉代码中的空行。您不应该同时需要卷和 ASPNETCORE_Kestrel 环境变量。在我的方法中也是非标准的,我选择在我的解决方案根目录下指定一个卷证书目录。

编辑:另外,你很可能有错误的证书。友好名称应为“ASP.NET Core HTTPS 开发证书”而不是“IIS 开发...”


推荐阅读