SSL/TLS 통신은 인터넷에서 데이터를 안전하게 주고받기 위해 사용한다. 특히 mTLS(Mutual TLS)는 서버와 클라이언트가 서로를 인증하여 보안 수준을 더욱 강화한다. 이 글에서는 OpenSSL과 KeyTool을 사용하여 인증서를 발급하고, 이를 Java 애플리케이션에서 관리하며 mTLS를 설정하는 방법을 간단히 정리한다.
주요 개념
mTLS통신을 통한 상호 인증에는 인증서를 발급하는 곳(CA), 인증서, 인증서를 검증하는 방법이 필요하다.
인증서를 발급하는 방법은 OpenSSL과 KeyTool을 사용해서 사설인증서를 직접 발급하는 방법과, 외부 CA에서 발급받는 방법이 있다. 테스트를 위해서 OpenSSL을 통해서 발급받는 방법을 사용했다.
SSL(Secure Sockets Layer)
웹사이트와 브라우저 사이 또는 서버 사이에 전송되는 데이터를 암호화하여 인터넷 연결을 보호하기 위한 표준 기술
TLS(Transport Layer Security)
SSL의 향상된, 더욱 안전한 버전으로, SSL은 취약점(인증문제 등)으로 더 이상 사용하지않으며, TLS로 대체됨.
향상된 암호화 알고리즘을 지원하며, TLS 1.3 기준 DH(ECDHE)기반 키 교환을 기본으로 사용하고 MAC(메시지 인증코드)를 사용해 중간자 공격(MITM)을 방지할 수 있음
TLS는 1.2에서 1.3로 버전 업그레이드가 되면서 큰 성능향상을 이뤄냈고, Java 11 이상에서 부터 TLS 1.3을 지원함(이전 버전은 TLS 1.2까지만 지원)
mTLS(Mutual TLS)
mTLS는 상호간의 TLS로, 일반적인 HTTPS에서 사용되는 TLS는 서버만 인증하는 방식이지만, mTLS는 서버측에서도 클라이언트를 인증하는 방식으로 양방향 인증이라고 불림. B2B 통신 또는 보안이 중요한 API에 주로 쓰임.
클라이언트를 인증해야하기때문에 클라이언트 인증서가 추가로 필요함
키스토어(KeyStore) 트러스트스토어(TrustStore)?
키스토어와 트러스트스토어는 JDK(Java Development Kit)에서 제공하는 Keytool 유틸리티를 통해 관리할 수 있는 파일 형식이다. 모두 JKS(Java Key Sotre)형식으로 동일하고 차이점은 다음과 같다.
구분 | KeyStore | TrustStore |
키 타입 | 개인 키(Private Key) | 공개 키(Public Key) |
저장 | 개인 키와 관련된 인증서 저장 | 신뢰할 수 있는 CA 인증서나 공개 키 인증서를 저장 |
사용 | TLS통신에서 자신의 신원 증명 또는 암호화를 위한 개인키 사용 시 | TLS 통신에서 서버나 클라이언트의 인증서를 신뢰할 수 있는지 확인 |
mTLS 작동 방식
1. 클라이언트가 서버에 연결 요청 : 클라이언트가 서버 인증서를 검증
2. 서버가 클라이언트 인증서 요청 : 클라이언트가 자신의 인증서 서버에 전달
3. 서버와 클라이언트 서로 인증 : 서버는 TrustStore에 등록된 CA 인증서를 통해 클라이언트 검증, 클라이언트도 마찬가지고 서버의 인증서 검증
4. 양방향 인증 완료 후 통신 시작
SpringBoot에서 mTLS를 사용하기
1. 인증서 발급 방법(CA) - OpenSSL로 인증서 생성 및 관리
1) CA 인증서 생성
# CA의 개인 키 생성
openssl genrsa -out ca-key.pem 2048
# CA의 자체 서명 인증서 생성
openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 365 -out ca-cert.pem -subj "/CN=MyCA"
2) 서버 인증서 생성
# 서버의 개인 키 생성
openssl genrsa -out server-key.pem 2048
# 서버의 인증서 서명 요청(CSR) 생성
openssl req -new -key server-key.pem -out server-csr.pem -subj "/CN=server.example.com"
# CA로 서버 인증서 서명
openssl x509 -req -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 365 -sha256
3) 클라이언트 인증서 생성
# 클라이언트의 개인 키 생성
openssl genrsa -out client-key.pem 2048
# 클라이언트의 CSR 생성
openssl req -new -key client-key.pem -out client-csr.pem -subj "/CN=client.example.com"
# CA로 클라이언트 인증서 서명
openssl x509 -req -in client-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -days 365 -sha256
2. Keytool을 이용한 인증서 관리
1) KeyStore 생성 및 인증서 추가
# KeyStore에 서버 인증서 및 개인 키 추가
keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server-keystore.jks -deststoretype JKS -storepass password
2) TrustStore 생성 및 CA 인증서 추가
# TrustStore에 CA 인증서 추가
keytool -import -trustcacerts -file ca-cert.pem -alias ca-cert -keystore server-truststore.jks -storepass password
3. mTLS 설정
1) SpringBoot의 mTLS 설정 방법
# application.yml
server:
ssl:
enabled: true
key-store: classpath:server-keystore.p12 # 서버의 키스토어 경로
key-store-password: serverpassword # 서버 키스토어 비밀번호
key-store-type: PKCS12 # 서버 키스토어 타입
trust-store: classpath:server-truststore.jks # 트러스트 스토어 경로(클라이언트인증서 검증)
trust-store-password: trustpassword # 트러스트 스토어 비밀번호
trust-store-type: JKS # 트러스트 스토어 타입
client-auth: need # 클라이언트 인증서 반드시 요구(want는 선택 요구)
client-auth를 need로 설정하면, 클라이언트의 인증서를 반드시 요구하기때문에 기본적으로 클라이언트측에서 하는 서버 검증과 서버쪽에서하는 클라이언트 검증을 해, 상호 인증이 이루어진다.
다음은 참고사항인데(테스트 코드 작성 시 참고) 클라이언트측에서도 이러한 방법으로 자신의 키스토어와 서버 트러스트 스토어를 설정해서 서버와의 mTLS 통신을 준비할 수 있다.
HttpClient httpClient = HttpClients.custom()
.setSSLContext(SSLContexts.custom()
.loadKeyMaterial(clientKeyStore, "clientKeyPassword".toCharArray())
.loadTrustMaterial(clientTrustStore, new TrustSelfSignedStrategy())
.build())
.build();
'프레임워크 (Framework) > Spring' 카테고리의 다른 글
[Spring] @Configuration 알아보기 (0) | 2023.11.30 |
---|