У меня проблема с HTTPS-связью между Docker nginx: Angular и .NET Core API.
Я создал цепные самоподписанные сертификаты для двух API и угловой страницы, используя:
mkdir certs
openssl genrsa -des3 -out certs/RootCA.key 4096
openssl req -x509 -new -nodes -key certs/RootCA.key -sha256 -days 1024 -out certs/RootCA.crt -subj "/C=PL/ST=WR/O=Solteq/CN=ROOT Cert"
openssl genrsa -out certs/angular.key 2048
openssl genrsa -out certs/api.key 2048
openssl genrsa -out certs/identityserver.key 2048
openssl req -new -sha256 -key certs/angular.key -subj "/C=PL/ST=WR/O=Solteq/CN=angular" -out certs/angular.csr
openssl req -new -sha256 -key certs/api.key -subj "/C=PL/ST=WR/O=Solteq/CN=api" -out certs/api.csr
openssl req -new -sha256 -key certs/identityserver.key -subj "/C=PL/ST=WR/O=Solteq/CN=identityserver" -out certs/identityserver.csr
openssl x509 -req -in certs/angular.csr -CA certs/RootCA.crt -CAkey certs/RootCA.key -CAcreateserial -out certs/angular.crt -days 1500 -sha256
openssl x509 -req -in certs/api.csr -CA certs/RootCA.crt -CAkey certs/RootCA.key -CAcreateserial -out certs/api.crt -days 1500 -sha256
openssl x509 -req -in certs/identityserver.csr -CA certs/RootCA.crt -CAkey certs/RootCA.key -CAcreateserial -out certs/identityserver.crt -days 1500 -sha256
openssl pkcs12 -export -out certs/RootCA.pfx -inkey certs/RootCA.key -in certs/RootCA.crt
openssl pkcs12 -export -out certs/angular.pfx -inkey certs/angular.key -in certs/angular.crt
openssl pkcs12 -export -out certs/api.pfx -inkey certs/api.key -in certs/api.crt
openssl pkcs12 -export -out certs/identityserver.pfx -inkey certs/identityserver.key -in certs/identityserver.crt
Первая часть - успешная, это означает, что я могу подключить два API через HTTPS, они настроеныследующим образом:
API:
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["src/Demo.Api/Demo.Api.csproj", "src/Demo.Api/"]
COPY ["src/Demo.Context/Demo.Context.csproj", "src/Demo.Context/"]
COPY ["src/Demo.Domain/Demo.Domain.csproj", "src/Demo.Domain/"]
RUN dotnet restore "src/Demo.Api/Demo.Api.csproj"
COPY . .
WORKDIR "/src/src/Demo.Api"
RUN dotnet build "Demo.Api.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Demo.Api.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
COPY certs/api.pfx /root/.dotnet/https
COPY certs/RootCA.crt /usr/local/share/ca-certificates/RootCA.crt
RUN chmod 644 /usr/local/share/ca-certificates/RootCA.crt
RUN update-ca-certificates
ENTRYPOINT ["dotnet", "Demo.Api.dll"]
Identity Server:
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["src/Demo.IdentityServer/Demo.IdentityServer.csproj", "src/Demo.IdentityServer/"]
RUN dotnet restore "src/Demo.IdentityServer/Demo.IdentityServer.csproj"
COPY . .
WORKDIR "/src/src/Demo.IdentityServer"
RUN dotnet build "Demo.IdentityServer.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "Demo.IdentityServer.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
COPY certs/identityserver.pfx /root/.dotnet/https
COPY certs/RootCA.crt /usr/local/share/ca-certificates/RootCA.crt
RUN chmod 644 /usr/local/share/ca-certificates/RootCA.crt
RUN update-ca-certificates
ENTRYPOINT ["dotnet", "Demo.IdentityServer.dll"]
И последняя часть, которая не будет работать, - это Angular APP, который настроен следующим образом: Dockerfile:
### STAGE 1: Build ###
# We label our stage as ‘builder’
FROM node:12-alpine as build
COPY src/Demo.angular/ClientApp/package.json src/Demo.angular/ClientApp/package-lock.json ./
## Storing node modules on a separate layer will prevent unnecessary npm installs at each build
RUN npm ci && mkdir /ng-app && mv ./node_modules ./ng-app
WORKDIR /ng-app
COPY src/Demo.angular/ClientApp/ .
## Build the angular app in production mode and store the artifacts in dist folder
WORKDIR /ng-app
RUN npm run build-locale-dev
### STAGE 2: Setup ###
FROM nginx:1.17.3-alpine as runtime
# copy artifact build from the 'build environment'
COPY --from=build /ng-app/dist /etc/nginx/html/
# expose port 443
EXPOSE 443
COPY src/Demo.angular/ClientApp/nginx.conf /etc/nginx/nginx.conf
COPY certs/angular.crt /etc/ssl/certs/
COPY certs/angular.key /etc/ssl/keys/
COPY certs/RootCA.crt /usr/local/share/ca-certificates/RootCA.crt
RUN chmod 644 /usr/local/share/ca-certificates/RootCA.crt
# run nginx
CMD ["nginx", "-g", "daemon off;"]
nginx.conf:
events {
}
http {
server {
listen 443 ssl;
server_name bvl;
ssl_certificate /etc/ssl/certs/angular.crt;
ssl_certificate_key /etc/ssl/keys/angular.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
index index.html;
location /en {
try_files $uri $uri/ /en/index.html =404;
}
location /de {
try_files $uri $uri/ /de/index.html =404;
}
location = / {
return 301 https://$http_host/en$request_uri;
}
location ~ \.css {
add_header Content-Type text/css;
}
location ~ \.js {
add_header Content-Type application/x-javascript;
}
}
}
Я пробовал другую конфигурацию, но все еще не могу пройти проверку сертификата API:
api_1 | [06:59:30 DBG] Failed to authenticate HTTPS connection.
api_1 | System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL. ---> Interop+Crypto+OpenSslCryptographicException: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown
api_1 | --- End of inner exception stack trace ---
api_1 | at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, Byte[] recvBuf, Int32 recvOffset, Int32 recvCount, Byte[]& sendBuf, Int32& sendCount)
api_1 | at System.Net.Security.SslStreamPal.HandshakeInternal(SafeFreeCredentials credential, SafeDeleteContext& context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)
api_1 | --- End of inner exception stack trace ---
api_1 | at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
api_1 | at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
api_1 | at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
api_1 | at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
api_1 | at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
api_1 | at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
api_1 | --- End of stack trace from previous location where exception was thrown ---
api_1 | at System.Net.Security.SslState.ThrowIfExceptional()
api_1 | at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
api_1 | at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
api_1 | at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult)
api_1 | at System.Net.Security.SslStream.<>c.<AuthenticateAsServerAsync>b__51_1(IAsyncResult iar)
api_1 | at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)