分类
devops

Tomcat8使用SSLHostConfig配置PEM格式证书开启tls

准备

jdk
tomcat8
cfssl

# 安装java环境略
java -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)

curl -fksSL -O https://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.5.61/bin/apache-tomcat-8.5.61.tar.gz
tar -xvf apache-tomcat-8.5.61.tar.gz


for i in "cfssl" "cfssl-bundle" "cfssl-certinfo" "cfssl-newkey" "cfssl-scan" "cfssljson" "mkbundle" "multirootca"; do \
curl -sSL -o /usr/local/bin/${i} https://github.com/cloudflare/cfssl/releases/download/v1.5.0/${i}_1.5.0_linux_amd64; \
chmod +x /usr/local/bin/${i}; \
done

制作证书

cat > config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "876000h"
    },
    "profiles": {
      "kubernetes": {
        "usages": ["signing", "key encipherment", "server auth", "client auth"],
        "expiry": "876000h"
      },
      "client": {
        "usages": ["signing", "key encipherment", "client auth"],
        "expiry": "876000h"
      }
    }
  }
}
EOF


cat > ca-csr.json <<EOF
{
  "CN": "root-ca",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "dyrnq"
    }
  ],
  "ca": {
    "expiry": "876000h"
 }
}
EOF

cat > server-csr.json <<EOF
{
  "CN": "tomcat",
  "hosts": [
    "127.0.0.1",
    "192.168.1.101",
    "tomcat",
    "tomcat.default",
    "tomcat.default.svc",
    "tomcat.local"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "BeiJing",
      "L": "BeiJing",
      "O": "k8s",
      "OU": "dyrnq"
    }
  ]
}
EOF
cat > client-csr.json <<EOF
{
  "CN": "client",
  "key": {
    "algo": "rsa",
    "size": 4096
  },
  "names": [
    {
      "O": "tomcat"
    }
  ]
}
EOF

cat server-csr.json;

cfssl gencert -initca ca-csr.json | cfssljson -bare ca
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=config.json -profile=kubernetes server-csr.json | cfssljson -bare server

在server-csr.json的hosts字段增加你的tomcat要使用的域名或者IP。

配置tomcat

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Nio2Protocol" secure="true" scheme="https" SSLEnabled="true">
  <SSLHostConfig caCertificateFile="ca.pem">
    <Certificate
        certificateFile="server.pem"
        certificateKeyFile="server-key.pem" />
  </SSLHostConfig>
</Connector>

启动tomcat

./catalina.sh run
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/local/java
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
23-Dec-2020 23:45:09.331 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name:   Apache Tomcat/8.5.61
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built:          Dec 3 2020 14:03:28 UTC
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 8.5.61.0
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name:               Linux
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version:            4.19.95
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture:          amd64
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home:             /usr/local/java/jre
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version:           1.8.0_201-b09
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor:            Oracle Corporation
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE:         /usr/local/tomcat
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME:         /usr/local/tomcat
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
23-Dec-2020 23:45:09.333 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs=
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp
23-Dec-2020 23:45:09.334 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib]
23-Dec-2020 23:45:09.421 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
23-Dec-2020 23:45:09.429 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
23-Dec-2020 23:45:09.438 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["https-jsse-nio2-8443"]
23-Dec-2020 23:45:09.602 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 512 ms
23-Dec-2020 23:45:09.615 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
23-Dec-2020 23:45:09.615 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.61
23-Dec-2020 23:45:09.619 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/ROOT]
23-Dec-2020 23:45:09.743 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/ROOT] has finished in [124] ms
23-Dec-2020 23:45:09.743 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/docs]
23-Dec-2020 23:45:09.752 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/docs] has finished in [9] ms
23-Dec-2020 23:45:09.752 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/examples]
23-Dec-2020 23:45:09.882 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/examples] has finished in [129] ms
23-Dec-2020 23:45:09.882 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/host-manager]
23-Dec-2020 23:45:09.894 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/host-manager] has finished in [12] ms
23-Dec-2020 23:45:09.895 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/usr/local/tomcat/webapps/manager]
23-Dec-2020 23:45:09.905 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/usr/local/tomcat/webapps/manager] has finished in [11] ms
23-Dec-2020 23:45:09.910 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
23-Dec-2020 23:45:09.955 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["https-jsse-nio2-8443"]
23-Dec-2020 23:45:09.955 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 353 ms

