IdentityServer 部署踩坑記

IdentityServer 部署踩坑記

Intro

周末終於部署了 IdentityServer 以及 IdentityServerAdmin 項目,踩了幾個坑,在此記錄分享一下。

部署架構

項目是基於 IdentityServerAdmin 項目修改的,感謝作者的開源付出,有需要 IdentityServer 管理需求的可以關注一下,覺得好用的可以給個 star 支援一下 https://github.com/skoruba/IdentityServer4.Admin

實際部署的有兩個服務,一個是 IdentityServer 項目(https://id.weihanli.xyz),一個是 IdentityAdmin 項目(<https://id-admin.weihanli.xyz>)。

兩個服務都是部署在一台伺服器上,這一台伺服器上部署一個單節點的 kubernetes,兩個服務都是部署在 k8s 上並通過 NortPort 的方式對外提供服務,外面有一層 nginx 做了請求轉發同時提供對外 https 的支援。

image-20200407151639076

最初的 nginx 配置如下

server {        listen 443;        ssl_certificate            /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.cer;        ssl_certificate_key      /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.key;        server_name id.weihanli.xyz;          location / {           proxy_pass http://172.17.0.2:31210;           proxy_set_header X-Real-IP $remote_addr;           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       }  }  server {        listen 443;        ssl_certificate            /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.cer;        ssl_certificate_key      /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.key;        server_name id-admin.weihanli.xyz;          location / {           proxy_pass http://172.17.0.2:31211;           proxy_set_header X-Real-IP $remote_addr;           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       }  }  

IdentityServer重定向到內網地址

部署起來之後,IdentityServer 可以訪問,但是 IdentityAdmin 訪問的時候會重定向到 IdentityServer 去登錄,在發生重定向的時候會重定向到內網地址,重定向到了 172.17.0.1:31210 這個內網地址,這個地址是一個內網地址,公網肯定是沒有辦法訪問的,在網上 Google 了半天發現有個類似的問題 網路迴流(NAT Loopback/ Hairpin NAT),大概就是在同一網段的內網中的兩個服務通訊的時候通過公網域名沒有辦法訪問,會轉換成內網IP訪問,所以發生重定向的時候會出現原本是域名重定向但是卻變成了內網IP(不確定我的這種情況是不是屬於網路迴流的情況,有網路大佬的話可以幫忙分析一下,萬分感謝)

因為使用了 nginx 並且轉發後的內網 IP 地址是 nginx 轉發到的請求地址,所以又 Google 了 nginx proxy redirect 關鍵詞,最後找到一個解決方案 https://unix.stackexchange.com/questions/290141/nginx-reverse-proxy-redirection

最後生效的 nginx 完整配置如下:

server {        listen 443 http2;        ssl_certificate            /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.cer;        ssl_certificate_key      /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.key;          server_name id-admin.weihanli.xyz;          location / {           proxy_pass http://172.17.0.2:31211;           proxy_redirect http://172.17.0.2:31210/ https://id.weihanli.xyz/;           proxy_set_header Host $host;           proxy_set_header Referer $http_referer;           proxy_set_header X-Real-IP $remote_addr;           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       }  }  

增加了上面的配置之後再發生重定向的時候地址就是正確的了,不再是一個內網IP 了

Invalid Token

Identity Server 重定向的問題解決之後,馬上就出現了新的問題。。。

首先在 Identity Server 登錄成功之後返回到 IdentityAdmin 的時候會報錯,查看日誌可以看到是 token 不合法的問題,起初是 issuer 不對的問題,我想可能是 issuer 可能 http/https 不一致的問題,於是增加了一個配置,直接在註冊 IdentityServer 的時候使用指定的 issuer ,想著這樣就不會有 http/https 的問題,於是重新部署,重新嘗試之後,token 還是有問題,日誌顯示是token 簽名驗證錯誤,這時不經意之間看了一眼 IdentityServer 的 發現文檔,打開之後發現裡面的各種 endpoint 都是 http 的,後來發現 IdentityServer 有一個 PublicOrigin 的配置,把這個配置配置成 https://id.weihanli.xyz 之後就沒有 invalid token 之類的錯誤了,再看發現文檔的時候,endpoint 也是基於 https 的了。

Identity-Admin 502

IdentityServer 登錄成功之後重定向到 IdentityAdmin 的時候 502,但是服務是存在的 在日誌里只找到下面這樣的錯誤日誌

Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_grant' , error_description: 'error_description is null', error_uri: 'error_uri is null'  

在網上 Google 之後找到了這個issue: https://github.com/IdentityServer/IdentityServer4/issues/1670,嘗試了下面這個解決方案解決了,是因為重定向的時候請求資訊太大了

nginx 中 IdentityAdmin 項目增加配置:

proxy_buffer_size          128k;    proxy_buffers              4 256k;    proxy_busy_buffers_size    256k;  

修改之後,執行 sudo nginx -s reload 重新載入配置之後就正常了

More

最後現在在用的有效的完整的 nginx 配置如下:

server {        listen 443 http2;        ssl_certificate            /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.cer;        ssl_certificate_key      /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.key;          server_name id.weihanli.xyz;          location / {           proxy_pass http://172.17.0.2:31210;           proxy_redirect off;             proxy_set_header Host $host;           proxy_set_header Referer $http_referer;           proxy_set_header X-Real-IP $remote_addr;           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       }  }    server {        listen 443 http2;        ssl_certificate            /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.cer;        ssl_certificate_key      /home/pipeline/.acme.sh/*.weihanli.xyz/*.weihanli.xyz.key;          server_name id-admin.weihanli.xyz;          location / {           proxy_pass http://172.17.0.2:31211;           proxy_redirect http://172.17.0.2:31210/ https://id.weihanli.xyz/;           proxy_buffer_size          128k;           proxy_buffers              4 256k;           proxy_busy_buffers_size    256k;           proxy_set_header Host $host;           proxy_set_header Referer $http_referer;           proxy_set_header X-Real-IP $remote_addr;           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;       }  }  

Reference