You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker运行ASP.NET Core应用时SSL证书加载异常求助

问题描述

在Mac系统中通过Keychain Access生成SSL证书并导出为.cer文件,本地运行正常,但部署到Docker时抛出异常:

Unhandled exception. System.NotSupportedException: The server mode SSL must use a certificate with the associated private key.

为解决该问题,我导出了证书的.p12文件,并通过以下命令提取.key文件:

Nabils-MBP:certs nabilhaffar$ openssl pkcs12 -legacy -nocerts -in mycert.p12 -out mykey.key 

随后用原.cer文件和提取出的mykey.key生成.pfx文件:

openssl pkcs12 -export -out mycert.pfx -inkey mykey.key -in mycert.cer

但现在出现新的异常:

Unhandled exception. System.Security.Cryptography.CryptographicException: The certificate data cannot be read with the provided password, the password may be incorrect.

需要让证书在本地Docker及AWS EC2实例中正常工作。


相关配置代码

.NET 7 Program.cs中的证书加载逻辑

var certFilePath = builder.Configuration["Kestrel:Endpoints:Https:Certificate:Path"];
var certPassword = builder.Configuration["Cert:Password"];
Console.WriteLine($"Certificate Path: {certFilePath}");
Console.WriteLine($"Certificate Password: {certPassword}");
if (string.IsNullOrEmpty(certFilePath) || string.IsNullOrEmpty(certPassword))
{
    throw new Exception("Certificate file path or password not configured.");
}


try
{
    var certificate = new X509Certificate2(certFilePath, certPassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
    builder.WebHost.ConfigureKestrel((context, options) =>
    {
        options.ConfigureHttpsDefaults(httpsOptions =>
        {
            httpsOptions.ServerCertificate = certificate;
        });
        options.Listen(IPAddress.Any, 80);   // HTTP port
        options.Listen(IPAddress.Any, 5001, listenOptions =>
        {
            listenOptions.UseHttps();        // HTTPS port with a certificate
        });
    });


    // Use certificate (e.g., add to services for HTTPS)
    builder.Services.AddSingleton(certificate);
}
catch (CryptographicException ex)
{
    Console.WriteLine($"CryptographicException: {ex.Message}");
    throw;
}

Dockerfile

# Use the official .NET 7 SDK image for building the app
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /app

# Copy and restore dependencies
COPY *.sln ./
COPY AssetTracker/*.csproj ./AssetTracker/
RUN dotnet restore AssetTracker/AssetTracker.csproj

# Copy everything else and build the application
COPY AssetTracker/. ./AssetTracker/
WORKDIR /app/AssetTracker
RUN dotnet publish -c Release -o /app/publish

# Use the .NET runtime image to run the app
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 80
EXPOSE 443
EXPOSE 5001
CMD ["dotnet", "AssetTracker.dll"]

RUN apt update && apt install -y curl

docker-compose.dev.yml

services:
  assettracker:
    image: assettracker
    build: .
    ports:
      - "8080:80"
      - "5001:443"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - Redis__Host=redis
      - Redis__Port=6379
    volumes:
      - /Users/nabilhaffar/.microsoft/usersecrets:/root/.microsoft/usersecrets:ro
      - /Users/nabilhaffar/.aspnet/DataProtection-Keys:/root/.aspnet/DataProtection-Keys
      - ./Assettracker/certs:/root/certs  # Mount certs to /root/certs inside container

    env_file:
      - .env
    depends_on:
      - redis

  redis:
    image: redis:latest
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

volumes:
  redis-data:
    driver: local

appsettings.Development.json

{
  "Kestrel": {
    "Endpoints": {
      "Https": {
        "Url": "https://0.0.0.0:443",
        "Certificate": {
          "Path": "/root/certs/mycert.pfx"
          //"Path": "certs/mycert.cer" // Use the relative path locally
        },
        "CertificateKey": {
          //"Path": "/root/certs/mykey.key",
          //"Path": "certs/mykey-pkcs8.key" // Use the relative path locally

        }
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },

  "Redis": {
    "Host": "127.0.0.1",
    "Port": "6379"
  }
}

解决方案建议

  • 直接导出带私钥的PFX文件:从Keychain Access导出证书时,直接选择.p12(即PFX)格式,导出过程设置密码并确保包含私钥,跳过后续OpenSSL拆分合并步骤,避免密码不匹配或格式损坏。
  • 确保密码完全一致:若必须用OpenSSL生成PFX,执行openssl pkcs12 -export时设置的输出密码,要和配置中Cert:Password的内容完全相同;提取.key时若设置了密码,生成PFX时需输入该密码解锁私钥。
  • 调整密钥存储参数:在Linux环境(Docker/EC2)中,将X509KeyStorageFlags改为EphemeralKeySet | Exportable,避免系统密钥存储的权限问题:
    var certificate = new X509Certificate2(certFilePath, certPassword, X509KeyStorageFlags.EphemeralKeySet | X509KeyStorageFlags.Exportable);
    
  • 验证PFX有效性:在本地用以下命令验证PFX文件是否正常,输入密码后能显示证书和私钥信息则说明文件没问题:
    openssl pkcs12 -info -in mycert.pfx
    
  • 检查Docker挂载路径:进入容器验证.pfx文件是否存在于指定路径:
    docker exec -it <容器ID> ls /root/certs/
    

内容的提问来源于stack exchange,提问作者Nabil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:54:50