Enabling Mutual SSL - WSO2 Identity Server Documentation


클라이언트와 서버 간에 매칭이 되는 인증서를 소유하고 있지 않다면 서로 접근을 아예 거부하는 방법이 필요할 수도 있다. 뭔가 정보 수집을 하는 서버-에이전트 간에 인증된 에이전트에서만 정보를 받아들이게 한다던가 뭐 그런 경우로 쓰고 있는데, 간단하게 구현을 할 때는 HTTP HEADER에 AUTH에 관한 부분을 삽입해서 그걸 체크하거나, 좀 더 복잡한 구현이 필요하다면 해당 헤더에 들어가는 값을 주기적으로 바꿔서 DB등에서 가져오게 한 후 삽입을 하거나 하는 식으로 구현을 하였다. 이 포스팅에서는 TLS/SSL에서 인증서를 검증한 후 실패한다면 아예 접근을 거부하도록 하는 방법을 적어보려 한다.
이와 같은 구현을 하게 되면 웹 브라우저에서 신뢰할 수 없는 인증서이지만 이동하겠냐는 확인을 하거나, insecure SSL 요청을 하여도 응답을 받을 수 없고, TLS/SSL은 전송 계층 레이어의 암호화이므로, 이 방법은 HTTPS뿐 아니라 TCP 소켓 등을 통한 연결에도 적용될 수 있다는 장점이 있다. (kafka와 같은 메시지 브로커에도 내부에 client-auth property를 설정하고 키를 설정하게 되어 있는데 이것과 동일하다)
SSL에 대해 기본적인 사항을 짚고 넘어가면 대충 아래와 같다
  1. PKI
    • Public Key Infrastructure
    • 공개키 암호화 방식을 기반으로 하는 암호화/인증 방식의 총칭
    • 공개키 기반의 인증서 관련 프로세스 및, 관련된 Authority 등을 포함
  2. Public Key
    • 모두에게 공개되는 키
  3. Private Key
    • 특정한 사람만이 알고 있는 키
  4. CA (Certificate Authority)
    • 인증 기관
    • 공개키 기반 암호화를 위한 인증서를 발급, 관리하는 서비스를 제공하는 신뢰할 수 있는 제3자
    • 인증서에 대한 정보를 인증하는 역할 등을 수행함
    • 인증 기관들도 상-하위 관계가 있음. 최 상위 기관을 ROOT CA라고 지칭함
  5. 인증서
    • 인증서에는 암호화를 위한 인증서 소유자의 공개키 정보와 인증서 소유자임을 보증할 수 있는 개인키 서명 등이 포함됨
    • 일반적으로 우리가 발급 받는 인증서는 신뢰할 수 있는 기관이 발급하고, 상위 기관의 서명을 받음
  6. Self-signed 인증서
    • 최상위 인증기관의 인증서는 누군가 더 상위에서 서명을 해 줄 수가 없으므로 스스로 서명을 하여 인증서를 발급함
    • OS나 브라우저등은 신뢰할 수 있는 ROOT CA의 인증서들을 미리 탑재하고 있음
    • 개인이 직접 발급하고 스스로 서명하여 ROOT CA와 같이 행동할 수도 있음
    • 이 때 개인이 직접 발급하고 스스로 서명한 인증서는 ROOT CA 정보가 어디에도 등록되어 있지 않으므로, 신뢰할 수 없는 인증서로 경고가 발생함
    • 이러한 문제를 해결하기 위해서 스스로 ROOT CA를 OS나 브라우저 등에 등록하거나, 인증서 검증로직을 회피하도록 프로그래밍함 (https://springboot.cloud/19 와 같이)
  7. CSR (Certificate Signing Request)
    • 인증서 서명 요청
    • 공개키+인증서에 포함되어야 하는 식별정보(신청자, 적용 대상 도메인 등)를 담은 인증서 발급 요청 정보
  8. SSL 인증서 발급 과정
    • ROOT CA 인증서 생성
      • ROOT CA의 Key로 KeyPair 생성
      • ROOT CA인증서 발급을 위한 CSR 생성
      • CSR에 자신의 KeyPair로 서명하여 ROOT CA 인증서 발급
    • SSL 인증서 발급
      • SSL에서 사용할 KeyPair 생성
      • SSL인증서 발급을 위한 CSR 생성
      • ROOT CA Key로 서명하여 SSL 인증서 발급
  9. Java의 관점
    • keystore : 인증서 및 그와 관련된 개인키를 보관하는 공간. 공개키로 암호화 된 정보가 왔을 때 이 정보를 이용해 통신할 수 있다.
    • truststore : 신뢰할 수 있는 인증서의 목록을 보관하는 공간 (일반적으로 cacerts 파일이 기본 truststore이다, custom truststore에는 custom keystore를 import하여 생성한다)
물론 인증서에 대해서 모두 짚고 넘어가려면 PKI에서 사용하는 RSA나 ECDSA, 그 정보를 암호화하기 위한 AES나 인증서의 정보를 담는 표준 문법인 ASN이나 인증서 저장포맷인 PKCS들에도 다루고 넘어가야하겠지만, 내가 그것을 전체적으로 설명할 실력은 되지 않는 것 같으므로... 궁금하시면 위의 키위드를 바탕으로 더 검색을 해 보시면 되겠다 :)
Client-authentication, 혹은 two-way SSL이라고 불리는 것에 대해서 잠깐 살펴 보자면, https://www.ibm.com/support/knowledgecenter/en/SSRMWJ_7.0.1/com.ibm.isim.doc/securing/cpt/cpt_ic_security_ssl_scenario.htm 에 나와 있는 도식을 참고하자면.
  1. 클라이언트의 인증서와 서버의 인증서를 각각 생성하여
  2. 클라이언트의 신뢰할 수 있는 CA에 서버의 인증서를 추가하고
  3. 서버의 신뢰할 수 있는 CA에 클라이언트의 인증서를 추가하여

    양쪽이 양호 신뢰할 수 없는 경우에는 연결을 거부하는 방법이다.




