메뉴 건너뛰기

Cloudera, BigData, Semantic IoT, Hadoop, NoSQL

Cloudera CDH/CDP 및 Hadoop EcoSystem, Semantic IoT등의 개발/운영 기술을 정리합니다. gooper@gooper.com로 문의 주세요.


*출처 : https://blog.lael.be/post/5107


웹은 계속 발전하고 있으며, 여러 새로운 기술이 끊임 없이 등장하고 있다.

이 글에서는 웹 기술 중 하나인 SSL (Secure Socket Layer) 에 대해서 이야기 해 보고자 한다.

ssl1

< 그림 : OSI Model 에서 SSL 의 위치 >

 

정확히 말해서 SSL 은 전송계층과 (Transport Layer) 응용계층 (Application Layer) 사이에서 동작한다. Transport 에서 패킷을 받으면 -> SSL 에서 패킷의 암호를 해독하고 -> Application 에게 전달하는 것이다.

SSL 을 세션계층(Layer 5), 표현계층(Layer 6)으로 분류하는 사람도 있고, 응용계층(Layer 7)으로 분류하는 사람도 있다. 나름대로 주장에 대한 근거가 일리 있으니 여기서는 따로 정확히 분류하지는 않겠다. 확실한건 Transport 와 Application 의 사이라는 것.

 


I) 어떻게 SSL 은 암호화 통신을 하는가?

- 쉽게 말하자면 SSL 은 “보안인증서” 라고 말할 수 있다.

- 사람으로 비유하자면 보안인증서 암호화코드가 내장된 주민등록증이라고 볼 수 있다.
요즘 대부분의 편의점이나 술집에서는 주민등록증 진위여부 판독기를 가지고 있다.

- 암호학에서 “비대칭키 암호화 방식” 이라는 것이 있다. 어떤 문자를 A 로 암호화하면 B 로만 해독할 수 있는 것이다.
일반적으로 암호화에 사용하는 것을 “암호화키” 라고 부르며 이것은 암호통신에서 공개되기 때문에 “공개키” 또는 “공개 암호화키”, “Public Key” 라고도 부른다.

참조 (RSA_암호) : https://ko.wikipedia.org/wiki/RSA_%EC%95%94%ED%98%B8

ssl2

[1] 클라이언트가 서버에 접속한다.

[2] 서버가 보안인증서를 제공한다.

[3] 클라이언트가 서버가 제출한 보안인증서의 유효성을 파악한다. 최상위 발급 기관과 통신하여 유효성을 확인한다. (최상위 발급기관은 운영체제 또는 웹브라우저에 미리 정의되어 있다.)

ssl-161024

< 그림 : 서버에서 제공한 인증서가 유효하지 않다면 클라이언트는 검증오류로 인해 통신을 중단한다 >

[4] 보안인증서가 유효하면 인증서에 쓰여져 있는 공개 암호화키 A 를 사용하여 클라이언트 자신의 공개 암호화키 C 를 암호화 하여 전송한다.

[5] 서버는 전송된 암호화 구문을 자신만 가지고 있는 해독키(개인 비밀키) B 를 통해서 해독한다.

[6] 해독한 메세지가 유효한 요청이고 클라이언트의 공개 암호화키 C 를 포함하고 있다면 암호화키 C 를 사용하여 잘 받았다는 메세지를 암호화해서 응답한다.

[7] 클라이언트는 자신만 가지고 있는 해독키(개인 비밀키) D 를 통해서 해독한다. 서버에서 받은 응답 메시지가 유효하다면 클라이언트는 A 를 통해 암호화해서 메세지를 보내고, 서버는 C 를 통해 암호화해서 메세지를 보낸다. A키로 암호화된 메세지는 B키로만 해독이 가능하고, C키로 암호화된 메세지는 D키로만 해독이 가능하므로 서로 종단간(End-to-End) 암호화 통신이 성립하는 것이다.

 

SSL이 적용된 사이트는 “종단간 암호화” 가 적용되기 때문에 중간 패킷 감청으로부터 안전하다. (해독키가 없으므로 메세지 해석이 불가능.)

 

보안인증서(SSL) 최상위 발급기관은 매우 많으며, 전세계 점유율은 다음 표와 같다.

참조 : https://en.wikipedia.org/wiki/Certificate_authority

market

< 그림 : World SSL Issuer Market Share >

참고로 이 블로그는 점유율 7위의 StartCom 보안인증서를 사용하고 있다.

mac-ssl

 


최상위 발급기관중 하나인 Let’s Encrypt 를 사용하여 SSL 을 발급받아 사이트에 적용하는 방법을 설명하겠다.

Let’s Encrypt 는 점유율 0.1% 미만의 인증기관이다.(점유율이 매우 낮음) 하지만 발급절차가 간단하고, 무료이기 때문에 점유율이 점차 늘어나지 않을까 싶다.

Let’s Encrypt의 점유율 (Market Share) : https://w3techs.com/technologies/details/sc-letsencrypt/all/all

 


II) SSL 발급 및 적용 방법

암호화 통신 이론에 대해서 알아보았으니 이제 실제로 적용을 해보도록 하자.

 