我们用chrome浏览器打开 https://192.168.1.101:8443 ,由于是自签的证书,chrome浏览器会提示 您的连接不是私密连接 攻击者可能会试图从 192.168.1.101 窃取您的信息(例如:密码、通讯内容或信用卡信息)。了解详情
NET::ERR_CERT_AUTHORITY_INVALID
,这时候我们点开高级,点击 继续前往192.168.1.101(不安全) 即可。也可以用curl命令加上--cacert进行测试。

curl --cacert ./ca.pem https://127.0.0.1:8443
curl --resolve "tomcat:8443:127.0.0.1"  --cacert ./ca.pem https://tomcat:8443

也可以通过curl命令加上--insecure强制忽略验证

curl --insecure https://127.0.0.1:8443
openssl s_client -showcerts -connect 127.0.0.1:8443 -servername 127.0.0.1:8443 </dev/null 2>/dev/null |openssl x509 -noout -text

通过以下命令得到sha1指纹

openssl s_client -showcerts -connect 127.0.0.1:8443 -servername 127.0.0.1:8443 </dev/null 2>/dev/null |openssl x509 -in /dev/stdin  -sha1 -noout -fingerprint

双向认证

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=config.json -profile=client client-csr.json | cfssljson -bare client

keytool -importcert -trustcacerts \
-alias server-trust \
-file ca.pem -keystore server-trust.keystore \
-v \
-noprompt \
-storepass changeit
<Connector port="9443" protocol="org.apache.coyote.http11.Http11Nio2Protocol" secure="true" scheme="https" SSLEnabled="true">
  <SSLHostConfig caCertificateFile="ca.pem" truststoreType="jks" truststoreFile="server-trust.keystore" truststorePassword="changeit" certificateVerification="required">
    <Certificate
        certificateFile="server.pem"
        certificateKeyFile="server-key.pem" />
  </SSLHostConfig>
</Connector>

这时候我们再用chrome浏览器打开https://192.168.1.101:9443会提示报错:

此网站无法提供安全连接192.168.1.101 不接受您的登录证书,或者您可能没有提供登录证书。
请尝试联系系统管理员。
ERR_BAD_SSL_CLIENT_AUTH_CERT

使用curl命令也会报错alert bad certificate

curl --cacert ./ca.pem https://127.0.0.1:9443
curl: (35) error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
curl -k https://127.0.0.1:9443
curl: (35) error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate

正确的方法用curl命令带--cacert --cert --key 这三个参数

curl --cacert ./ca.pem --cert client.pem --key client-key.pem https://127.0.0.1:9443

总结

tree -I "*.json|*.csr"
.
|-- ca-key.pem
|-- ca.pem
|-- client-key.pem
|-- client.pem
|-- server-key.pem
|-- server-trust.keystore
`-- server.pem

0 directories, 7 files
jks -> p12

keytool -importkeystore \
-srckeystore server-trust.keystore \
-srcstoretype JKS \
-deststoretype PKCS12 \
-destkeystore server-trust.p12 \
-srcalias server-trust \
-destalias server-trust \
-srcstorepass changeit \
-deststorepass changeit \
-noprompt \
-v

keytool -list -keystore ./server-trust.p12 -storepass changeit -v
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: server-trust
Creation date: Dec 25, 2020
Entry type: trustedCertEntry


keytool -list -keystore ./server-trust.keystore -storepass changeit -v
Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: server-trust
Creation date: Dec 25, 2020
Entry type: trustedCertEntry

这里需要注意jdk版本default keystore type 是JKS还是PKCS12 https://openjdk.java.net/jeps/229

<Connector port="9443" protocol="org.apache.coyote.http11.Http11Nio2Protocol" secure="true" scheme="https" SSLEnabled="true">
  <SSLHostConfig caCertificateFile="ca.pem" truststoreType="pkcs12" truststoreFile="server-trust.p12" truststorePassword="changeit" certificateVerification="required">
    <Certificate
        certificateFile="server.pem"
        certificateKeyFile="server-key.pem" />
  </SSLHostConfig>
</Connector>

ref

  • https://tomcat.apache.org/tomcat-8.5-doc/ssl-howto.html
  • https://tomcat.apache.org/tomcat-8.5-doc/config/http.html#SSL_Support_-_SSLHostConfig
  • https://geekflare.com/tomcat-ssl-guide/
  • https://geekflare.com/apache-tomcat-hardening-and-security-guide/
  • https://blog.csdn.net/chuzhi78/article/details/76877935
  • https://colobu.com/2016/06/07/simple-golang-tls-examples/
  • https://yevon-cn.github.io/2017/04/09/https-config-of-tomcat.html
  • https://blog.freessl.cn/ssl-cert-format-introduce/