前言
这个方案的很多核心问题都是在公司同事的帮助下解决的,本文特别予以感谢。本文是通过自签名证书对GeoSmarter5.2系统进行https改造,为了使得改造成本变低本文采用把tomcat使用https + nginx使用https的方式(如果仅修改nginx的话,会需要修改程序jsp获取scheme的逻辑,否则将获取不到css和js)。
nginx:
使用我的脚本自签名证书给nginx签发一对tls证书,脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#!/bin/sh
HOST=$1
PASSWORD="123@Abc.com"
SUBJECT="/C=CN/ST=Hubei/L=Wuhan/O=GeoStar/CN=$HOST"
# create self-signed server certificate:
echo "Create server key..."
openssl genrsa -passout pass:$PASSWORD -des3 -out $HOST.key 4096
echo "Create server certificate signing request..."
openssl req -passin pass:$PASSWORD -new -subj $SUBJECT -key $HOST.key -out $HOST.csr
echo "Remove password..."
mv $HOST.key $HOST.origin.key
openssl rsa -passin pass:$PASSWORD -in $HOST.origin.key -out $HOST.key
echo "Sign SSL certificate..."
openssl x509 -req -passin pass:$PASSWORD -days 3650 -in $HOST.csr -signkey $HOST.key -out $HOST.crt
echo "Example TODO:"
echo "Copy $HOST.crt to /etc/nginx/ssl/$HOST.crt"
echo "Copy $HOST.key to /etc/nginx/ssl/$HOST.key"
echo "Add configuration in nginx:"
echo "server {"
echo " ..."
echo " listen 443 ssl;"
echo " ssl_certificate /etc/nginx/ssl/$HOST.crt;"
echo " ssl_certificate_key /etc/nginx/ssl/$HOST.key;"
echo "}"
|
执行脚本的时候,脚本的第一个参数是nginx的ip,这个很关键,因为程序在调用https的接口的时候回校验证书,如果你的host跟证书的CommonName不匹配的话就会报错:
1
2
3
4
5
|
javax.net.ssl.SSLPeerUnverifiedException: Certificate for <xxx> doesn't match common name of the certificate subject: xx.xxx.xx.xx
at org.apache.http.conn.ssl.DefaultHostnameVerifier.matchCN(DefaultHostnameVerifier.java:186)
at org.apache.http.conn.ssl.DefaultHostnameVerifier.verify(DefaultHostnameVerifier.java:133)
at org.apache.http.conn.ssl.DefaultHostnameVerifier.verify(DefaultHostnameVerifier.java:99)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:463)
|
生成证书以后,拷贝证书到应用代理的nginx容器,把证书配置到应用代理的nginx配置中:
1
2
3
4
5
6
|
server{
listen 9010 ssl;
ssl_certificate <crt公钥证书>;
ssl_certificate_key <key私钥证书>;
error_page 497 307 https://$host:$server_port$request_uri;
}
|
然后修改location下的proxy_pass地址为https协议,一般cas我们是不需要修改的,修改其他应用即可。
其他应用(tomcat下):
①屏蔽系统配置初始化的选项,这个配置在/srv/tomcat8/bin/catalina.sh,打开脚本后一般在第一或者第二页能够找到形如:
1
|
java -jar /opt/jar/update-bigdatacenter-config.jar ***
|
在这一句前面添加一个#号,注释掉。
②给tomcat生成一个keystore证书:
1
2
|
$ mkdir /ssl
$ keytool -genkey -alias tomcat -keyalg RSA -storetype pkcs12 -validity 7300 -keystore /ssl/server.keystore -keysize 2048 -keypass DwpPAd23xzvZTn09RmMuZKe3T4FeXfhM -storepass DwpPAd23xzvZTn09RmMuZKe3T4FeXfhM -dname "CN=GeoStar, OU=GeoStar, O=GeoStar, L=Wuhan, S=Hubei, C=China"
|
③配置证书到8080端口,有人会疑问为啥不直接用8443端口,很简单,为了不用改动容器的端口映射:
1
2
3
4
5
6
7
8
9
10
11
|
<!-- # 屏蔽掉原来8080的connector
<Connector port="8080" URIEncoding="UTF-8" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" /> -->
<!-- 新增如下connector -->
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8080" maxThreads="200" URIEncoding="UTF-8"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="/ssl/server.keystore"
keystorePass="DwpPAd23xzvZTn09RmMuZKe3T4FeXfhM"
clientAuth="false" sslProtocol="TLS"/>
|
④拷贝nginx的证书到每个应用的容器中,使用keytools工具把nginx证书添加为jdk的白名单:
1
2
3
4
|
# 假设你nginx的ip为10.0.0.1,并且证书被拷贝到了容器的/root目录,$JAVA_HOME已经到了jre的目录(如果没到的话需要增加一级jre路径)
$ keytool -keystore $JAVA_HOME/lib/security/cacerts -import -alias 10.0.0.1 -file /root/10.0.0.1.crt
# 输入默认密码,这里只需要输入一次密码,如果你需要输入两次说明你的路径不对
$ changeit
|
⑤修改应用的配置文件:
一般应用的配置文件都在/srv/tomcat8/webapps/<应用名>/WEB-INF/classes或者/srv/tomcat8/webapps/<应用名>/WEB-INF/classes/config,将应用间调用的地址改成https。
⑥cas_client会校验证书的合法性,由于是我们自己签发的证书,所以铁定会报错
1
|
ERROR [https-jsse-nio-8080-exec-8] org.jasig.cas.client.util.CommonUtils.getResponseFromServer - SSL error getting response from host xx.xx.xx.xx: Error Message: No subject alternative names present javax.net.ssl.SSLHandshakeException:No subject alternative names present
|
拷贝cas_client的补丁(点我下载),到容器里面,解压到/srv/tomcat8/webapps/<应用名>/WEB-INF/classes/com/geostar/gfstack/util目录
1
2
3
|
$ mkdir -p /srv/tomcat8/webapps/<应用名>/WEB-INF/classes/WEB-INF/classes/com/geostar/gfstack/util
$ mv /root/com/geostar/gfstack/util/TrustCASServerSSLListener.class /srv/tomcat8/webapps/<应用名>/WEB-INF/classes/WEB-INF/classes/com/geostar/gfstack/util/
$ mv /root/com/geostar/gfstack/util/TrustCASServerSSLListener\$TrustAllManager.class /srv/tomcat8/webapps/<应用名>/WEB-INF/classes/WEB-INF/classes/com/geostar/gfstack/util/
|
然后配置/srv/tomcat8/webapps/<应用名>/WEB-INF/web.xml,增加监听这个类:
1
2
3
|
<listener>
<listener-class>com.geostar.gfstack.util.TrustCASServerSSLListener</listener-class>
</listener>
|
⑦重启应用