Local

이 글에서는 로컬 환경에서, 즉 'development' Profile 에서 https 통신을 설정하는 방법을 다룬다.

1. keystore file 생성하기.

keystore file 의 format은 java에서만 쓰이는 JKS 방식과, PKCS12 방식이 있다.

후자가 업계 표준이고, 최근 권장되고 있다.

keystore 생성하기

아래의 두 방식 중 하나를 택한다.

아래 명령어를 입력하면 앞으로 해당 keystore를 사용하기 위한 비밀번호를 설정하게 된다.

또, 이름, 주소 등 부가 정보를 설정하게 되는데, 사실상 개발단계에서 비밀번호를 제외한 이런 타 정보들은 필요 없으므로 엔터를 눌러 패스하면 된다.

  • .jks 파일(JKS 방식) 생성
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650
  • .p12 파일(PKCS12 방식) 생성 info.mama.software
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
keystore 내용보기
  • JKS 방식
keytool -list -v -keystore keystore.jks
  • PKCS12 방식
keytool -list -v -storetype pkcs12 -keystore keystore.p12
keystore.jks 를 keystore.p12 로 바꾸기
keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12
keystore.p12 를 keystore.jks 로 바꾸기
keytool -v -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS
.crt 파일 생성하기

.jks 파일로부터 다음 명령어로 .crt 파일을 생성할 수 있다. 이때, alias (아래에서는 tomcat)를 나중에 사용하게 된다.

keytool -export -keystore keystore.jks -alias tomcat -file mama.crt

2. Spring Boot 에 keystore file 넣고, 호환 설정하기.

keystore 파일을 프로젝트의 root 또는 resources 디렉토리 아래에 위치시켜 classpath 의 범위에 위치시킨다.

트여기서는 resources 디렉토리 아래에 위치시켰다고 가정한다.

아래와 같이 설정시 spring boot 가 keystore 파일을 인식하여 https request 가 가능하게 된다. 그러나, 우리가 만든 self-signed certificate 는 공인된 Certificate Authority(CA) 가 인정한 것이 아니므로, 브라우저는 경고를 표시할 수 있는데, 개발 환경이므로 패스하면 된다.

또한, 추가적으로 설정한 property인 security.require-ssl=true 로 인해, http 는 거부되게 된다.

security:
  require-ssl: true # http 프로토콜 접근을 불허한다. 
server:
  ssl:
    key-store-type: PKCS12 # either JKS(java specific) or PKCS12(industry standard) : PKCS12-type is recommended to use
    key-store: classpath:keystore.p12 # The path to the keystore containing the certificate
    key-store-password: mamamoo # The password used to generate the certificate
    key-alias: tomcat # The alias mapped to the certificate

3. http request 를 https request 로 redirect 시키기.

기본적으로 spring boot 는 properties 파일로(application.yml) 설정할 수 있는 connector 를 단 하나로 한정지어 놓았다. 그래서 https 를 사용하면 기본으로 존재하는 하나의 커넥터는 https 연결에 사용된다고 한다. 그래서 connector 를 하나 더 만들어서 http 프로토콜 용으로 따로 설정하려면 직접 프로그래밍하는 방식으로 설정한다. 여기서는 http 프로토콜 전용 connector 를 추가로 만들어 https 로 리다이렉트 시킨다. (예를들어, http://localhost:8080https://localhost:32222 로 redirect 된다.)

package io.mama.index.profile.development;

import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("development")
public class ConnectorConfig {
    @Value("${server.port}")
    private int port; // 32222

    @Bean
    public EmbeddedServletContainerFactory servletContainer() {
        final TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                final SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                final SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(getHttpConnector());
        return tomcat;
    }

    private Connector getHttpConnector() {
        final Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(8080);
        connector.setSecure(false);
        connector.setRedirectPort(port); //32222
        return connector;
    }
}

4. 인증서 import 하기

JDK 가 self-signed 인증서를 신뢰하도록 keystore에 추가하기

먼저 .crt 파일이 필요하다. .crt 파일을 아래 명령어로 JDK 에 import한다.

(${JDK_HOME} 으로 명시한 path 는 intellij 에서 Project Structure > SDK 에서 찾을 수 있다.)

sudo keytool -import -trustcacerts -keystore ${JDK_HOME}/jre/lib/security/cacerts \
   -storepass changeit -noprompt -alias tomcat -file /생략/mama.crt

실제 우분투에서 사용한 예시는 아래와 같다.

sudo keytool -import -trustcacerts -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts \
-storepass changeit -noprompt -alias tomcat -file \
/home/user/문서/projects/mamaProjects/mamaIndex/src/main/resources/mama.crt
크롬 브라우저가 localhost 에서 안전하지 않은 연결을 신뢰하도록 하기
chrome://flags/#allow-insecure-localhost

크롬을 사용한다면 위의 옵션은 켜 준다.

트브라우저가 CA가 발급하지 않은 인증서를 신뢰하도록 하기

위 옵션을 켜는 것은

~~IDE가 sudo 로 실행되도록 하기. ~~
(경고, gksu 사용시 완전히 프로그램이 새로운 설정으로 초기화되어 시작한다.
또한 직접 사용해 본 결과, https를 local IDE에서 실행하는 테스트를 위해 gksu는 필요하지 않은 듯 하다.)

만약 IDE가 sudo 로 실행되지 않는다면 test를 실행하는 중에 오류가 발생할 수 있다.

나는 http + 8080 포트를 핸들링하는 Connector 를 만들었고, 테스트도 잘 통과 하는 것을 확인했었다. 그러나 인증서를 추가하고 application.yml 을 위처럼 수정하고 난 후, test 를 수행하니 8080 포트가 이미 사용 중이라는 오류가 발생했다. 이는 IDE 가 sudo 권한으로 실행되지 않아서 인증서를 인식조차 할 수 없다서 생기는 에러라고 한다.

따라서 intellij.desktop 파일의 내용에서

Exec="/opt/intellij/bin/idea.sh" %f

부분을 아래와 같이 변경한다.

Exec=gksu /opt/intellij/bin/idea.sh

그 후 gksu 를 설치한다.

sudo apt-get install gksu
출처
https://www.thomasvitale.com/https-spring-boot-ssl-certificate/

results matching ""

    No results matching ""