我正在做一个使用IdentityServer来传递令牌给Ocelot网关和它的微服务的项目。它是在本地工作的,但是当我想在一个docker容器中配置相同的设置时,我不得不信任我的自签名证书。我的容器是linux容器,并且每个项目都是用一个docker文件生成的。这些不同的项目是用一个docker合成文件添加在一起的。
所有容器都在同一个域中运行,现在我想通过网关访问我的微服务,使用IdentityServer提供的令牌,所有这些都通过https进行。
这是我的Docker覆盖文件
version: '3.4'
services:
abiidentity.web:
environment:
ASPNETCORE_ENVIRONMENT: docker
ASPNETCORE_URLS: https://+;http://+
Kestrel__Certificates__Default__Password: development
Kestrel__Certificates__Default__Path: "/root/.aspnet/https/aspnetapp-identity-server.pfx"
ports:
- "45570:443"
- "45571:80"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https
- type: bind
source: "${APPDATA}\\ASP.NET\\Https\\aspnetapp-root-cert.cer"
target: "/root/.aspnet/https/aspnetapp-root-cert.cer"
depends_on:
- idendity-db
- abiweb.apigateway
abiweb.HRM:
environment:
ASPNETCORE_ENVIRONMENT: docker
ASPNETCORE_URLS: https://+;http://+
Kestrel__Certificates__Default__Password: development
Kestrel__Certificates__Default__Path: "/root/.aspnet/https/aspnetapp-web-api.pfx"
ports:
- "45591:443"
- "45590:80"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https
- type: bind
source: "${APPDATA}/ASP.NET/Https/aspnetapp-root-cert.cer"
target: /root/.aspnet/https/aspnetapp-root-cert.cer
abiweb.apigateway:
environment:
ASPNETCORE_ENVIRONMENT: docker
ASPNETCORE_URLS: https://+;http://+
Kestrel__Certificates__Default__Password: development
Kestrel__Certificates__Default__Path: "/root/.aspnet/https/aspnetapp-gateway.pfx"
ports:
- "44351:443"
- "44350:80"
volumes:
- ${APPDATA}/ASP.NET/Https:/root/.aspnet/https
- type: bind
source: "${APPDATA}/ASP.NET/Https/aspnetapp-root-cert.cer"
target: /root/.aspnet/https/aspnetapp-root-cert.cer
我已使用以下脚本生成证书:
# Source: https://stackoverflow.com/a/62060315
# Generate self-signed certificate to be used by IdentityServer.
# When using localhost - API cannot see the IdentityServer from within the docker-compose'd network.
# You have to run this script as Administrator (open Powershell by right click -> Run as Administrator).
$ErrorActionPreference = "Stop"
$rootCN = "IdentityServerDockerDemoRootCert"
$identityServerCNs = "abiidentity.web", "localhost"
$webApiCNs = "abiweb.hrm", "localhost"
$gatewayCns = "abiweb.apigateway", "localhost"
$alreadyExistingCertsRoot = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.Subject -eq "CN=$rootCN"}
$alreadyExistingCertsIdentityServer = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.Subject -eq ("CN={0}" -f $identityServerCNs[0])}
$alreadyExistingCertsApi = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.Subject -eq ("CN={0}" -f $webApiCNs[0])}
$alreadyExistingCertsGateway = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.Subject -eq ("CN={0}" -f $gatewayCns[0])}
if ($alreadyExistingCertsRoot.Count -eq 1) {
Write-Output "Skipping creating Root CA certificate as it already exists."
$testRootCA = [Microsoft.CertificateServices.Commands.Certificate] $alreadyExistingCertsRoot[0]
} else {
$testRootCA = New-SelfSignedCertificate -Subject $rootCN -KeyUsageProperty Sign -KeyUsage CertSign -CertStoreLocation Cert:\LocalMachine\My
}
if ($alreadyExistingCertsIdentityServer.Count -eq 1) {
Write-Output "Skipping creating Identity Server certificate as it already exists."
$identityServerCert = [Microsoft.CertificateServices.Commands.Certificate] $alreadyExistingCertsIdentityServer[0]
} else {
# Create a SAN cert for both identity-server and localhost.
$identityServerCert = New-SelfSignedCertificate -DnsName $identityServerCNs -Signer $testRootCA -CertStoreLocation Cert:\LocalMachine\My
}
if ($alreadyExistingCertsApi.Count -eq 1) {
Write-Output "Skipping creating API certificate as it already exists."
$webApiCert = [Microsoft.CertificateServices.Commands.Certificate] $alreadyExistingCertsApi[0]
} else {
# Create a SAN cert for both web-api and localhost.
$webApiCert = New-SelfSignedCertificate -DnsName $webApiCNs -Signer $testRootCA -CertStoreLocation Cert:\LocalMachine\My
}
if ($alreadyExistingCertsGateway.Count -eq 1) {
Write-Output "Skipping creating API certificate as it already exists."
$webApiCert = [Microsoft.CertificateServices.Commands.Certificate] $alreadyExistingCertsGateway[0]
} else {
# Create a SAN cert for both web-api and localhost.
$webApiCert = New-SelfSignedCertificate -DnsName $gatewayCns -Signer $testRootCA -CertStoreLocation Cert:\LocalMachine\My
}
# Export it for docker container to pick up later.
$password = ConvertTo-SecureString -String "xxx" -Force -AsPlainText
$rootCertPathPfx = "C:/Users/jvdw/AppData/Roaming/ASP.NET/Https"
$identityServerCertPath = "C:/Users/jvdw/AppData/Roaming/ASP.NET/Https"
$webApiCertPath = "C:/Users/jvdw/AppData/Roaming/ASP.NET/Https"
[System.IO.Directory]::CreateDirectory($rootCertPathPfx) | Out-Null
[System.IO.Directory]::CreateDirectory($identityServerCertPath) | Out-Null
[System.IO.Directory]::CreateDirectory($webApiCertPath) | Out-Null
Export-PfxCertificate -Cert $testRootCA -FilePath "$rootCertPathPfx/aspnetapp-root-cert.pfx" -Password $password | Out-Null
Export-PfxCertificate -Cert $identityServerCert -FilePath "$identityServerCertPath/aspnetapp-identity-server.pfx" -Password $password | Out-Null
Export-PfxCertificate -Cert $webApiCert -FilePath "$webApiCertPath/aspnetapp-web-api.pfx" -Password $password | Out-Null
Export-PfxCertificate -Cert $webApiCert -FilePath "$rootCertPathPfx/aspnetapp-gateway.pfx" -Password $password | Out-Null
# Export .cer to be converted to .crt to be trusted within the Docker container.
$rootCertPathCer = "C:/Users/jvdw/AppData/Roaming/ASP.NET/Https/aspnetapp-root-cert.cer"
Export-Certificate -Cert $testRootCA -FilePath $rootCertPathCer -Type CERT | Out-Null
# Trust it on your host machine.
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root","LocalMachine"
$store.Open("ReadWrite")
$rootCertAlreadyTrusted = ($store.Certificates | Where-Object {$_.Subject -eq "CN=$rootCN"} | Measure-Object).Count -eq 1
if ($rootCertAlreadyTrusted -eq $false) {
Write-Output "Adding the root CA certificate to the trust store."
$store.Add($testRootCA)
}
$store.Close()
在执行脚本之后,我的所有pfx文件都生成了,然后我检查了这些文件在我的docker容器示例中是否可用,情况确实如此。
但当我https://aibiidentity.web在容器示例的终端中执行“wget www.example.com”时,我得到以下响应:
root@1e3233925091:/app# wget https://abiidentity.web
--2023-03-06 19:30:39-- https://abiidentity.web/
Resolving abiidentity.web (abiidentity.web)... 172.21.0.11
Connecting to abiidentity.web (abiidentity.web)|172.21.0.11|:443... connected.
ERROR: The certificate of 'abiidentity.web' is not trusted.
ERROR: The certificate of 'abiidentity.web' doesn't have a known issuer.
当我检查我的根证书是否可信时,我得到一个ok:
echo | openssl verify /usr/local/share/ca-certificates/aspnetapp-root-cert.crt
/usr/local/share/ca-certificates/aspnetapp-root-cert.crt: OK
有人能告诉我我做错了什么吗?我还关注了这篇博客文章:https://mjarosie.github.io/dev/2020/09/24/running-identityserver4-on-docker-with-https.html
1条答案
按热度按时间gudnpqoy1#
要使linux容器信任您的证书,您需要在
Dockerfile
上添加一个新步骤,将证书复制到类似/usr/local/share/ca-certificates/
的路径COPY path/to/your/crt /usr/local/share/ca-certificates/
然后运行
update-ca-certificates
RUN sudo update-ca-certificates
这样,生成的映像将在其CA存储上具有您的证书,因此信任您对使用该证书的https端点所做的任何连接。
换句话说,您需要在主机上安装证书,以连接到服务公开的TLS端点。但是,如果在容器上运行的服务还需要连接到容器公开的其他TLS端点,则该容器也需要安装证书,就像您的主机一样。
您还可以创建一个新的Dockerfile,并使用原始映像作为基础来创建一个带有证书的特定Docker映像,您可以在您的Docker-Compsoe上使用该映像,而不是原始服务映像。