SpringBoot는 Java기반이므로 java keytool로 생성하는 jks 파일 및 truststore를 사용한다. 이 때 사용하는 keytool 커맨드는 다음과 같다.

:: 서버 용 키 스토어 생성
keytool -genkey -alias gnu-server-key -keyalg RSA -keypass server -storepass server -keystore server.jks -validity 365 -keysize 2048 -dname "CN=localhost,OU=gnu,O=gnu,L=gnu,S=gnu,C=KR"
:: 클라이언트 용 키 스토어 생성
keytool -genkey -alias gnu-client-key -keyalg RSA -keypass client -storepass client -keystore client.jks -validity 365 -keysize 2048 -dname "CN=localhost,OU=gnu,O=gnu,L=gnu,S=gnu,C=KR"
:: Truststore에 인증서를 등록하기 위해서는 X.509로 export가 필요함 (클라이언트)
keytool -export -alias gnu-client-key -keystore client.jks -file client_X509.cer -storepass client
:: Truststore에 인증서를 등록하기 위해서는 X.509로 export가 필요함 (서버)
keytool -export -alias gnu-server-key -keystore server.jks -file server_X509.cer -storepass server

:: 클라이언트 인증서를 서버의 truststore에 등록함
keytool -import -alias gnu-client-key -keystore server.truststore -file client_X509.cer -storepass server
:: 서버의 인증서를 클라이언트의 truststore에 등록함
keytool -import -alias gnu-server-key -keystore client.truststore -file server_X509.cer -storepass client


출처: https://springboot.cloud/20


keytool -importkeystore -srckeystore sslcert.co.kr.jks -srcstoretype JKS -srcstorepass "password" -destkeystore sslcert.co.kr.pfx -deststoretype PKCS12 -deststorepass "password"
* .jks 파일을 .pfx 파일로 변환 저장 (원본 jks 파일 패스워드 필요, 대상 pfx 패스워드 지정)

open ssl 로 server - private + public key 쌍 keystore에 등록 , client 인증서 등록 ---

+) 참고