ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GeoServer部署SSL证书实战:从keystore到Tomcat配置全流程

GeoServer部署SSL证书实战:从keystore到Tomcat配置全流程 做GIS开发或者运维的朋友应该都跟GeoServer打过交道它本身是个开源的矢量栅格地图服务器发布WMS、WFS、WMTS都很方便。但真正把它推上生产环境、挂在公网下面的时候第一个绕不开的坎往往是地址栏那个红色感叹号也就是HTTPS/SSL证书的问题。很多项目都是在内网跑得风生水起一到外网联调就因为“该站点不安全”被卡住轻则被客户截图投诉重则地图服务被浏览器拦截甚至被封装成客户端后直接报SSL证书错误。这篇文章把我自己在GeoServer上部署SSL证书的完整过程写出来包括证书方案怎么选、Java环境里的keystore怎么处理、Tomcat容器怎么配置以及一堆实际踩过的SSL报错和排查方法。无论你是刚接手GIS服务器的运维新人还是做WebGIS开发的工程师只要GeoServer用的是Tomcat或者内嵌Jetty部署都可以直接参考这里面的步骤用最小代价把HTTPS通道跑通。1. GeoServer加SSL的整体思路先把容器和架构想清楚1.1 GeoServer不只是个Java程序SSL这件事要分两层看GeoServer本质上是一个Java Web应用通常部署在Tomcat、Jetty这类Servlet容器里所以“给GeoServer部署SSL证书”这句话背后其实有两层意思。第一层是传输层也就是让容器把TLS/SSL这块启用起来把443或8443端口变成HTTPS端口保证浏览器和服务器之间的数据是加密的。第二层是应用层GeoServer在拼WMS/WFS请求地址时会自动读取请求协议来决定返回的URL是http还是https。如果你只解决了第一层没有处理第二层就会遇到一个很经典的现象浏览器地址栏锁已经出来了但地图服务返回的GetMap地址却还是http导致浏览器把瓦片当作混合内容拦截掉地图一片空白。这两层必须同时处理好才算真的配完。另外GeoServer的部署架构决定了做SSL的方式。常见的部署架构有这么几种单机直连GeoServer直接跑在一台机器上用户直接通过IP或域名加端口访问。Tomcat反代GeoServer前面再加一层Nginx或者Apache由前面的服务来处理HTTPSGeoServer只监听内网HTTP端口。云负载均衡云厂商的LB挂证书后端GeoServer还是HTTP。容器化部署Geoserver跑在Docker里前面可能是网关也可能是端口映射直连。在动手配SSL之前先想清楚你这套GeoServer是哪种架构因为不同架构下“部署证书”的位置完全不一样。我第一次接手的时候没想这层直接往GeoServer上塞证书结果发现前面其实还有一层Nginx来回折腾了好几天。1.2 三种常见SSL接入方式我为什么选了Tomcat直配我梳理一下主流的三种接入方式放在一起对比更清楚。接入方式优点缺点适用场景Nginx/网关层终止SSL灵活性高、证书续期方便、可以统一管理入口需要多维护一层代理GeoServer内部仍要处理代理头有统一入口网关的团队Tomcat/Jetty直接配置SSL架构简单无中间层GeoServer的原生链接协议最不容易出错证书配置在Java keystore里续期和更新需要操作服务器单机部署、内网环境、不想引入额外组件云端LB挂证书证书管理最省心自动续期可能要额外收费GeoServer仍需要处理转发头云上部署、多实例横向扩展如果是单机部署我最推荐直接在Tomcat层配SSL。原因很简单少一层反向代理就少一层排查点GeoServer从容器那边拿到的就是HTTPS请求应用层判断协议不会抽风。如果你公司要求必须走Nginx统一入口那GeoServer这边主要任务是设置好PROXY_BASE_URL和代理头处理这部分我在第三节也会提一下。1.3 端口和域名规划决定了后续证书申请的难度SSL证书和域名是绑定的所以在申请证书前你要先确定GeoServer对外提供服务的域名和端口。这里有个很容易被忽略的点GeoServer的Java Web应用本身不关心域名证书才关心域名。如果你在server.xml里配置HTTPS端口时证书CN和访问URL不一致浏览器就会弹安全警告。规划的时候我建议预留一个正式域名比如gis.example.com指向GeoServer所在机器。如果还没上域名也可以用IP地址申请IP证书或者临时用自签名证书做联调但生产环境建议还是用正规证书。免费证书和商业证书都行GeoServer不关心证书是哪家签发的只要证书链完整、私钥能对上Java的keytool都能导入。2. 证书获取与格式转换Java keystore是绕不开的环节2.1 证书文件格式扫盲PEM、CRT、KEY、PFX到底谁是谁用GeoServer配SSL最容易被绕晕的就是文件格式。浏览器和Nginx用的证书和Java里要用的证书不是同一个形态。这里有个非常关键的概念Java程序一般不直接读取单独的.crt和.key文件而是读取一个叫做keystore的密钥库文件后缀通常是.jks、.p12或者.pfx里面同时包含了证书和私钥。这一点和Python、Go、Nginx的理解方式不太一样很多从其他后端转过来的朋友第一次都会在这里卡住。先说常见的原始证书文件.crt / .cer / .pem这三类本质上都是证书本体内容是一段Base64编码的文本包含公钥和证书持有者信息。.pem是通用格式.crt多用于Linux系统。.key私钥文件一定要妥善保管泄露等于别人能用你的域名做HTTPS服务。.pfx / .p12 / .pkcs12把证书和私钥打包成一个文件的格式可以直接被Java keytool识别导入。.jksJava特有的KeyStore格式也是老项目里常见的Tomcat证书存储格式新项目我更建议直接用PKCS12。用一张表格整理清楚文件后缀内容Java是否直接用.crt/.cer/.pem证书本体公钥申请者信息不能直接用.key私钥不能直接用.pfx/.p12/.pkcs12证书私钥打包可以推荐.jksJava专用密钥库可以传统方式2.2 用keytool生成自签名证书先跑通本地HTTPS正式证书下来之前我习惯先用自签名证书把流程整个跑一遍确认Tomcat配置没问题。这样做的好处是申请正式证书的流程可能有几天但本地验证链路可以先打通而且后续导入正式证书时配置几乎可以复用。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解释一下关键参数alias证书条目别名后续在Tomcat配置里要用到建议起个有意义的名称比如geoserver。keyalg RSA与keysize 2048加密算法和密钥长度。2048是目前主流最低标准4096更安全但握手性能会稍差一点GeoServer这种服务用2048够了。validity有效期天数自签名测试可以写3650天正式证书一般只有90天或1年。storetype PKCS12新版本keytool默认就是PKCS12强烈建议用它而不是老式的JKS。PKCS12是跨语言标准格式以后如果想把证书迁移到Nginx或者其他Java应用可以直接用openssl处理。自签名证书生成后访问时会遇到“不安全”的警告这是正常的。在客户端机器上把这个keystore里的证书导出来安装到系统受信任的根证书颁发机构里警告就会消失。测试时也可以直接用-c参数忽略证书校验。2.3 正式证书导入PKCS12转换完成证书链合并从证书厂商下载的证书通常是两个文件一个是域名证书比如gis_example_com.crt一个是中间CA证书比如ca.crt有时候还会有root.crt。这里我强调一个重点Java的keystore导入证书时如果只导入域名证书不导入中间CA证书会导致“unable to get local issuer certificate”或者“证书链不完整”的报错。这不是玄学是服务器和客户端都缺少中间CA导致无法信任链验证。所以拿到正式证书后我建议先把证书链合并成一个PEM文件再转成PKCS12格式。假设你的私钥是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导入keytool -importkeystore \ -srckeystore geoserver.pfx -srcstoretype PKCS12 -srcstorepass 证书密码 \ -destkeystore geoserver.jks -deststoretype PKCS12 -deststorepass changeit \ -srcalias 1 -destalias geoserver这里有两个容易忽略的小细节。第一个是srcaliaspfx文件里的别名有时候是“1”或者“mykey”你可以先执行keytool -list -keystore geoserver.pfx -storetype PKCS12查看一下。第二个是deststoretype我用的是PKCS12而不是老项目里常见的JKS原因前面说了跨平台兼容性更好Tomcat 8.5以上版本完全支持。2.4 证书链完整性的自检方法证书导完之后强烈建议先验证一遍而不是直接重启服务。验证证书链最直观的命令是openssl的s_clientopenssl s_client -connect gis.example.com:8443 -showcerts如果证书链正常会返回一个类似“Verify return code: 0 (ok)”的提示。如果返回20、21、22这类code基本就是证书链没传完整。本地在没有占用443端口的情况下也可以先用keytool查看一下keystore里的内容keytool -list -v -keystore geoserver.jks -storetype PKCS12 -storepass changeit能看到alias对应的条目并且证书链显示长度为2服务器证书中间CA或更长就说明导入是完整的。如果只有一条证书信息说明中间CA丢了要重新合并再导入一次。3. GeoServer上的SSL证书配置实操Tomcat完整流程3.1 准备阶段确认Java环境与GeoServer部署方式动手之前先搞清楚两件事GeoServer是独立安装版还是WAR包部署到Tomcat的版本因为配置文件的路径有差异。如果是GeoServer War包部署到独立Tomcat配置的是Tomcat自己的conf/server.xml如果是GeoServer官方网站下载的二进制发布版它内嵌了Jetty那么配置文件在GeoServer安装目录的etc目录下。这两者的配置方式和重启方式不太一样我身边有同事就是混淆了这两个路径改了半天发现不生效。这里我以最常见的“GeoServer WAR包 Tomcat”为例来写内嵌Jetty版本的处理方法在后面单独说明。另外确认一下tomcat的版本。Tomcat 8.5之前和8.5之后server.xml里配置SSL的写法差别很大。旧版本喜欢在Connector标签上一股脑塞keystoreFile、keystorePass这些属性新版本推荐用SSLHostConfig子标签。两种写法在Tomcat 8.5/9/10里都可以运行但我建议新配置直接用新的写法避免升级Tomcat时出问题。3.2 修改server.xml添加HTTPS Connector打开Tomcat的conf/server.xml文件找到现有的Connector配置区域默认情况下注释掉了一个8443端口的连接器。我们需要在这个区域新增一个HTTPS连接器配置。Connector port8443 protocolorg.apache.coyote.http11.Http11NioProtocol maxThreads300 schemehttps securetrue SSLEnabledtrue SSLHostConfig Certificate certificateKeystoreFile/data/ssl/geoserver.jks certificateKeystoreTypePKCS12 certificateKeystorePasswordchangeit certificateKeyAliasgeoserver / /SSLHostConfig /Connector这里有几个参数必须按实际情况改certificateKeystoreFile指向你存放keystore的绝对路径建议不要放在Tomcat的webapps目录下避免下次部署时被误删certificateKeystorePassword要和生成keystore时设置的storepass一致certificateKeyAlias要和keystore里的alias一致。证书路径我习惯放在一个统一的目录比如/data/ssl或者/etc/ssl/geoserver方便以后续期替换。有人会问端口为什么是8443而不是标准的443。原因很简单GeoServer本身一般不会占用80和443但在Linux系统上低于1024的端口启动时需要有root权限而Tomcat通常不以root运行。所以我一般先用8443做验证等确认没问题了再用iptables或者Nginx把443转发到8443或者直接改用Nginx处理443。如果是云服务器记得在安全组里放行对应端口。3.3 重启Tomcat并验证HTTPS端口配置完成后重启Tomcat然后确认端口监听状态netstat -tlnp | grep 8443看到LISTEN状态后用curl验证HTTPS是否正常curl -vk https://127.0.0.1:8443/geoserver如果出现HTTP/1.1 200状态码说明HTTPS连接器已经生效。curl命令里的-v参数会把证书链信息打出来你可以顺便确认下发证书的域名和CN是否匹配。如果出现证书错误别急着改配置先看错误发生在哪一环节。自签名证书的话curl会报self-signed certificate错误加-k参数只是跳过校验不代表配置没问题。3.4 让GeoServer正确识别HTTPS请求PROXY_BASE_URL设置这一步非常关键但很多人会漏掉。GeoServer默认情况下如果一个请求走的是HTTPS但是GeoServer看不到代理头或者没有明确的base URL配置它生成的WMS/WFS服务URL可能还是http。结果就是你的地图服务用HTTPS打开了但里面的资源地址是http浏览器直接拦截。解决办法是在GeoServer管理后台设置代理地址。打开GeoServer的Web管理界面进入“全局设置”(Global Settings)找到“代理基准URL”(Proxy Base URL)一栏填上对外服务的地址比如https://gis.example.com/geoserver然后保存并且把所有图层发布缓存清一下。这个配置的作用等于告诉GeoServer以后生成的所有服务链接都基于这个地址来拼。如果你用了Nginx反代还要再加一行设置让Tomcat识别X-Forwarded-Proto头这一步在后面的常见问题部分详细说。3.5 内嵌Jetty版本怎么配GeoServer发布版的SSL配置如果你的GeoServer是官网下载的独立安装版它内嵌了Jetty不能直接复用Tomcat的server.xml方案。Jetty版本的配置方式有两种。第一种是修改GeoServer安装目录下的start.ini在末尾追加SSL相关配置--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。这种配置相对繁琐我一般只用start.ini方式。改完要重启GeoServer服务然后同样用curl验证一下8443端口。其实不管Tomcat还是Jetty核心概念没变给容器指定一个包含证书和私钥的密钥库指定密码然后声明一个HTTPS监听端口。容器之间的语法差异只是换了一种写配置文件的方式。4. 遇到SSL报错怎么办常见问题排查与避坑实录4.1 高频报错速查表我把平时在GeoServer部署SSL过程中最常见的报错或者现象整理成了一个速查表遇到问题可以直接照着排查。报错/现象可能原因处理办法SSL证书错误无法建立安全连接证书链不完整把中间CA证书合并进certificateChainFile重新导入keystoreno required ssl certificate was sent服务端配置了强制客户端证书校验把clientAuth设为falsecurl: unable to get local issuer certificate本地缺少中间CA合并证书链或者本机导入根证书SSL connection required, but not provided by server客户端请求的端口不是HTTPS检查端口和连接器协议配置页面能打开但报混合内容错误GeoServer生成的URL还是http设置代理基准URL和X-Forwarded-Proto头证书显示不受信任自签名证书未安装到信任库安装根证书到系统信任区域keytool提示alias不存在导入时的别名与配置不一致用keytool -list查看实际别名HTTPS端口无法访问防火墙/安全组未放行端口检查iptables和云安全组策略4.2 经典问题一证书链不完整导致的手握证书也报错这个问题是我在实际工作中遇到最多的一个。用户明明已经把证书导入keystore了访问时浏览器还是提示“证书链不完整”或者“服务器证书不受信任”。原因很简单证书厂商发的证书包里有server.crt、root.crt、ca.crt三个文件有人只把server.crt导进了keystore没有把中间CA一起打包进去。解决办法是把证书链合并后再转成PKCS12我在前面2.3已经写过完整命令这里再强调一遍合并的顺序域名证书在前中间CA在后根证书可以不放进服务器但如果你的根证书不是公开信任的最好也一并放进去。合并后的文件用openssl验证一下openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout从输出里看到证书链的数量如果只有一条说明合并没成功。4.3 经典问题二GeoServer的WMS链接还是http地图服务白屏这个现象在切换HTTPS后特别常见。GeoServer管理界面正常但前端地图加载时报“Mixed Content: The page at ... was loaded over HTTPS, but requested an insecure resource http://.../geoserver/...”。问题根源是GeoServer不知道访问者的协议是HTTPS。如果你是Tomcat直连HTTPS不经过反代那只要在管理后台把“代理基准URL”设置成https开头就行。如果你前面加了Nginx还需要让Tomcat能够识别转发过来的协议头。Tomcat 8.5以上有一个阀门配置在server.xml的Host标签里加上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协议生成的WMS链接也会是https开头。这个问题排查起来很隐蔽因为表面上SSL是配好的实际应用层没有感知到安全协议的切换。4.4 经典问题三客户端请求报“no required ssl certificate was sent”这个报错很多做Java客户端或者脚本调用的朋友会遇到。它说的是服务端要求客户端发送SSL证书但客户端没有发。一般有两个原因一是GeoServer的Tomcat配置里把clientAuth设成了true或者want导致服务端强制客户端提供证书二是你用了某种客户端SDK它默认开启双向验证。排查方法很直接打开server.xml看看HTTPS连接器里是否包含clientAuth。默认GeoServer部署是不需要客户端证书的所以这个值应该是false或者不设置。如果你曾经为了某些安全测试改过记得改回来Connector ... clientAuthfalse ...如果确认不是Tomcat端的问题再检查客户端代理比如JMeter做压力测试时的SSL配置Chrome Developer证书选择等。GeoServer的WEB-GIS场景一般用不到双向证书不开启客户端校验才是正常状态。4.5 经典问题四证书续期后服务没生效免费证书的周期通常是90天所以续期是每个GeoServer管理员逃不掉的事。有的人续期后直接拿新fullchain.pem替换了服务器上的文件然后重启Tomcat发现还是旧证书。排查下来大概率是keystore里导入的还是旧证书。解决办法是把新的证书链重新合并重新生成keystore或者直接更新PKCS12文件。因为同一个密码和alias下导入的新证书会覆盖旧条目但如果你用了不同密码或aliasTomcat里的引用就找不到新条目自然还是旧证书生效。我个人习惯每次续期后用一个固定的文件名覆盖旧文件重启之前先用keytool -list确认下证书的有效期keytool -list -v -keystore geoserver.jks -storetype PKCS12 -storepass changeit | grep -A 5 Valid看到到期日期更新了再重启Tomcat就不会出现替换文件后没生效的尴尬。4.6 经典问题五安全扫描报告SSL/TLS协议漏洞CVE-2016-2183很多内网项目渗透测试时会报出一个“SSL/TLS协议信息泄露漏洞(CVE-2016-2183)”这个原理扫描经常让运维紧张。其实这个漏洞对应的是弱加密套件和旧版TLS协议。解决办法是在Tomcat的SSLHostConfig里显式指定启用的协议和禁用弱加密算法。SSLHostConfig protocolsTLSv1.2,TLSv1.3 ciphersTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,...这里我提醒一句不要照抄网上的加密套件列表要结合客户端的兼容性来调。比如有些测绘类桌面客户端用的老版本Java如果只保留最强套件反而会握手失败。稳妥的做法是先只限制协议为TLSv1.2以上算法保持默认等扫描报告不再报高危了再逐步收紧。CVE-2016-2183这个报错多数情况下只是扫描工具探测到服务端支持了一些过时密码套件及时升级Java版本并限制协议版本就好。5. 生产环境的额外建议从能访问到稳定跑5.1 用Nginx做443转发Tomcat保持8443本地监听如果你不想让Tomcat直接占用443端口也不想给Tomcat提权到root最省心的方案是让Nginx监听443然后反代到本地的8443或8080。这样做的好处是Nginx的证书管理比Tomcat更灵活以后续期证书都不用动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后面是否带/直接决定了访问路径会不会被重写。如果不带斜杠会把/geoserver/整个路径透传给后端带了斜杠会把/geoserver部分去掉。GeoServer必须保留/geoserver这个上下文所以这里我建议写成proxy_pass http://127.0.0.1:8080/geoserver/;。然后别忘了在GeoServer的代理基准URL里面设置https地址以及RemoteIpValve阀门。5.2 证书续期与自动化脚本化替换keystore免费证书最大的痛点就是续期。我自己的做法是写一个简单的shell脚本证书续期后自动把新证书转成keystore再重启Tomcat。因为阿里云SSL证书、Lets Encrypt这类证书服务商都有API或者客户端可以自动下发证书剩下的只是转换和重启。脚本核心逻辑是这样的# 续期后拿到新的fullchain.pem和server.key openssl pkcs12 -export -in fullchain.pem -inkey server.key \ -name geoserver -out /data/ssl/geoserver.p12 \ -passout pass:changeit # 如果原本用的JKS可以重新导入 keytool -importkeystore \ -srckeystore /data/ssl/geoserver.p12 -srcstoretype PKCS12 \ -destkeystore /data/ssl/geoserver.jks -deststoretype PKCS12 \ -deststorepass changeit -srcalias 1 -destalias geoserver # 重启服务 systemctl restart tomcat这里要小心一个问题在替换PKCS12文件前先备份旧文件一旦新证书有问题可以快速回滚。另外systemctl restart tomcat之前检查一下keystore文件的属主权限Tomcat运行用户是否能读取这块路径否则可能会出现配置文件没变但服务起不来的情况。5.3 端口关停老HTTP避免两边都开放造成逻辑混乱很多部署事故其实不是因为SSL没配好而是配好之后老的HTTP端口没有关掉。用户访问时如果还通过旧地址进来看到的页面又是http整个HTTPS改造看起来就相当于没做。建议在确认HTTPS稳定后禁用Tomcat上对外开放的8080端口或者在防火墙层面只允许内网访问8080对外只暴露443或8443。同时GeoServer有些第三方OSS上传或者其他插件可能也有基于HTTP的集成地址。改造HTTPS后要全面检查一遍所有集成方的回调地址把硬编码的老地址一并改掉否则前端地图能打开但上传服务、打印服务这些插件还是在跑HTTP。5.4 验证清单部署完成后逐项确认我每次部署完GeoServer SSL都会按下面这个清单过一遍浏览器用https://域名/geoserver访问地址栏无警告。用curl确认证书链和有效期证书无过期风险。发布一个WMS图层检查预览地址是否为https。前端页面用HTTPS加载控制台无mixed content报错。供桌面客户端或脚本调用的HTTP接口改为HTTPS后能正常返回数据。安全扫描工具复扫无高危SSL/TLS漏洞。这个清单看起来简单但每一项都可能藏着坑。尤其是第3和第4项只要代理基准URL或者X-Forwarded-Proto没配好就会出现“单点能访问、整体用不了”的情况。我在实际项目里最深的体会是GeoServer部署SSL本身不难难点在于把整个链条上的每个环节都搞明白。证书链只是第一步Java keystore是第二个坑容器配置是第三个坑应用层识别HTTPS是第四个坑。这四步只要走通一次后面再遇到其他Java应用需要配SSL基本都是同一个套路。尤其建议新手把PKCS12格式和keytool命令练熟这个工具会在后续所有Java相关的SSL配置里反复用到。最后再分享一个小技巧每次改完server.xml或keystore先把旧配置完整备份一份再动手。我遇到过不少次因为配置文件里多一个空格、路径写错一个字母导致服务起不来的情况有备份在手回滚起来会从容得多。
返回列表