작업 전 확인
어느 조치를 하든 여기서 시작한다. SSH로 접속한다.
웹서버 종류와 버전을 확인한다.
ps -ef | grep -E 'catalina|tomcat' | grep -v grep # 프로세스에서 CATALINA_HOME 경로도 보임
$CATALINA_HOME/bin/version.sh # 버전·JVM 확인
프로세스 인자의 -Dcatalina.home= 값이 설치 경로다.
앞단에 Nginx나 Apache 프록시가 있으면 TLS는 프록시에서 종단될 수 있다. server.xml에 8443/443 Connector가 없으면 TLS 조치는 프록시 가이드를 따른다.
설정 파일은 $CATALINA_HOME/conf/server.xml(TLS)과 conf/web.xml(헤더 필터)이다. 인증서 경로는 server.xml의 SSLHostConfig > Certificate나 구식 Connector의 keystoreFile 속성에 있다.
TLS 1.0, 1.1 끄고 TLS 1.3 켜기
Tomcat 8.5, 9, 10 이상은 SSLHostConfig로 지정한다.
Tomcat 9.0.x는 2027-03-31에 지원이 끝난다(공지). 새로 구성한다면 10.1 이상으로 한다. 아래 SSLHostConfig 설정은 9와 10.1에서 같다.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
SSLEnabled="true">
<SSLHostConfig protocols="TLSv1.2+TLSv1.3">
<Certificate certificateKeystoreFile="conf/keystore.jks" ... />
</SSLHostConfig>
</Connector>
Tomcat 7, 8.0은 구식 Connector 속성을 쓴다.
<Connector port="8443" ... sslEnabledProtocols="TLSv1.2" />
TLS 1.3은 JDK 11 이상에서 되고, JDK 8은 8u261부터 지원한다(Oracle 8u261 릴리스 노트의 JSSE TLS 1.3 백포트). version.sh에 나오는 JVM Version을 확인한다.
보안 헤더
conf/web.xml에는 Tomcat 내장 HttpHeaderSecurityFilter의 <filter>와 <filter-mapping>이 각각 주석 처리된 채로 들어 있다(저장소 원문 참고). 두 블록의 주석을 풀고 <filter>에 init-param을 더한다. <filter-mapping>은 <filter> 안에 넣지 않고 바깥에 따로 둔다.
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<async-supported>true</async-supported>
<init-param><param-name>hstsEnabled</param-name><param-value>true</param-value></init-param>
<init-param><param-name>hstsMaxAgeSeconds</param-name><param-value>31536000</param-value></init-param>
<init-param><param-name>antiClickJackingEnabled</param-name><param-value>true</param-value></init-param>
<init-param><param-name>blockContentTypeSniffingEnabled</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
CSP와 Referrer-Policy는 이 필터에 없다. 애플리케이션 필터로 넣거나 앞단 프록시에서 붙이는 편이 간단하다.
HTTP → HTTPS 리다이렉트
conf/web.xml 끝에 넣는다.
<security-constraint>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
server.xml의 80(8080) Connector에 redirectPort="443"이 설정돼 있어야 실제로 넘어간다.
약한 키나 서명이면 인증서 교체
keystore(JKS/PKCS12)를 다시 만들어 바꾼다. 만료일 확인은 SSL 인증서 만료일 확인하는 법에 있다.
신규 도메인 인증서 설치
발급과 파일 준비는 발급 공통 가이드에서 먼저 끝낸다. Tomcat은 keystore로 바꿔야 한다.
PKCS12 keystore를 만든다.
openssl pkcs12 -export -out 새도메인.p12 \
-inkey privkey.pem -in fullchain.pem -name 새도메인
server.xml에 커넥터와 호스트를 추가한다. 8.5+는 SNI로 도메인마다 인증서를 따로 둘 수 있다.
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true">
<SSLHostConfig hostName="새도메인" protocols="TLSv1.2+TLSv1.3">
<Certificate certificateKeystoreFile="conf/새도메인.p12"
certificateKeystorePassword="비밀번호" type="RSA" />
</SSLHostConfig>
</Connector>
7, 8.0은 Connector당 keystore가 1개(keystoreFile, keystorePass 속성)라서, 도메인별로 나누려면 포트를 나눠야 한다.
진단 툴로 확인한다.
재검사
진단 툴로 다시 검사한다. 결과는 최대 10분 캐시된다.