[기록] DocumentDB에서 TLS 인증 문제

 

자율 프로젝트에서의 제일 큰 도전 과제는 MSA 도입이었는데, 

더불어 DB도 EC2에 도커 이미지로 띄우는게 아니라 AWS DocumentDB랑 RDS를 써보기로했다.

이번 문제는 EC2에서 실행되고있는 Spring에서 DocumentDB에 있는 mongoDB로 데이터를 전송하면 TLS 인증 문제가 발생하는 것이었다.

 

🖥️ 개발 환경

Ubuntu 22.04
Spring 2.7
Java 11

 

👩🏻‍💻 전체 에러 로그

Timed out after 30000 ms while waiting for a server that matches com.mongodb.client.internal.MongoClientDelegate$1@33790563. Client view of cluster state is {type=REPLICA_SET, servers=[{address:27017=zootopia-mongodb.cluster-c2f2jpwzzxst.ap-northeast-2.docdb.amazonaws.com, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketWriteException: Exception sending message}, caused by {javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}, caused by {sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}, caused by {sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches com.mongodb.client.internal.MongoClientDelegate$1@33790563. Client view of cluster state is {type=REPLICA_SET, servers=[{, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketWriteException: Exception sending message}, caused by {javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}, caused by {sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}, caused by {sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target}}]

 

👩🏻‍💻 핵심 에러 로그

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

 

👩🏻‍💻 원인 (확실하진 않으나 추정)

Java에서 https를 이용한 SSL/TLS 통신을 할 때, 통신하려는 서버의 인증서가 통신을 시도하는 자바 버전에서 신뢰할 수 있는 인증 기관으로 인식되지 못해 발생하는 것

 

👩🏻‍💻 해결 방법

  • 사실 팀원이랑 동시에 에러 해결에 붙어서 해결 방법은 이것입니다!!! 할수 없음
  • 그래서 우리가 행한 모든 행동을 기록하려 함

1️⃣ AWS 공식 문서 참고

  • Ubuntu에서 script.sh 작성
    • truststorePassword → 별도 설정
    • 실제로 /tmp/ 경로는 존재했으나 /certs/는 없어서 mkdir certs를 통해 폴더 생성 해줌
    • 스크립트 파일 실행 ./script.sh
    • 스크립트 실행 시, 권한 때문에 deny되면 chmod +x script.sh
    • 그 외 권한 문제 검색 참고
mydir=/tmp/certs
truststore=${mydir}/rds-truststore.jks
storepassword=

curl -sS "<https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem>" > ${mydir}/global-bundle.pem
awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1}{print > "rds-ca-" n ".pem"}' < ${mydir}/global-bundle.pem

for CERT in rds-ca-*; do
  alias=$(openssl x509 -noout -text -in $CERT | perl -ne 'next unless /Subject:/; s/.*(CN=|CN = )//; print')
  echo "Importing $alias"
  keytool -import -file ${CERT} -alias "${alias}" -storepass ${storepassword} -keystore ${truststore} -noprompt
  rm $CERT
done

rm ${mydir}/global-bundle.pem

echo "Trust store content is: "

keytool -list -v -keystore "$truststore" -storepass ${storepassword} | grep Alias | cut -d " " -f3- | while read alias 
do
   expiry=`keytool -list -v -keystore "$truststore" -storepass ${storepassword} -alias "${alias}" | grep Valid | perl -ne 'if(/until: (.*?)\\n/) { print "$1\\n"; }'`
   echo " Certificate ${alias} expires in '$expiry'" 
done
  • Spring 프로젝트 DocumentDBConfig 작성
@Configuration
public class DocumentDBConfig {
    private MongoProperties properties;

    public static final String KEY_STORE_TYPE = "/tmp/certs/rds-truststore.jks";
    public static final String DEFAULT_KEY_STORE_PASSWORD = <truststorePassword>;

    public DocumentDBConfig(final MongoProperties properties) {
        super();
        this.properties = properties;
    }

    @Bean
    public MongoClientSettings mongoClientSettings() {
        setSslProperties();
        return MongoClientSettings.builder()
                .applyToSslSettings(builder -> builder.enabled(true))
                .build();
    }

    private static void setSslProperties() {
        System.setProperty("javax.net.ssl.trustStore", KEY_STORE_TYPE);
        System.setProperty("javax.net.ssl.trustStorePassword",
                DEFAULT_KEY_STORE_PASSWORD);
    }

    @Bean
    public MongoPropertiesClientSettingsBuilderCustomizer mongoPropertiesCustomizer(final MongoProperties properties, final Environment environment) {
        return new MongoPropertiesClientSettingsBuilderCustomizer(properties, environment);
    }

}

 

2️⃣ Ubuntu에서 인증서 관련 설정

 

1. InstallCert.java 다운

2. Ubuntu 환경에 해당 파일을 복사해줌 (MovaXterm은 로컬에서 바로 복사가 가능한데 일반 터미널에서 하는 방법은 검색해보시길,,!)

  • 우리 프로젝트의 경우
  • /usr/lib/jvm/java-11-openjdk-amd64/lib/security/ 였음
여기서 ${JAVA_HOME}은 java가 설치된 위치
찾는 방법은 이 링크 참고
(https://codingdog.tistory.com/entry/%EC%9A%B0%EB%B6%84%ED%88%AC-java-%EC%84%A4%EC%B9%98%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4)
sudo mv [경로]/InstallCert.java ${JAVA_HOME}/jre/lib/security/

 

3. 옮겨진 파일 위치로 들어가서, 컴파일 해줌

sudo javac -d . InstallCert.java

 

4. 컴파일 됐으면 파일 실행

sudo java -cp . InstallCert [IP/HOST]
  • IP/HOST에는 우리 서비스 주소를 넣어줬음

5. https 보안 적용된 주소로 접속해서 보안인증서 다운
→ 주소창 옆 자물쇠눌러서 이 연결은 안전합니다 > 인증서가 유효함 > 세부사항 > 내보내기

6. ubuntu로 인증서 복사

7. 아래 명령어 입력

sudo keytool -importcert -file _.heartpath.site.crt -keystore /usr/lib/jvm/java-11-openjdk-amd64/lib/security/cacerts -storepass changeit -noprompt

1번과 2번 과정이 동시다발로 이뤄져서 무엇이 문제다!는 말 못하지만, 예상컨데 TLS인증서 못찾음 + 자바가 인증서를 신뢰하지 못함 둘 다가 원인인 것 같다.

각자 설정을 마치고 테스트했을때 TLS관련 오류는 더이상 뜨지않고 mongoDB에 데이터가 잘 들어갔음을 확인했다.


23.11.29 추가

1번이나 2번 둘중에 하나만 해도 상관없음. 다만 적용하면 FCM이 오류나는 현상 발생,,,,ㅎ


참고자료

https://docs.aws.amazon.com/ko_kr/documentdb/latest/developerguide/connect_programmatically.html

https://freestrokes.tistory.com/67

https://hasiki.tistory.com/5