Traefik、Keycloak与WebApp集成故障:无法获取OpenID配置
问题描述
通过Docker Compose在服务器部署Traefik、Keycloak与WebApp服务,预期流程为:WebApp基于OpenIdConnect实现授权,访问其域名时会调用Keycloak容器展示授权表单,登录成功后Keycloak重定向回WebApp并展示内容。
当前异常:访问WebApp域名时,日志报错Unable to obtain configuration from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration',但直接访问该链接可正常显示Realm的配置信息,怀疑问题出在Traefik的请求处理逻辑上。
Docker Compose配置
services: reverse-proxy: image: traefik:v3.1 command: - "--log.level=DEBUG" - "--providers.docker" - "--providers.docker.exposedbydefault=false" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" - "--certificatesresolvers.myresolver.acme.email=email@domain.cloud" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme-v1.json" - "--entrypoints.web.address=:8080" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.asDefault=true" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" ports: - "8080:8080" - "443:443" volumes: - letsencrypt:/letsencrypt - /var/run/docker.sock:/var/run/docker.sock networks: - webnet kcdb: container_name: kcdb image: postgres:16.2 restart: unless-stopped environment: - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_DB} expose: - 5432 volumes: - pgdata:/var/lib/postgresql/data networks: - webnet keycloak: image: quay.io/keycloak/keycloak:26.0.7 command: start environment: KC_HOSTNAME: keycloak.thesispath.cloud PROXY_ADDRESS_FORWARDING: true KC_HOSTNAME_PORT: 8088 KC_HOSTNAME_STRICT: false KC_PROXY_HEADERS: 'xforwarded' KC_HTTP_ENABLED: true KEYCLOAK_LOGLEVEL: DEBUG KC_HEALTH_ENABLED: true KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} KC_DB: postgres KC_DB_URL: jdbc:postgresql://kcdb/${POSTGRES_DB} KC_DB_USERNAME: ${POSTGRES_USER} KC_DB_PASSWORD: ${POSTGRES_PASSWORD} restart: always ports: - "8088:8088" depends_on: - kcdb labels: - "traefik.enable=true" - "traefik.http.routers.keycloak.rule=Host(`keycloak.domain.cloud`)" - "traefik.http.routers.keycloak.entrypoints=websecure" - "traefik.http.routers.keycloak.tls.certresolver=myresolver" networks: - webnet webApp: image: webApp:v6.1 labels: - "traefik.enable=true" - "traefik.http.routers.webApp.rule=Host(`webApp.domain.cloud`)" - "traefik.http.routers.webApp.entrypoints=websecure" - "traefik.http.routers.webApp.tls.certresolver=myresolver" networks: - webnet networks: webnet: driver: bridge volumes: pgdata: letsencrypt:
Program.cs中的OpenIdConnect配置
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { options.Authority = builder.Configuration["Authentication:OpenId:Authority"]; options.ClientId = builder.Configuration["Authentication:OpenId:ClientId"]; options.ClientSecret = builder.Configuration["Authentication:OpenId:ClientSecret"]; options.ResponseType = "code"; options.SaveTokens = true; options.RequireHttpsMetadata = bool.Parse(builder.Configuration["Authentication:OpenId:Metadata"]); if (options.RequireHttpsMetadata) { options.MetadataAddress = builder.Configuration["Authentication:OpenId:MetaAddress"]; } options.Scope.Add("openid"); options.CallbackPath = "/login-callback"; options.SignedOutCallbackPath = "/logout-callback"; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "preferred_username", RoleClaimType = "roles" }; })
appsettings.json配置
"OpenId": { "ClientId": "InvestigacionClient", "ClientSecret": "ClientSecret", "Authority": "https://example.com/realms/Investigacion", "MetaAddress": "https://example.com/realms/Investigacion/.well-known/openid-configuration", "Metadata": true }
错误日志
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1] An unhandled exception has occurred while executing the request. System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration'. Will retry at '12/16/2024 22:34:40 +00:00'. Exception: 'System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://example.com/realms/Investigacion/.well-known/openid-configuration'. ---> System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing. ---> System.TimeoutException: A task was canceled. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled. at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
问题分析与解决方案
从错误日志看,WebApp容器内部请求Keycloak的OIDC元数据地址超时,外部访问正常,核心原因是容器内部网络路由或配置冲突,以下是针对性修复方案:
1. 修正Keycloak端口与代理配置
Keycloak默认监听8080端口,但当前配置映射了8088端口却未指定内部监听端口,同时代理配置错误导致Traefik转发请求无法到达Keycloak:
keycloak: environment: # 指定内部监听端口 KC_HTTP_PORT: 8088 # 移除错误的端口配置,使用edge代理适配Traefik KC_PROXY: edge # 关闭严格HTTPS检查,适配内部HTTP访问 KC_HOSTNAME_STRICT_HTTPS: false # 删除KC_HOSTNAME_PORT配置,由Traefik处理端口转发 ports: - "8088:8088"
2. 解决WebApp内部DNS解析超时问题
WebApp容器内部无法正确解析Keycloak的外部域名,导致请求超时,可通过两种方式修复:
- 方案一:添加容器hosts映射
让WebApp直接将Keycloak域名解析到Traefik容器IP(替换TRAEFIK_IP为宿主机或Traefik容器的实际IP):
webApp: extra_hosts: - "example.com:TRAEFIK_IP"
- 方案二:使用内部服务名访问Keycloak
修改appsettings.json,直接通过容器名访问Keycloak内部服务:
"OpenId": { "Authority": "http://keycloak:8088/realms/Investigacion", "MetaAddress": "http://keycloak:8088/realms/Investigacion/.well-known/openid-configuration", "Metadata": false }
3. 修正Traefik ACME协议版本
Traefik v3.1使用ACME v2协议,当前存储路径为v1格式会导致证书异常:
reverse-proxy: command: - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme-v2.json"
内容的提问来源于stack exchange,提问作者Martin Solari Vargas
相关产品推荐
相关产品推荐

