戰(zhàn):從keystore到Tomcat配置全流程)
做GIS開發(fā)或者運(yùn)維的朋友應(yīng)該都跟GeoServer打過(guò)交道它本身是個(gè)開源的矢量柵格地圖服務(wù)器發(fā)布WMS、WFS、WMTS都很方便。但真正把它推上生產(chǎn)環(huán)境、掛在公網(wǎng)下面的時(shí)候第一個(gè)繞不開的坎往往是地址欄那個(gè)紅色感嘆號(hào)也就是HTTPS/SSL證書的問(wèn)題。很多項(xiàng)目都是在內(nèi)網(wǎng)跑得風(fēng)生水起一到外網(wǎng)聯(lián)調(diào)就因?yàn)椤霸撜军c(diǎn)不安全”被卡住輕則被客戶截圖投訴重則地圖服務(wù)被瀏覽器攔截甚至被封裝成客戶端后直接報(bào)SSL證書錯(cuò)誤。這篇文章把我自己在GeoServer上部署SSL證書的完整過(guò)程寫出來(lái)包括證書方案怎么選、Java環(huán)境里的keystore怎么處理、Tomcat容器怎么配置以及一堆實(shí)際踩過(guò)的SSL報(bào)錯(cuò)和排查方法。無(wú)論你是剛接手GIS服務(wù)器的運(yùn)維新人還是做WebGIS開發(fā)的工程師只要GeoServer用的是Tomcat或者內(nèi)嵌Jetty部署都可以直接參考這里面的步驟用最小代價(jià)把HTTPS通道跑通。1. GeoServer加SSL的整體思路先把容器和架構(gòu)想清楚1.1 GeoServer不只是個(gè)Java程序SSL這件事要分兩層看GeoServer本質(zhì)上是一個(gè)Java Web應(yīng)用通常部署在Tomcat、Jetty這類Servlet容器里所以“給GeoServer部署SSL證書”這句話背后其實(shí)有兩層意思。第一層是傳輸層也就是讓容器把TLS/SSL這塊啟用起來(lái)把443或8443端口變成HTTPS端口保證瀏覽器和服務(wù)器之間的數(shù)據(jù)是加密的。第二層是應(yīng)用層GeoServer在拼WMS/WFS請(qǐng)求地址時(shí)會(huì)自動(dòng)讀取請(qǐng)求協(xié)議來(lái)決定返回的URL是http還是https。如果你只解決了第一層沒有處理第二層就會(huì)遇到一個(gè)很經(jīng)典的現(xiàn)象瀏覽器地址欄鎖已經(jīng)出來(lái)了但地圖服務(wù)返回的GetMap地址卻還是http導(dǎo)致瀏覽器把瓦片當(dāng)作混合內(nèi)容攔截掉地圖一片空白。這兩層必須同時(shí)處理好才算真的配完。另外GeoServer的部署架構(gòu)決定了做SSL的方式。常見的部署架構(gòu)有這么幾種單機(jī)直連GeoServer直接跑在一臺(tái)機(jī)器上用戶直接通過(guò)IP或域名加端口訪問(wèn)。Tomcat反代GeoServer前面再加一層Nginx或者Apache由前面的服務(wù)來(lái)處理HTTPSGeoServer只監(jiān)聽內(nèi)網(wǎng)HTTP端口。云負(fù)載均衡云廠商的LB掛證書后端GeoServer還是HTTP。容器化部署Geoserver跑在Docker里前面可能是網(wǎng)關(guān)也可能是端口映射直連。在動(dòng)手配SSL之前先想清楚你這套GeoServer是哪種架構(gòu)因?yàn)椴煌軜?gòu)下“部署證書”的位置完全不一樣。我第一次接手的時(shí)候沒想這層直接往GeoServer上塞證書結(jié)果發(fā)現(xiàn)前面其實(shí)還有一層Nginx來(lái)回折騰了好幾天。1.2 三種常見SSL接入方式我為什么選了Tomcat直配我梳理一下主流的三種接入方式放在一起對(duì)比更清楚。接入方式優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景Nginx/網(wǎng)關(guān)層終止SSL靈活性高、證書續(xù)期方便、可以統(tǒng)一管理入口需要多維護(hù)一層代理GeoServer內(nèi)部仍要處理代理頭有統(tǒng)一入口網(wǎng)關(guān)的團(tuán)隊(duì)Tomcat/Jetty直接配置SSL架構(gòu)簡(jiǎn)單無(wú)中間層GeoServer的原生鏈接協(xié)議最不容易出錯(cuò)證書配置在Java keystore里續(xù)期和更新需要操作服務(wù)器單機(jī)部署、內(nèi)網(wǎng)環(huán)境、不想引入額外組件云端LB掛證書證書管理最省心自動(dòng)續(xù)期可能要額外收費(fèi)GeoServer仍需要處理轉(zhuǎn)發(fā)頭云上部署、多實(shí)例橫向擴(kuò)展如果是單機(jī)部署我最推薦直接在Tomcat層配SSL。原因很簡(jiǎn)單少一層反向代理就少一層排查點(diǎn)GeoServer從容器那邊拿到的就是HTTPS請(qǐng)求應(yīng)用層判斷協(xié)議不會(huì)抽風(fēng)。如果你公司要求必須走Nginx統(tǒng)一入口那GeoServer這邊主要任務(wù)是設(shè)置好PROXY_BASE_URL和代理頭處理這部分我在第三節(jié)也會(huì)提一下。1.3 端口和域名規(guī)劃決定了后續(xù)證書申請(qǐng)的難度SSL證書和域名是綁定的所以在申請(qǐng)證書前你要先確定GeoServer對(duì)外提供服務(wù)的域名和端口。這里有個(gè)很容易被忽略的點(diǎn)GeoServer的Java Web應(yīng)用本身不關(guān)心域名證書才關(guān)心域名。如果你在server.xml里配置HTTPS端口時(shí)證書CN和訪問(wèn)URL不一致瀏覽器就會(huì)彈安全警告。規(guī)劃的時(shí)候我建議預(yù)留一個(gè)正式域名比如gis.example.com指向GeoServer所在機(jī)器。如果還沒上域名也可以用IP地址申請(qǐng)IP證書或者臨時(shí)用自簽名證書做聯(lián)調(diào)但生產(chǎn)環(huán)境建議還是用正規(guī)證書。免費(fèi)證書和商業(yè)證書都行GeoServer不關(guān)心證書是哪家簽發(fā)的只要證書鏈完整、私鑰能對(duì)上Java的keytool都能導(dǎo)入。2. 證書獲取與格式轉(zhuǎn)換Java keystore是繞不開的環(huán)節(jié)2.1 證書文件格式掃盲PEM、CRT、KEY、PFX到底誰(shuí)是誰(shuí)用GeoServer配SSL最容易被繞暈的就是文件格式。瀏覽器和Nginx用的證書和Java里要用的證書不是同一個(gè)形態(tài)。這里有個(gè)非常關(guān)鍵的概念Java程序一般不直接讀取單獨(dú)的.crt和.key文件而是讀取一個(gè)叫做keystore的密鑰庫(kù)文件后綴通常是.jks、.p12或者.pfx里面同時(shí)包含了證書和私鑰。這一點(diǎn)和Python、Go、Nginx的理解方式不太一樣很多從其他后端轉(zhuǎn)過(guò)來(lái)的朋友第一次都會(huì)在這里卡住。先說(shuō)常見的原始證書文件.crt / .cer / .pem這三類本質(zhì)上都是證書本體內(nèi)容是一段Base64編碼的文本包含公鑰和證書持有者信息。.pem是通用格式.crt多用于Linux系統(tǒng)。.key私鑰文件一定要妥善保管泄露等于別人能用你的域名做HTTPS服務(wù)。.pfx / .p12 / .pkcs12把證書和私鑰打包成一個(gè)文件的格式可以直接被Java keytool識(shí)別導(dǎo)入。.jksJava特有的KeyStore格式也是老項(xiàng)目里常見的Tomcat證書存儲(chǔ)格式新項(xiàng)目我更建議直接用PKCS12。用一張表格整理清楚文件后綴內(nèi)容Java是否直接用.crt/.cer/.pem證書本體公鑰申請(qǐng)者信息不能直接用.key私鑰不能直接用.pfx/.p12/.pkcs12證書私鑰打包可以推薦.jksJava專用密鑰庫(kù)可以傳統(tǒng)方式2.2 用keytool生成自簽名證書先跑通本地HTTPS正式證書下來(lái)之前我習(xí)慣先用自簽名證書把流程整個(gè)跑一遍確認(rèn)Tomcat配置沒問(wèn)題。這樣做的好處是申請(qǐng)正式證書的流程可能有幾天但本地驗(yàn)證鏈路可以先打通而且后續(xù)導(dǎo)入正式證書時(shí)配置幾乎可以復(fù)用。keytool是JDK自帶的工具在Java安裝目錄的bin目錄下。生成自簽名證書的命令如下keytool -genkeypair -alias geoserver -keyalg RSA -keysize 2048 \ -validity 3650 -keystore geoserver.jks -storetype PKCS12 \ -dname CNgis.example.com, OUGIS, OExample, LShanghai, STShanghai, CCN \ -storepass changeit -keypass changeit解釋一下關(guān)鍵參數(shù)alias證書條目別名后續(xù)在Tomcat配置里要用到建議起個(gè)有意義的名稱比如geoserver。keyalg RSA與keysize 2048加密算法和密鑰長(zhǎng)度。2048是目前主流最低標(biāo)準(zhǔn)4096更安全但握手性能會(huì)稍差一點(diǎn)GeoServer這種服務(wù)用2048夠了。validity有效期天數(shù)自簽名測(cè)試可以寫3650天正式證書一般只有90天或1年。storetype PKCS12新版本keytool默認(rèn)就是PKCS12強(qiáng)烈建議用它而不是老式的JKS。PKCS12是跨語(yǔ)言標(biāo)準(zhǔn)格式以后如果想把證書遷移到Nginx或者其他Java應(yīng)用可以直接用openssl處理。自簽名證書生成后訪問(wèn)時(shí)會(huì)遇到“不安全”的警告這是正常的。在客戶端機(jī)器上把這個(gè)keystore里的證書導(dǎo)出來(lái)安裝到系統(tǒng)受信任的根證書頒發(fā)機(jī)構(gòu)里警告就會(huì)消失。測(cè)試時(shí)也可以直接用-c參數(shù)忽略證書校驗(yàn)。2.3 正式證書導(dǎo)入PKCS12轉(zhuǎn)換完成證書鏈合并從證書廠商下載的證書通常是兩個(gè)文件一個(gè)是域名證書比如gis_example_com.crt一個(gè)是中間CA證書比如ca.crt有時(shí)候還會(huì)有root.crt。這里我強(qiáng)調(diào)一個(gè)重點(diǎn)Java的keystore導(dǎo)入證書時(shí)如果只導(dǎo)入域名證書不導(dǎo)入中間CA證書會(huì)導(dǎo)致“unable to get local issuer certificate”或者“證書鏈不完整”的報(bào)錯(cuò)。這不是玄學(xué)是服務(wù)器和客戶端都缺少中間CA導(dǎo)致無(wú)法信任鏈驗(yàn)證。所以拿到正式證書后我建議先把證書鏈合并成一個(gè)PEM文件再轉(zhuǎn)成PKCS12格式。假設(shè)你的私鑰是server.key證書是server.crt中間CA是ca.crt合并命令如下cat server.crt ca.crt fullchain.pem openssl pkcs12 -export -in fullchain.pem -inkey server.key \ -name geoserver -out geoserver.p12 \ -passout pass:changeit如果你手里直接拿到的是.pfx格式那更省事直接用keytool導(dǎo)入keytool -importkeystore \ -srckeystore geoserver.pfx -srcstoretype PKCS12 -srcstorepass 證書密碼 \ -destkeystore geoserver.jks -deststoretype PKCS12 -deststorepass changeit \ -srcalias 1 -destalias geoserver這里有兩個(gè)容易忽略的小細(xì)節(jié)。第一個(gè)是srcaliaspfx文件里的別名有時(shí)候是“1”或者“mykey”你可以先執(zhí)行keytool -list -keystore geoserver.pfx -storetype PKCS12查看一下。第二個(gè)是deststoretype我用的是PKCS12而不是老項(xiàng)目里常見的JKS原因前面說(shuō)了跨平臺(tái)兼容性更好Tomcat 8.5以上版本完全支持。2.4 證書鏈完整性的自檢方法證書導(dǎo)完之后強(qiáng)烈建議先驗(yàn)證一遍而不是直接重啟服務(wù)。驗(yàn)證證書鏈最直觀的命令是openssl的s_clientopenssl s_client -connect gis.example.com:8443 -showcerts如果證書鏈正常會(huì)返回一個(gè)類似“Verify return code: 0 (ok)”的提示。如果返回20、21、22這類code基本就是證書鏈沒傳完整。本地在沒有占用443端口的情況下也可以先用keytool查看一下keystore里的內(nèi)容keytool -list -v -keystore geoserver.jks -storetype PKCS12 -storepass changeit能看到alias對(duì)應(yīng)的條目并且證書鏈顯示長(zhǎng)度為2服務(wù)器證書中間CA或更長(zhǎng)就說(shuō)明導(dǎo)入是完整的。如果只有一條證書信息說(shuō)明中間CA丟了要重新合并再導(dǎo)入一次。3. GeoServer上的SSL證書配置實(shí)操Tomcat完整流程3.1 準(zhǔn)備階段確認(rèn)Java環(huán)境與GeoServer部署方式動(dòng)手之前先搞清楚兩件事GeoServer是獨(dú)立安裝版還是WAR包部署到Tomcat的版本因?yàn)榕渲梦募穆窂接胁町?。如果是GeoServer War包部署到獨(dú)立Tomcat配置的是Tomcat自己的conf/server.xml如果是GeoServer官方網(wǎng)站下載的二進(jìn)制發(fā)布版它內(nèi)嵌了Jetty那么配置文件在GeoServer安裝目錄的etc目錄下。這兩者的配置方式和重啟方式不太一樣我身邊有同事就是混淆了這兩個(gè)路徑改了半天發(fā)現(xiàn)不生效。這里我以最常見的“GeoServer WAR包 Tomcat”為例來(lái)寫內(nèi)嵌Jetty版本的處理方法在后面單獨(dú)說(shuō)明。另外確認(rèn)一下tomcat的版本。Tomcat 8.5之前和8.5之后server.xml里配置SSL的寫法差別很大。舊版本喜歡在Connector標(biāo)簽上一股腦塞keystoreFile、keystorePass這些屬性新版本推薦用SSLHostConfig子標(biāo)簽。兩種寫法在Tomcat 8.5/9/10里都可以運(yùn)行但我建議新配置直接用新的寫法避免升級(jí)Tomcat時(shí)出問(wèn)題。3.2 修改server.xml添加HTTPS Connector打開Tomcat的conf/server.xml文件找到現(xiàn)有的Connector配置區(qū)域默認(rèn)情況下注釋掉了一個(gè)8443端口的連接器。我們需要在這個(gè)區(qū)域新增一個(gè)HTTPS連接器配置。Connector port8443 protocolorg.apache.coyote.http11.Http11NioProtocol maxThreads300 schemehttps securetrue SSLEnabledtrue SSLHostConfig Certificate certificateKeystoreFile/data/ssl/geoserver.jks certificateKeystoreTypePKCS12 certificateKeystorePasswordchangeit certificateKeyAliasgeoserver / /SSLHostConfig /Connector這里有幾個(gè)參數(shù)必須按實(shí)際情況改certificateKeystoreFile指向你存放keystore的絕對(duì)路徑建議不要放在Tomcat的webapps目錄下避免下次部署時(shí)被誤刪certificateKeystorePassword要和生成keystore時(shí)設(shè)置的storepass一致certificateKeyAlias要和keystore里的alias一致。證書路徑我習(xí)慣放在一個(gè)統(tǒng)一的目錄比如/data/ssl或者/etc/ssl/geoserver方便以后續(xù)期替換。有人會(huì)問(wèn)端口為什么是8443而不是標(biāo)準(zhǔn)的443。原因很簡(jiǎn)單GeoServer本身一般不會(huì)占用80和443但在Linux系統(tǒng)上低于1024的端口啟動(dòng)時(shí)需要有root權(quán)限而Tomcat通常不以root運(yùn)行。所以我一般先用8443做驗(yàn)證等確認(rèn)沒問(wèn)題了再用iptables或者Nginx把443轉(zhuǎn)發(fā)到8443或者直接改用Nginx處理443。如果是云服務(wù)器記得在安全組里放行對(duì)應(yīng)端口。3.3 重啟Tomcat并驗(yàn)證HTTPS端口配置完成后重啟Tomcat然后確認(rèn)端口監(jiān)聽狀態(tài)netstat -tlnp | grep 8443看到LISTEN狀態(tài)后用curl驗(yàn)證HTTPS是否正常curl -vk https://127.0.0.1:8443/geoserver如果出現(xiàn)HTTP/1.1 200狀態(tài)碼說(shuō)明HTTPS連接器已經(jīng)生效。curl命令里的-v參數(shù)會(huì)把證書鏈信息打出來(lái)你可以順便確認(rèn)下發(fā)證書的域名和CN是否匹配。如果出現(xiàn)證書錯(cuò)誤別急著改配置先看錯(cuò)誤發(fā)生在哪一環(huán)節(jié)。自簽名證書的話curl會(huì)報(bào)self-signed certificate錯(cuò)誤加-k參數(shù)只是跳過(guò)校驗(yàn)不代表配置沒問(wèn)題。3.4 讓GeoServer正確識(shí)別HTTPS請(qǐng)求PROXY_BASE_URL設(shè)置這一步非常關(guān)鍵但很多人會(huì)漏掉。GeoServer默認(rèn)情況下如果一個(gè)請(qǐng)求走的是HTTPS但是GeoServer看不到代理頭或者沒有明確的base URL配置它生成的WMS/WFS服務(wù)URL可能還是http。結(jié)果就是你的地圖服務(wù)用HTTPS打開了但里面的資源地址是http瀏覽器直接攔截。解決辦法是在GeoServer管理后臺(tái)設(shè)置代理地址。打開GeoServer的Web管理界面進(jìn)入“全局設(shè)置”(Global Settings)找到“代理基準(zhǔn)URL”(Proxy Base URL)一欄填上對(duì)外服務(wù)的地址比如https://gis.example.com/geoserver然后保存并且把所有圖層發(fā)布緩存清一下。這個(gè)配置的作用等于告訴GeoServer以后生成的所有服務(wù)鏈接都基于這個(gè)地址來(lái)拼。如果你用了Nginx反代還要再加一行設(shè)置讓Tomcat識(shí)別X-Forwarded-Proto頭這一步在后面的常見問(wèn)題部分詳細(xì)說(shuō)。3.5 內(nèi)嵌Jetty版本怎么配GeoServer發(fā)布版的SSL配置如果你的GeoServer是官網(wǎng)下載的獨(dú)立安裝版它內(nèi)嵌了Jetty不能直接復(fù)用Tomcat的server.xml方案。Jetty版本的配置方式有兩種。第一種是修改GeoServer安裝目錄下的start.ini在末尾追加SSL相關(guān)配置--modulehttps jetty.ssl.port8443 jetty.ssl.keystore/data/ssl/geoserver.jks jetty.ssl.keystorePasswordchangeit jetty.ssl.keyManagerPasswordchangeit jetty.ssl.trustStore/data/ssl/geoserver.jks jetty.ssl.trustStorePasswordchangeit第二種是在GeoServer的etc目錄下直接集成jetty-ssl.xml和jetty-https.xml。這種配置相對(duì)繁瑣我一般只用start.ini方式。改完要重啟GeoServer服務(wù)然后同樣用curl驗(yàn)證一下8443端口。其實(shí)不管Tomcat還是Jetty核心概念沒變給容器指定一個(gè)包含證書和私鑰的密鑰庫(kù)指定密碼然后聲明一個(gè)HTTPS監(jiān)聽端口。容器之間的語(yǔ)法差異只是換了一種寫配置文件的方式。4. 遇到SSL報(bào)錯(cuò)怎么辦常見問(wèn)題排查與避坑實(shí)錄4.1 高頻報(bào)錯(cuò)速查表我把平時(shí)在GeoServer部署SSL過(guò)程中最常見的報(bào)錯(cuò)或者現(xiàn)象整理成了一個(gè)速查表遇到問(wèn)題可以直接照著排查。報(bào)錯(cuò)/現(xiàn)象可能原因處理辦法SSL證書錯(cuò)誤無(wú)法建立安全連接證書鏈不完整把中間CA證書合并進(jìn)certificateChainFile重新導(dǎo)入keystoreno required ssl certificate was sent服務(wù)端配置了強(qiáng)制客戶端證書校驗(yàn)把clientAuth設(shè)為falsecurl: unable to get local issuer certificate本地缺少中間CA合并證書鏈或者本機(jī)導(dǎo)入根證書SSL connection required, but not provided by server客戶端請(qǐng)求的端口不是HTTPS檢查端口和連接器協(xié)議配置頁(yè)面能打開但報(bào)混合內(nèi)容錯(cuò)誤GeoServer生成的URL還是http設(shè)置代理基準(zhǔn)URL和X-Forwarded-Proto頭證書顯示不受信任自簽名證書未安裝到信任庫(kù)安裝根證書到系統(tǒng)信任區(qū)域keytool提示alias不存在導(dǎo)入時(shí)的別名與配置不一致用keytool -list查看實(shí)際別名HTTPS端口無(wú)法訪問(wèn)防火墻/安全組未放行端口檢查iptables和云安全組策略4.2 經(jīng)典問(wèn)題一證書鏈不完整導(dǎo)致的手握證書也報(bào)錯(cuò)這個(gè)問(wèn)題是我在實(shí)際工作中遇到最多的一個(gè)。用戶明明已經(jīng)把證書導(dǎo)入keystore了訪問(wèn)時(shí)瀏覽器還是提示“證書鏈不完整”或者“服務(wù)器證書不受信任”。原因很簡(jiǎn)單證書廠商發(fā)的證書包里有server.crt、root.crt、ca.crt三個(gè)文件有人只把server.crt導(dǎo)進(jìn)了keystore沒有把中間CA一起打包進(jìn)去。解決辦法是把證書鏈合并后再轉(zhuǎn)成PKCS12我在前面2.3已經(jīng)寫過(guò)完整命令這里再?gòu)?qiáng)調(diào)一遍合并的順序域名證書在前中間CA在后根證書可以不放進(jìn)服務(wù)器但如果你的根證書不是公開信任的最好也一并放進(jìn)去。合并后的文件用openssl驗(yàn)證一下openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout從輸出里看到證書鏈的數(shù)量如果只有一條說(shuō)明合并沒成功。4.3 經(jīng)典問(wèn)題二GeoServer的WMS鏈接還是http地圖服務(wù)白屏這個(gè)現(xiàn)象在切換HTTPS后特別常見。GeoServer管理界面正常但前端地圖加載時(shí)報(bào)“Mixed Content: The page at ... was loaded over HTTPS, but requested an insecure resource http://.../geoserver/...”。問(wèn)題根源是GeoServer不知道訪問(wèn)者的協(xié)議是HTTPS。如果你是Tomcat直連HTTPS不經(jīng)過(guò)反代那只要在管理后臺(tái)把“代理基準(zhǔn)URL”設(shè)置成https開頭就行。如果你前面加了Nginx還需要讓Tomcat能夠識(shí)別轉(zhuǎn)發(fā)過(guò)來(lái)的協(xié)議頭。Tomcat 8.5以上有一個(gè)閥門配置在server.xml的Host標(biāo)簽里加上Valve classNameorg.apache.catalina.valves.RemoteIpValve protocolHeaderx-forwarded-proto internalProxies127.0.0.1|::1 /然后Nginx那邊要加上proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host;這樣GeoServer拿到的就是https協(xié)議生成的WMS鏈接也會(huì)是https開頭。這個(gè)問(wèn)題排查起來(lái)很隱蔽因?yàn)楸砻嫔蟂SL是配好的實(shí)際應(yīng)用層沒有感知到安全協(xié)議的切換。4.4 經(jīng)典問(wèn)題三客戶端請(qǐng)求報(bào)“no required ssl certificate was sent”這個(gè)報(bào)錯(cuò)很多做Java客戶端或者腳本調(diào)用的朋友會(huì)遇到。它說(shuō)的是服務(wù)端要求客戶端發(fā)送SSL證書但客戶端沒有發(fā)。一般有兩個(gè)原因一是GeoServer的Tomcat配置里把clientAuth設(shè)成了true或者want導(dǎo)致服務(wù)端強(qiáng)制客戶端提供證書二是你用了某種客戶端SDK它默認(rèn)開啟雙向驗(yàn)證。排查方法很直接打開server.xml看看HTTPS連接器里是否包含clientAuth。默認(rèn)GeoServer部署是不需要客戶端證書的所以這個(gè)值應(yīng)該是false或者不設(shè)置。如果你曾經(jīng)為了某些安全測(cè)試改過(guò)記得改回來(lái)Connector ... clientAuthfalse ...如果確認(rèn)不是Tomcat端的問(wèn)題再檢查客戶端代理比如JMeter做壓力測(cè)試時(shí)的SSL配置Chrome Developer證書選擇等。GeoServer的WEB-GIS場(chǎng)景一般用不到雙向證書不開啟客戶端校驗(yàn)才是正常狀態(tài)。4.5 經(jīng)典問(wèn)題四證書續(xù)期后服務(wù)沒生效免費(fèi)證書的周期通常是90天所以續(xù)期是每個(gè)GeoServer管理員逃不掉的事。有的人續(xù)期后直接拿新fullchain.pem替換了服務(wù)器上的文件然后重啟Tomcat發(fā)現(xiàn)還是舊證書。排查下來(lái)大概率是keystore里導(dǎo)入的還是舊證書。解決辦法是把新的證書鏈重新合并重新生成keystore或者直接更新PKCS12文件。因?yàn)橥粋€(gè)密碼和alias下導(dǎo)入的新證書會(huì)覆蓋舊條目但如果你用了不同密碼或aliasTomcat里的引用就找不到新條目自然還是舊證書生效。我個(gè)人習(xí)慣每次續(xù)期后用一個(gè)固定的文件名覆蓋舊文件重啟之前先用keytool -list確認(rèn)下證書的有效期keytool -list -v -keystore geoserver.jks -storetype PKCS12 -storepass changeit | grep -A 5 Valid看到到期日期更新了再重啟Tomcat就不會(huì)出現(xiàn)替換文件后沒生效的尷尬。4.6 經(jīng)典問(wèn)題五安全掃描報(bào)告SSL/TLS協(xié)議漏洞CVE-2016-2183很多內(nèi)網(wǎng)項(xiàng)目滲透測(cè)試時(shí)會(huì)報(bào)出一個(gè)“SSL/TLS協(xié)議信息泄露漏洞(CVE-2016-2183)”這個(gè)原理掃描經(jīng)常讓運(yùn)維緊張。其實(shí)這個(gè)漏洞對(duì)應(yīng)的是弱加密套件和舊版TLS協(xié)議。解決辦法是在Tomcat的SSLHostConfig里顯式指定啟用的協(xié)議和禁用弱加密算法。SSLHostConfig protocolsTLSv1.2,TLSv1.3 ciphersTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,...這里我提醒一句不要照抄網(wǎng)上的加密套件列表要結(jié)合客戶端的兼容性來(lái)調(diào)。比如有些測(cè)繪類桌面客戶端用的老版本Java如果只保留最強(qiáng)套件反而會(huì)握手失敗。穩(wěn)妥的做法是先只限制協(xié)議為TLSv1.2以上算法保持默認(rèn)等掃描報(bào)告不再報(bào)高危了再逐步收緊。CVE-2016-2183這個(gè)報(bào)錯(cuò)多數(shù)情況下只是掃描工具探測(cè)到服務(wù)端支持了一些過(guò)時(shí)密碼套件及時(shí)升級(jí)Java版本并限制協(xié)議版本就好。5. 生產(chǎn)環(huán)境的額外建議從能訪問(wèn)到穩(wěn)定跑5.1 用Nginx做443轉(zhuǎn)發(fā)Tomcat保持8443本地監(jiān)聽如果你不想讓Tomcat直接占用443端口也不想給Tomcat提權(quán)到root最省心的方案是讓Nginx監(jiān)聽443然后反代到本地的8443或8080。這樣做的好處是Nginx的證書管理比Tomcat更靈活以后續(xù)期證書都不用動(dòng)Tomcat。配置大概是server { listen 443 ssl http2; server_name gis.example.com; ssl_certificate /etc/nginx/ssl/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/server.key; location /geoserver/ { proxy_pass http://127.0.0.1:8080/geoserver/; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }注意location末尾的斜杠proxy_pass后面是否帶/直接決定了訪問(wèn)路徑會(huì)不會(huì)被重寫。如果不帶斜杠會(huì)把/geoserver/整個(gè)路徑透?jìng)鹘o后端帶了斜杠會(huì)把/geoserver部分去掉。GeoServer必須保留/geoserver這個(gè)上下文所以這里我建議寫成proxy_pass http://127.0.0.1:8080/geoserver/;。然后別忘了在GeoServer的代理基準(zhǔn)URL里面設(shè)置https地址以及RemoteIpValve閥門。5.2 證書續(xù)期與自動(dòng)化腳本化替換keystore免費(fèi)證書最大的痛點(diǎn)就是續(xù)期。我自己的做法是寫一個(gè)簡(jiǎn)單的shell腳本證書續(xù)期后自動(dòng)把新證書轉(zhuǎn)成keystore再重啟Tomcat。因?yàn)榘⒗镌芐SL證書、Lets Encrypt這類證書服務(wù)商都有API或者客戶端可以自動(dòng)下發(fā)證書剩下的只是轉(zhuǎn)換和重啟。腳本核心邏輯是這樣的# 續(xù)期后拿到新的fullchain.pem和server.key openssl pkcs12 -export -in fullchain.pem -inkey server.key \ -name geoserver -out /data/ssl/geoserver.p12 \ -passout pass:changeit # 如果原本用的JKS可以重新導(dǎo)入 keytool -importkeystore \ -srckeystore /data/ssl/geoserver.p12 -srcstoretype PKCS12 \ -destkeystore /data/ssl/geoserver.jks -deststoretype PKCS12 \ -deststorepass changeit -srcalias 1 -destalias geoserver # 重啟服務(wù) systemctl restart tomcat這里要小心一個(gè)問(wèn)題在替換PKCS12文件前先備份舊文件一旦新證書有問(wèn)題可以快速回滾。另外systemctl restart tomcat之前檢查一下keystore文件的屬主權(quán)限Tomcat運(yùn)行用戶是否能讀取這塊路徑否則可能會(huì)出現(xiàn)配置文件沒變但服務(wù)起不來(lái)的情況。5.3 端口關(guān)停老HTTP避免兩邊都開放造成邏輯混亂很多部署事故其實(shí)不是因?yàn)镾SL沒配好而是配好之后老的HTTP端口沒有關(guān)掉。用戶訪問(wèn)時(shí)如果還通過(guò)舊地址進(jìn)來(lái)看到的頁(yè)面又是http整個(gè)HTTPS改造看起來(lái)就相當(dāng)于沒做。建議在確認(rèn)HTTPS穩(wěn)定后禁用Tomcat上對(duì)外開放的8080端口或者在防火墻層面只允許內(nèi)網(wǎng)訪問(wèn)8080對(duì)外只暴露443或8443。同時(shí)GeoServer有些第三方OSS上傳或者其他插件可能也有基于HTTP的集成地址。改造HTTPS后要全面檢查一遍所有集成方的回調(diào)地址把硬編碼的老地址一并改掉否則前端地圖能打開但上傳服務(wù)、打印服務(wù)這些插件還是在跑HTTP。5.4 驗(yàn)證清單部署完成后逐項(xiàng)確認(rèn)我每次部署完GeoServer SSL都會(huì)按下面這個(gè)清單過(guò)一遍瀏覽器用https://域名/geoserver訪問(wèn)地址欄無(wú)警告。用curl確認(rèn)證書鏈和有效期證書無(wú)過(guò)期風(fēng)險(xiǎn)。發(fā)布一個(gè)WMS圖層檢查預(yù)覽地址是否為https。前端頁(yè)面用HTTPS加載控制臺(tái)無(wú)mixed content報(bào)錯(cuò)。供桌面客戶端或腳本調(diào)用的HTTP接口改為HTTPS后能正常返回?cái)?shù)據(jù)。安全掃描工具復(fù)掃無(wú)高危SSL/TLS漏洞。這個(gè)清單看起來(lái)簡(jiǎn)單但每一項(xiàng)都可能藏著坑。尤其是第3和第4項(xiàng)只要代理基準(zhǔn)URL或者X-Forwarded-Proto沒配好就會(huì)出現(xiàn)“單點(diǎn)能訪問(wèn)、整體用不了”的情況。我在實(shí)際項(xiàng)目里最深的體會(huì)是GeoServer部署SSL本身不難難點(diǎn)在于把整個(gè)鏈條上的每個(gè)環(huán)節(jié)都搞明白。證書鏈只是第一步Java keystore是第二個(gè)坑容器配置是第三個(gè)坑應(yīng)用層識(shí)別HTTPS是第四個(gè)坑。這四步只要走通一次后面再遇到其他Java應(yīng)用需要配SSL基本都是同一個(gè)套路。尤其建議新手把PKCS12格式和keytool命令練熟這個(gè)工具會(huì)在后續(xù)所有Java相關(guān)的SSL配置里反復(fù)用到。最后再分享一個(gè)小技巧每次改完server.xml或keystore先把舊配置完整備份一份再動(dòng)手。我遇到過(guò)不少次因?yàn)榕渲梦募锒嘁粋€(gè)空格、路徑寫錯(cuò)一個(gè)字母導(dǎo)致服務(wù)起不來(lái)的情況有備份在手回滾起來(lái)會(huì)從容得多。