인증서 발급 프로그램을 서버에 설치해야한다.

Let’s Encrypt  Ubuntu 16.04 LTS 에서 기본패키지로 추가되었다. 따라서 쉽게 설치할 수 있다.
반면 Ubuntu 14.04 LTS 에서는 기본패키지가 아니기 때문에 몇 줄 더 입력해야 한다.

 

발급, 설치, 적용 방법은 다음과 같다.
모든 단계는 Linux root 계정으로 진행한다.

 

1. 인증서 발급 프로그램 설치하기

- Ubuntu 14.04 일 경우

# cd /root
# wget https://dl.eff.org/certbot-auto
# mv certbot-auto /usr/bin/letsencrypt
# chmod 755 /usr/bin/letsencrypt

start1

 

 

- Ubuntu 16.04 일 경우

# apt-get install letsencrypt

start2

 

2. 인증서 발급 프로그램을 사용하여 인증서 발급받기

인증서는 Domain Control Validation 을 거쳐야 발급받을 수 있다. 당신이 도메인이 없다면 인증서를 발급받을 수 없다.
Domain Control Validation 은 주로 다음의 3가지 방법으로 이루어진다.

참고 : Domain Control Validation 의 3가지 방법 (https://support.comodo.com/?/Knowledgebase/Article/View/791)

Let’s Encrypt 는 위의 도메인 인증방법 중 3번째 HTTP(HTTPS)-based DCV 를 사용하여 인증한다.

명령 실행시 1회에 한해 인증관련 프로그램이 추가설치될 수 있다.
*예제 1 :

# letsencrypt certonly --webroot --webroot-path=/home/ssl-demo-1404/www -d ssl-demo-1404.lael.be

*예제 2 :

# letsencrypt certonly --webroot --webroot-path=/home/ssl-demo-1604/www -d ssl-demo-1604.lael.be

*예제 3 :

# letsencrypt certonly --webroot --webroot-path=/home/banana/www -d banana.com -d www.banana.com

*예제 4 :

# letsencrypt certonly --webroot --webroot-path=/home/laelbe/blog -d lael.be -d www.lael.be -d blog.lael.be -d myhome.lael.be

 

* 명령어 설명

-d 는 도메인명을 지정하면 된다. 최대 100개의 도메인 이름을 지정할 수 있다. (한 인증서가 서로다른 100개의 도메인 인증을 할 수 있음) 일반적으로는 기본도메인과 www 도메인 두개를 지정한다.

-webroot 는 웹인증을 받을 것이라는 것이다. 외부 인증프로그램이 -d 에 지정된 도메인 사이트에 접속한다.

-webroot-path 는 웹루트의 경로이다. 보통 index 페이지가 위치하는 경로이다. 인증 프로그램이 이 경로에 임시 랜덤 파일을 생성하고, 외부 인증프로그램이 이 파일을 접근할 수 있다면 Domain Validation 이 되는 것이다.

 

명령이 실행되면 다음 화면이 표시된다.

비상연락처 : 인증에 문제가 생겼거나, 인증서 만료기간이 가까웠을때 갱신 알림 메일을 수신할 주소이다.

start3

약관에 동의하면 즉시 인증서가 발급된다.

발급에 실패했다면 외부 접속이 문제가 있거나 -webroot-path 를 올바르게 입력하지 않았을 것이다.

 


Let’s Encrypt 인증 오류 발생시 다음의 사항을 확인한다.

다음의 문서로 이동해서
# Allow Lets Encrypt Domain Validation Program
설정이 되어있는지 확인하여라.

Apache 사용자의 경우 : https://blog.lael.be/post/73#apache2.conf
Nginx 사용자의 경우 : https://blog.lael.be/post/2600#myuser1.conf


 

- Ubuntu 14.04 발급성공

start4

- Ubuntu 16.04 발급성공

start5

 

/etc/letsencrypt/live/[인증서명]/ 위치에 발급된다.
cert.pem - 인증서 파일
chain.pem - 인증서 발급자 파일
fullchain.pem - cert.pem 과 chain.pen 을 하나로 합쳐놓은 파일
privkey.pem - 인증암호를 해독하는 개인키


#TIP : 이때 발급된 인증서 파일은 웹서버 인증서(HTTPS), 메일서버 인증서(IMAPS, POP3S, SMTPS), VPN서버 인증서(SSTP), 윈도우 원격데스크톱 인증서(MSTSC), Gitlab, OwnCloud 등의 용도로 사용 할 수 있다. (인증서 만료시 갱신해야하는 번거로움이 생기겠지만..)

ssl5

Apache2 서버에서는 cert.pem, chain.pem, privkey.pem 을 사용합니다.
Nginx 서버에서는 fullchain.pem, privkey.pem 을 사용합니다.

 

Apache2 적용방법 https://blog.lael.be/post/73 13번 항목을 참조한다.

1
2
3
4
5
6
7
8
9
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
 
SSLHonorCipherOrder on
 
SSLCertificateFile "/etc/letsencrypt/live/ssl-demo-1404.lael.be/cert.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/ssl-demo-1404.lael.be/privkey.pem"
SSLCertificateChainFile "/etc/letsencrypt/live/ssl-demo-1404.lael.be/chain.pem"

 

Nginx 적용방법 : https://blog.lael.be/post/2600 16번 항목을 참조한다.

dhparam.pem 파일은 한번만 생성하면 된다.

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
1
2
3
4
5
6
7
8
9
10
11
listen       443 ssl http2;
server_name  ssl-demo-1604.lael.be;
root   /home/ssl-demo-1604/www;
client_max_body_size 10M;
 
ssl_certificate "/etc/letsencrypt/live/ssl-demo-1604.lael.be/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/ssl-demo-1604.lael.be/privkey.pem";
ssl_dhparam "/etc/ssl/certs/dhparam.pem";
 
# Enable HSTS. This forces SSL on clients that respect it, most modern browsers. The includeSubDomains flag is optional.
add_header Strict-Transport-Security "max-age=31536000";

 

3. 인증서 발급 프로그램을 통해 인증서 갱신하기

Let’s Encrypt 는 3개월짜리 인증서를 발급해준다.

즉 인증서를 3개월마다 주기적으로 갱신(renewal)해 주어야한다. 갱신은 만료일 기준 1개월전부터 할 수 있다.

# letsencrypt renew

갱신할 인증서가 있다면 자동으로 갱신 작업을 진행한다.

갱신 작업에는 인증서의 재발급이 이루어진다. (renew = reissue)
동일한 도메인에 대해서, 동일한 인증기관이 여러개의 인증서를 발급할 수도 있다. (모두 유효)

 

4. 인증서 갱신 프로그램 주기적으로 실행하기

큰 부하가 일어나는 것이 아니기 때문에 아무때나 실행해 주어도 큰 문제가 없다.

매주 월요일 새벽 5시 10분에 인증서 갱신을, 매주 월요일 새벽 5시 15분에 웹서버 프로그램 변경사항 적용을 실행하도록 설정한다.

# crontab -e

혹시나 에디터 선택문구가 출력된다면 3번을 누르세요. (재선택 명령어 : select-editor)

 

- Apache2 웹서버를 사용하는 경우

10 5 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log
15 5 * * 1 /usr/sbin/service apache2 reload

q1

 

- Nginx 웹서버를 사용하는 경우

10 5 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log
15 5 * * 1 /usr/sbin/service nginx reload

q2

 

참조 : https://www.ssl.com/article/dv-ov-and-ev-certificates/

참조 : https://community.letsencrypt.org/t/which-browsers-and-operating-systems-support-lets-encrypt/4394

참조 : https://www.bluecoat.com/documents/download/0485e335-7437-4c4e-bfc0-ca5ffc5bfd4d/16f27cf7-5d59-44b4-b17f-fb04acea369f

참조 : https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04

 


번호 제목 날짜 조회 수
381 [shell script] 파일을 한줄씩 읽어서 파일내용으로 명령문 만들고 실행하는 shell script예제 2017.02.21 426
380 [shell script]test.txt에 space로 분리된 내용을 일어들이는 예제 2017.02.21 409
379 spark에서 hive table을 읽어 출력하는 예제 소스 2017.03.09 561
378 spark에서 hive table을 읽어 출력하는 예제 소스 2017.03.09 180
377 spark2.0.0에서 hive 2.0.1 table을 읽어 출력하는 예제 소스(HiveContext, SparkSession, SQLContext) 2017.03.09 284
376 It is indirectly referenced from required .class files 오류 발생시 조치방법 2017.03.09 587
375 spark 2.0.0의 api를 이용하는 예제 프로그램 2017.03.15 275
374 kafka-manager 1.3.3.4 설정및 실행하기 2017.03.20 702
373 nc -l 7777 : 7777포트에서 입력을 받는다. 2017.03.23 422
372 JavaStreamingContext를 이용하여 스트림으로 들어오는 문자열 카운트 소스 2017.03.30 211
371 [메모리 덤프파일 분석] 2017.03.31 262
370 streaming작업시 입력된 값에 대한 사본을 만들게 되는데 이것이 실패했을때 발생하는 경고메세지 2017.04.03 515
369 protege 설명및 사용법 file 2017.04.04 3025
368 Container killed by the ApplicationMaster. Container killed on request. Exit code is 143 Container exited with a non-zero exit code 143 TaskAttempt killed because it ran on unusable node 오류시 조치방법 2017.04.06 646
367 LUBM 개수별 hadoop HDFS data사이즈 정리 2017.04.06 214
366 update를 많이 하면 heap memory가 많이 소진되고 최종적으로 OOM가 발생하는데 이에 대한 설명 2017.04.10 817
365 [jsoup]Jsoup Tutorial 2017.04.11 257
364 [Jsoup]특정페이지를 jsoup을 이용하여 파싱하는 샘플소스 2017.04.18 418
363 Caused by: java.lang.ClassNotFoundException: org.apache.spark.Logging 발생시 조치사항 2017.04.19 519
362 Spark에서 Serializable관련 오류및 조치사항 2017.04.21 5030
위로