들어가기 전에
최근 Let's Encrpyt 인증서가 적용된 사이트와의 통신 시, 하기와 같인 에러가 발생하였습니다.
javax.net.ssl.SSLException: Received fatal alert: internal_error
이번 포스팅에서는 위 에러 발생 원인과 해결 방안에 대해 알아보고자 합니다.
왜 에러가 발생했을까?
위 에러가 발생했을 때, 해당 통신을 진행하는 서버에서 openssl 명령어로 SSL 통신은 제대로 이루어지는지 확인해보고자 아래 명령어를 통해 인증서를 체크해보았습니다.
[earth@earth-server ~]$ openssl s_client -connect [Let's encrypt 인증서 들어간 도메인]:443 -servername [호출한 도메인]
CONNECTED(00000003)
depth=3 O = Digital Signature Trust Co., CN = DST Root CA X3
verify error:num=10:certificate has expired
notAfter=Sep 30 14:01:15 2021 GMT
...
그 결과, verify error:num=10:certificate has expired라는 문구와 notAfter 부분에 이미 지난 날짜가 들어가있는 것을 확인할 수 있었습니다.
위 내용만 확인했을 때에는 Let's encrypt 인증서가 들어간 사이트의 SSL 인증서가 만료된건가?라는 의문이 들었지만, 그랬더라면 해당 사이트를 호출하는 다른 회사에서도 동일한 이슈가 발생했어야 정상일 것이란 생각이 들어 좀 더 찾아보게 되었습니다. 그 결과 아래와 같이 Let's Encrypt가 제공하는 Root Certificate에 변화가 생겼음을 확인할 수 있었습니다.
Let's Encrypt가 제공하는 Root Certificate 변화
Let's Encrypt Document를 확인해보면, 2021/09/30을 기준으로 Let's Encrypt 인증서의 DST Root CA X3의 교차 서명(cross-sign) 기능이 만료되었음을 확인할 수 있습니다.
Let's Encrypt에서 발급하는 인증서는, ISRG Root X1을 Root CA 목록에 가지고 있지 않은 오래된 버전의 플랫폼에서 Let's Encrypt 인증서를 신뢰할 수 있도록 DST Root CA X3의 교차 서명 역시 허용하고 있었습니다. 하지만, 2021/09/30을 기점으로 DST Root CA X3가 만료되어 ISRG Root X1을 신뢰하지 않는 JDK 버전을 사용하던 소스에서 Let's Encrypt 인증서를 사용한 사이트를 호출할 때에 expired 되었다는 에러가 발생한 것입니다.
- DST Root CA X3을 가지고 인증서 확인을 하였기 때문에 openssl 명령어 사용 시, NotAfter 부분에 2021/09/30이 적혀있던 것입니다.
해결 방법
해결 방안은 크게 두 가지로 나눌 수 있습니다.
- 현재 사용하고 있는 JDK(필자의 경우 JAVA를 사용하기 때문에 JDK로 예시)의 cacerts에 ISRG Root X1을 추가합니다.
- 기본적으로 cacerts에 ISRG Root X1을 포함하고 있는 JDK로 업그레이드합니다. cacerts에 ISRG Root X1을 포함하고 있는 플랫폼은 아래 캡쳐 사진에서 확인할 수 있습니다.
필자의 경우, 사용하고 있던 JDK의 마이너 버전을 높여 ISRG Root X1에 대해 JDK가 신뢰할 수 있도록 하였습니다. JDK 마이너 버전 업그레이드하는 것에 문제가 없다면 cacerts를 추가하는 것 보다 JDK 업그레이드가 더 나은 방안이라고 생각합니다.
- 계속하여 신규 버전이 나오기 때문에, 최대한 다음 버전으로 넘어가기 전 체크 포인트를 줄이기 위해 업그레이드 가능한 부분에 대해서는 미리 업그레이드하고자 합니다.