https를 사용하기 위한 Jetty + SSL(Let's Encrypt) 적용하는 방법

2023. 2. 9. 13:06IT

728x90

Jetty에서 SSL을 구성하기 위해서 구글링을 많이 해 봤지만, 딱히 이렇게 하면 된다 하는 글들은 많은데 실제로 해보면 하나같이 뭔 오류가 그리 많은지 다 실패했다.

그래서 나같이 단독으로 Linux에 Jetty를 올리고 java로 홈페이지를 구성하는 분들이 이 글을 참고하면 많은 도움이 될 듯하다.

 

성격이 급해서 대충 읽지 말고 첫 줄부터 차근차근 읽어 내려가길 바란다.

내가 성격이 급해서 그렇게 했다가 고생했다.

문서는 항상 정독하는 습관이 필요한 듯하다,,,

그럼 본론으로 들어가서 Jetty에 SSL을 적용해 보도록 하자.

OS는 Ubuntu 기준으로 설치 과정을 설명하겠다.

 

일단 SSL은 유료이고 1년에 몇만 원부터 몇십만 원까지 가격과 서비스가 다양하다.

그럼 우리 같은 일반 개인은 무료를 사용할 수 없는가? 

검색하다 보니 무료가 몇 개 있다. 물론 유효기간이 90일로 정해져 있긴 하지만, 그래도 무료이니 이걸 사용해 보기로 한다.

 

무료 SSL 인증서 Let's Encrypt

장점은 무료, 단점은 90일마다 갱신을 해야 한다.

 

이 문서에 적용된 버전
  • Ubuntu 22.10
  • Jetty 9.4.50
  • java 13.x

 

전체 과정을 간단히 정리하면
  1. Let's Encrypt 설치 
  2. 인증서 설치
  3. 인증서를 PEM 형식에서 PKCS12 형식으로 변환
  4. PKCS12 인증서를 Java 키 저장소 파일로 가져오기
  5. Jetty에 keystore 파일 인식 시키기

 

 

자~~ 시작해 볼까요 ~~
무료 SSL 설치

$sudo apt-get install certbot

 

인증서 설치

certbot certonly --webroot \
 -w {web ContextROOT} -d {domain name}

 

본인의 web context root와 SSL을 적용할 도메인을 적고 인증서 설치를 해야 한다.

web context root를 지정하는 이유는 인증서에 소유 도메인 확인을 위한 임시 파일이 해당 경로에 만들어지고 80 포트로 SSL 서비스 발급 업체에서 해당 파일을 찾기 때문에 web 시작 경로를 지정하는 것이다.

만약 현재 jetty가 구동 중이 아니라면 못 찾으니까 인증서 발급이 안된다. 

반드시 jetty를 구동해 놓고 인증서 설치를 해야 한다.

 

예를 들면 아래와 같이 자신의 경로와 도메인을 입력한다

certbot certonly --webroot \
 -w /home/jetty/webapps -d abc.domain.co.kr

위 명령어로 인증서를 설치하는 과정에서 Email 주소를 입력하라고 나오는데, 이 질의는 SSL 만료 2주 전에 메일로 만료일을 알려주니 입력하는 게 좋다.

 

두 번째 질문으로 나오는 것은 구독할 것인지 물어보는 화면이 나오는데, Let's Encrypt에서 유용한 정보를 메일로 보내줄 테니 받을 것인지 물어보는 것이다. 

일단 Y를 하고 넘어갔는데 N을 했을 때 계속 진행이 되는지는 안 해봐서 모르겠다, 일단 Y를 치고 넘어갔다.

 

Certificate is saved at: /etc/letsencrypt/live/abc.domain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/abc.domain.com/privkey.pem

인증서 설치가 정상적으로 완료되면 인증서를 저장한 경로와 이름을 출력해 준다. 꼭 복사해 놓자.

해당 경로에 가서 보면 fullchain.pem 파일과 privkey.pem이 생성되어 있는 것을 볼 수 있다.

물론 이 두 개 파일 외에 몇 개 더 보이기는 하지만 우리는 이 두 개가 필요하다.

 

 

인증서를 PEM 형식에서 PKCS12 형식으로 변환

pem 형태의 인증서를 pkcs12 형태로 변환해야 jetty로 옮겨 와서 적용할 수 있다.

#cd /etc/letsencrypt/live/abc.domain.com/ 로 이동을 하자. (root 계정)

openssl pkcs12 -export \
	-inkey privkey.pem -in fullchain.pem \
	-out jetty.pkcs12

이렇게 입력을 하면 암호를 물어본다. 6글자 이상으로 암호를 지정해야 한다. 옵션 등을 줘서 암호를 지정 안 할 수도 있는데 암호가 없으면 jetty에서 인증서 적용이 잘 안 된다. 반드시 암호를 지정하자.

이 과정이 끝나고 ls를 해보면 jetty.pkcs12라는 파일이 생겼을 것이다.

 

 

PKCS12 인증서를 Java 키 저장소 파일로 가져오기

방금 만든 jetty.pkcs12 파일을 바로 사용할 수는 없고 한 번의 과정을 더 거쳐야 한다.

keystore 파일을 만들어야 jetty에서 인식할 수 있는데, jetty.pkcs12 파일은 SSL type을 지정하기 위해 만든 것이고 이걸 기반으로 keystore 파일을 만들자

keytool -importkeystore -noprompt \
    -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -srcstorepass p \
    -destkeystore keystore
    
 # 암호까지 했는데 오류가 발생했다면 ...
 keytool error: java.io.IOException: keystore password was incorrect
 기존 keystore 에 뭔가 꼬인거 같다 ㅠㅠ 그래서 아래와 같이 수정해 주었다
 
 keytool -importkeystore -srckeystore jetty.pkcs12 \
 -srcstoretype pkcs12 -destkeystore keystore \
 -deststoretype jks

 keytool을 이용해야 하는데 jdk가 설치되어 있고 path가 잡혀 있으면 keytool을 이용해서 만들 수 있다.

물론 이 과정에서도 암호를 요구하는데 적당한 암호를 6글자 이상 입력한다.

 

생성된 파일들
생성된 파일들

그럼 해당 경로에 keystore 파일이 생긴 것을 볼 수 있다.

keystore 파일은 jetty가 설치된 위치로 복사해 준다.

예를 들면 아래와 같다

cp keystore /home/jetty/etc/keystore

이렇게 jetty의 홈 경로 밑에 etc아래에 keystore 파일이 옮겨졌다.

그런데 이 파일은 root 속성을 가지고 있기 때문에 jetty가 실행하는 유저의 권한을 부여한다.

 

예를 들면 아래와 같다

chown -R username:username /home/jetty/etc/keystore

 

여기까지 왔다면 인증서를 발급받아 jetty가 인지할 수 있도록 모든 과정이 끝났다.

마지막으로 jetty에서 keystore를 알아볼 수 있게 jetty의 설정 파일을 수정해 주면 된다.

 

Jetty에 keystore 파일 인식 시키기

jetty 홈 경로의 etc로 가서 vi로 파일을 편집한다.

 

$vi jetty-ssl-context.xml

 

......
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server">
  <Set name="Provider"><Property name="jetty.sslContext.provider"/></Set>
  <Set name="KeyStorePath">
    <Property name="jetty.sslContext.keyStoreAbsolutePath">
      <Default>
        <Property name="jetty.base" default="." />/<Property name="jetty.sslContext.keyStorePath" deprecated="jetty.keystore" default="etc/keystore"/>
      </Default>
    </Property>
  </Set>
  <Set name="KeyStorePassword">keypassword</Set>
  <Set name="KeyStoreType"><Property name="jetty.sslContext.keyStoreType" default="pkcs12"/></Set>
  <Set name="KeyStoreProvider"><Property name="jetty.sslContext.keyStoreProvider"/></Set>
  <Set name="KeyManagerPassword">keypassword</Set>
  <Set name="TrustStorePath">
    <Property name="jetty.sslContext.trustStoreAbsolutePath">
      <Default>
        <Property name="jetty.base" default="." />/<Property name="jetty.sslContext.trustStorePath" deprecated="jetty.truststore" default="etc/keystore"/>
      </Default>
    </Property>
  </Set>
.....

수정항 부분은

<Set name="KeyStorePassword"> 부분과

<Set name="KeyManagerPassword"> 을 찾아서 위와 같이 keystore의 비밀번호를 수정한다. 원래는 태그가 길게 되어 있는데 뒤에 다 잘라버리고 위와 같이 입력을 해줬다.

 

그리고 우리가 만든 keyStore type 이 pkcs12이기 때문에 <Set name="KeyStoreType"> 을 찾아서 위와 같이 수정해 준다.

 

여기까지가 모든 과정이 끝난 것이고 이제 jetty를 구동해줘야 하는 일만 남았다.

 

만약 keystore 비밀번호를 잊었다면 다시 지정할 수 있다.

#keytool -storepasswd -keystore /etc/letsencrypt/live/abc.domain.com/keystore
Enter keystore password:  현재비밀번호
New keystore password:  새로운 비밀번호
Re-enter new keystore password:  새로운 비밀번호.

 

 

Jetty를 SSL 적용하여 구동하기

jetty를 구동할 때 옵션을 줘서 구동할 수도 있고 start.ini를 수정하여 구동할 수도 있다.

중요한 것은 --module=https 옵션이 활성화되어야 한다는 것과 8443 포트가 열려 있어야 한다는 것이다.

SSL이 443 포트로 통신을 할텐데 자신의 환경이 독립적인 서버에 바로 네트워크가 적용되어 있으면 jetty 설정을 443 포트로 수정해주고 공유기나 스위치에서 jetty를 연결하여 사용하는 경우라면 공유기 쪽의 443포트로 전달받아 jetty의 8443 포트로 설정해 주어야 한다.

 

java -jar start.jar --module=https

jetty가 실행되고 오류가 없다면 로그에 아래와 같은 구문이 표시가 된다.

 

2023-02-09 10:45:53.452:INFO:oejs.AbstractConnector:main: Started ServerConnector@6a03ad8b{SSL, (ssl, http/1.1)}{0.0.0.0:8443}

 

이 메시지까지 잘 나오면 성공.

이제 Https로 홈페이지를 접속해서 사용하면 된다.

 

Test

Jetty를 구동해 놓고 아래와 같이 입력해 보자

# wget https://poem.nullpark.com
--2023-01-09 17:18:44--  https://abc.domain.com/
abc.domain.com (abc.domain.com) 해석 중... 175.xxx.xxx.xxx
다음으로 연결 중: poem.nullpark.com (poem.nullpark.com)|175.xxx.xxx.xxx|:443...
실패: 연결 시간 초과.
다시 시도 중.

아~ 공유기에서 443 포트를 Jetty가 있는 8443 포트로 연결을 안했구나 ~~~ ^^

공유기 설정을 하면 이제 잘 나옵니다

 

브라우저에 적용된 SSL 확인
브라우저에 적용된 SSL 확인

 

참고사항
인증서 남은 기간 확인 방법
#certbot certificates

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: poem.nullpark.com
    Serial Number: 4.......406b1........f1b37a1607
    Key Type: RSA
    Domains: abc.domain.com
    Expiry Date: 2023-01-09 09:51:20+00:00 (VALID: 45 days)
    Certificate Path: /etc/letsencrypt/live/abc.domain.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/abc.domain.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 

자동갱신 명령
# certbot renew

인증서가 만료기 몇일전에 이렇게 해서 갱신한 다음에 keystore 파일을 jetty쪽에 옮겨 놓으면 될듯하다

반응형