Identity Server - Dockerization - Part 2
09 Feb 2022- Identity Server - Example
- Identity Server - EF to PostgreSQL
- Identity Server - Dockerization (1)
- Identity Server - Dockerization (2)
- Identity Server - Kubernetes
- Identity Server failure
Npgsql.NpgsqlException (0x80004005): Exception while connecting is4_1 | ---> System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (99): Cannot assign requested address [::1]:5432
NOTE: localhost:5432 is unresolvable in container, which can only resolve db service
- Add one more environment variable in docker-compose.override.yml to overwrite ConnectionStrings:DefaultConnection in appSettings.json
is4: environment: - ConnectionStrings:DefaultConnection=Server=db;Port=5432;Database=IS4Database;User Id=postgres;Password=P@ssword!
Identity Server container will start workingđ
- Another exception will throw after navigating to Privacy page from Client app
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] client_1 | An unhandled exception has occurred while executing the request. client_1 | System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. client_1 | ---> System.IO.IOException: IDX20804: Unable to retrieve document from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. client_1 | ---> System.Net.Http.HttpRequestException: Cannot assign requested address client_1 | ---> System.Net.Sockets.SocketException (99): Cannot assign requested address client_1 | at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken) client_1 | --- End of inner exception stack trace ---
NOTE: Client needs to communicate to Identity Providerâs well-known endpoint and validate access token, however, it couldnât recognize localhost:5000 but is4
- Here is the most tricky step:
- In Client project, update MetadataAddress to load well-known configuration from is4 instead of localhost:5000
// Startup.cs: public void ConfigureServices(IServiceCollection services) { ...... var containerHost = Configuration.GetValue<string>("IdentityServer:ContainerHost"); services.AddAuthentication(options => { options.DefaultScheme = "cookie"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("cookie") .AddOpenIdConnect("oidc", options => { ...... // DEV ONLY // Container Identity Server replace well-known endpoint // e.g. Replace http://is4 to http://localhost:5000, as localhost is unknown options.MetadataAddress = $"{containerHost}/.well-known/openid-configuration"; });
- In Client project, replace the redirect Url from is4 to localhost:5000
public void Configure(IApplicationBuilder app) { ...... // DEV ONLY // Container Identity Server Redirection // e.g. Replace http://is4 to http://localhost:5000 app.Use(async (httpcontext, next) => { await next(); if (httpcontext.Response.StatusCode == StatusCodes.Status302Found) { var containerHost = Configuration.GetValue<string>("IdentityServer:ContainerHost"); var authority = Configuration.GetValue<string>("IdentityServer:Authority"); if (!containerHost.Equals(authority, StringComparison.OrdinalIgnoreCase)) { string location = httpcontext.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Location]; httpcontext.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Location] = location.Replace(containerHost, authority); } } }); ...... }
NOTE: Without this step, browser will redirect to https://is4, which canât be resolved by browser
- In Client project, update MetadataAddress to load well-known configuration from is4 instead of localhost:5000
- Update environment variables in docker-compose.override.yml
client: environment: - IdentityServer:Authority=https://localhost:5000 - IdentityServer:ContainerHost=https://is4
- Certificate validation failure for domain is4
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request. System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. ---> System.IO.IOException: IDX20804: Unable to retrieve document from: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
NOTE: As mentioned in Identity Server - Dockerization (1) #3, the certificate ONLY allows localhost, therefore the certificate is invalid for is4
- Genereate self-signed certificate
- Add configuration file e.g. âis4-container-cert.confâ to ./Certificates folder
[req] distinguished_name = req_distinguished_name req_extensions = req_ext x509_extensions = v3_ca [req_distinguished_name] commonName = jaylin commonName_default = localhost commonName_max = 64 [req_ext] subjectAltName = @alt_names 1.3.6.1.4.1.311.84.1.1=ASN1:UTF8String:Something [v3_ca] subjectAltName = @alt_names basicConstraints = critical, CA:false keyUsage = keyCertSign, cRLSign, digitalSignature,keyEncipherment [alt_names] DNS.1 = localhost DNS.2 = 127.0.0.1 DNS.3 = is4 DNS.4 = api
- Open bash command and navigate to Certificates folder
- Run openssl command to generate Linux certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./is4-container-cert.key -out ./is4-container-cert.crt -config ./is4-container-cert.conf
- Run openssl command to generate Windows certificate
openssl pkcs12 -export -out ./is4-container-cert.pfx -inkey ./is4-container-cert.key -in ./is4-container-cert.crt
- Add configuration file e.g. âis4-container-cert.confâ to ./Certificates folder
- Update Dockerfile for each project to install crt in container
FROM base AS final COPY ["./Certificates/is4-container-cert.crt", "/usr/local/share/ca-certificates/is4-container-cert.crt"] RUN chmod 644 /usr/local/share/ca-certificates/is4-container-cert.crt RUN update-ca-certificates WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "IdentityProvider.dll"]
- Update Kestrel environment variables and volumes in docker-compose.override.yml for api, client and is4 services
client: environment: - ASPNETCORE_Kestrel__Certificates__Default__Password=P@ssword! - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/is4-container-cert.pfx volumes: - .\Certificates:/https/
It will create a volume to map the Certificates folder, and Kestrel Password comes from #7.4 when generating pfx certificate.
- Install pfx certificate on Windows
- Right Click on is4-container-cert.pfx
- Install PFX
- Current User
- Fill Password
- Place all certificates in the following store âTrusted Root Certification Authoritiesâ
- Run
docker-compose up --build
- Browse https://localhost:5002
- Navigate to Privacy, it will redirect to Identity Server to login (username / password: scott / Password123!)
- After login successfully, it will redirect back to Privacy page
- Click on Call Api button
- API access authorized! should return