IT_Server/Web_Server & WAS

[펌] 아파치 환경에서의 SSL 구성하기

JJun ™ 2013. 6. 24. 03:34

 


제공 : 한빛 네트워크
저자 : Juliet Kemp
역자 : 고현영
원문 : Step by Step: Configuring SSL Under Apache


 

 


 

Introduction

보안 웹 서버에서, 클라이언트는 연결 대상을 알고 트랜잭션(역자주: 정보의 교환)이 암호화되어

보안상 안전하다는 환경하에서 서버에 연결하게 된다. 보안이 유지되는 트랜잭션을 수행하기 위한

최선의 방법은 Apache 2 - 리눅스 웹 서버 소프트웨어의 최신 버전, Secure Sockets Layer-

보안 채널 프로토콜을 이용하는 것이다.

 

차세대 보안 레이어인 Transport Layer Security(TLS) 는 기본개념에서는 SSL과 동일하다.

그러므로 여기서는 SSL을 이용하는 방법을 언급하고자 한다.

SSL은 웹 브라우저와 웹 서버간의 트랜잭션을 암호학적으로 안전하게 보호하기 위한 프로토콜이다.

대부분의 경우 서버쪽만 인증 대상이 된다. 즉 클라이언트는 서버가 누구인지 알 수 있지만

그 반대는 알 수 없다. 왜냐하면 한번 연결이 되면, 양쪽 단은 보안상 안전하게 되고,

클라이언트와 서버는 key material(핵심 데이터)에 접근할 수 있다.

계속 같은 클라이언트와 트랜잭션하게 되면 서버는 클라이언트가 누구인지 더 이상 고려할 필요가 없다.

누가 생각해도 이것은 당연하게 보인다.

 

클라이언트 인증에 대해 고려하고자 한다면, 클라이언트 SSL 인증서(다른 비슷한 방법으로는 htaccess, Kerberos가 있다)를 사용할 수 있지만 여기서는 다루지 않겠다.

우리가 클라이언트의 입장이 되어 보자.

클라이언트로서 우리는 암호화된 데이터를 보내고자 할 때 보내고자 하는 사람(서버)에 대해 알아야 한다.

따라서, 서버는 인증이 되어야 한다. 또한 third party(제 3자)가 우리가 보내는 데이터에 대해 접근하지

못하도록 신경서야 한다. SSL은 이 두 가지 보안 사항에 대하여 지원을 한다.

SSL의 수행 절차는 다음과 같다.

 

  1. 클라이언트는 웹 서버에 접속을 하고 자신이 사용할 수 있는 암호화 방법들을 알려준다.
  2. 서버는 클라이언트가 수행할 수 있는 암호화 방법 중 가장 안전한 방법을 택하여 신뢰할 수 있는 인증 기관(예. Verisign)에서 서명한 인증서를 클라이언트쪽으로 보낸다. 이 인증서에는 인증서 이름과 공개키가 들어있다.
     
  3. 클라이언트는 CA(역자주: Certificate Authority:인증기관)를 통해 받은 인증서를 검증한다. 실제적으로는 클라이언트는 CAs(인증기관들)에 대한 정보를 로컬(역자주: 예. 디스크)상에 가지고 있다. 이렇게 하는 이유는, 네트워크를 통해 CA에 접속하여 인증서에 대한 검증을 하는데 따르는 시간적인 부담을 덜기 위해서다.
     
  4. 클라이언트는 서버의 공개키로 암호화된 random number(임의의 수)를 서버로 되돌려 준다. 이 random number는 오직 클라이언트만 알고 있다. 서버는 클라이언트가 보낸 것을 자신의 개인키로 복호화한다. 이렇게 함으로써 third-party의 접근을 막을 수 있도록 안전함을 보장한다. 
  5. 서버와 클라이언트는 이 random number를 가지고 트랜잭션을 암호화하기 위한 key를 생성한다.

 

 

우리가 관심가질 부분은 위의 방법이 클라이언트 측면에서 좀 더 명확해 지고,

트랜잭션이 좀 더 쉬워지게 하는 것이다.

SSL을 사용해서 Apache를 설정하는 것은 간단한 것이지만, 몇 가지 절차를 밟아야 한다.

이 기사는 CA에 의해 서명된 인증서를 얻는 방법, Apache 컴파일, Apache 설정에 대해 다루고 있다.

여기서는 mod_ssl을 이용한 Apache2를 가지고 설명할 것이다. Apache SSL(SSL을 지원하는 Apache)도 역시 가능하지만 구식 기술이므로 mod_ssl을 사용하도록 하겠다.

 


Creating a Certificate

첫 번째 단계는 인증서 생성이다.

암호문(passphrase)이 있던 없던 인증서를 생성할 수 있다.

암호문를 사용할 때의 가장 큰 단점은 웹 서버를 시작할 때마다 암호문을 넣어야 한다는 것이다.

따라서 자동적으로 부팅이 되지 않는다.

 

예를 들어 전원을 끈 이후에 재 기동할 때 암호문을 넣어주어야 한다는 것이다.

여러분이 구성하는 환경에 따라 이것은 중요한 요소가 될 수 있다.

이론적으로, 암호문를 사용할 때의 장점은 보안을 강화한다는 것이다.

하지만 실제적으로는 그렇게 크게 강화시키지 못한다.

누군가 개인키를 읽거나 복제할 수 있다면, 그 사람은 이미 root 레벨로써 시스템에 접근할 수 있고

암호문을 얻을 수 있다는 것을 의미한다. 예를 들어 ‘keylogger’ 같은 프로그램을 사용한다면 말이다.

암호문은 script kiddies 스크립트 키디(역자주: 해킹 툴을 사용하는 해킹 초보자들을 지칭한다)에 대해서야 보호할 수 있겠지만, 숙련된 해커를 막을 수는 없다. 대부분의 사람이 한 가지 암호문만 사용하지 않는 이유는 이런 것 때문일 것이다.  

테스트 목적으로 혹은 소규모의 LANs에 대해 self-signed(자기 서명)한 인증서를 사용할 수 있다.

(역자 주: self-signed certificate은 말 그대로 자기가 자신을 서명했다는 것으로 자기가 자기를 신뢰한다는 뜻이다. 보통의 경우 어떤 인증서를 신뢰하기 위해서는 그 보다 상위의 신뢰된 CA가 서명을 한다. 보통 Root 인증서가 self-signed certificate 이다. ). 이 인증서는 다음과 같은 명령으로 발행(issue)할 수 있다. 

 

 

openssl req -new -x509 -days 365 -sha1 -newkey rsa:1024
-nodes -keyout server.key -out server.crt
-subj '/O=Company/OU=Department/CN=www.example.com'


 

 

옵션에 대해 살펴보자.

  • -x509 는 인증서가 요청(request)되었다는 의미보다는 인증서가 요구(required)된다는 것을 언급한다. 
  • -days 365 는 인증서가 일년 후에 만료된다는 것이다. 기간을 확장할 수 있다.
    만료기간을 늘리고 싶다면 만료시점을 기억했다가 필요할 때 갱신(renew)하면 될 것이다. 
  • -sha1 SHA1 암호방법을 사용했음을 의미한다.
  • rsa: 1024 RSA의 키 길이를 1024 bit로 두었다는 뜻이다.
    (역자주: 요즘은 1024bit의 안정성 때문에 2048bit로 가고 있는 추세이다. 
                하지만 암호화 연산 시간이 3~4배 늘어난다).
  • -nodes 암호문을 쓰지 않음을 의미한다. 
  • -keyout, -out 인증서와 키의 저장위치를 지정한다. 키는 반드시 root 권한만이 읽을 수 있어야 한다.
    반면, 인증서는 누구라도 읽을 수 있게 한다. 즉 Apache를 사용하는 유저가 읽을 수 있어야 한다. 
  • -subj 이 플래그는 회사 이름, 부서 이름, 웹 사이트 주소를 설정한다.
    이것을 그냥 두면 프롬프트로부터 입력을 받게 된다. CN은 여러분이 적은 웹 사이트의 주소와 반드시 일치해야 한다. 그렇지 않으면 인증서가 일치하지 않게 되고 사용자가 접속할 때 경고 메시지를 받게
    된다. 접속암호를 사용하지 않았나 다시 한 번 확인해 보자. 

 

 

웹 서버에서 self-signed 인증서를 사용할 때의 문제점은 이 웹 서버에 접속하는 어떤 브라우저도 인증서를 발급한 CA를 인식할 수 없다는 것이다. 즉 사용자가 신뢰할 수 있는 인증서인지 아닌지를 판단해야 한다는 것이다. 대부분의 경우 self-singed 인증서를 사용하는 것은 차선책 일 것이다. 그렇지만 테스트 용도이고, 소규모의 LANs이라면 CA로부터 인증서를 사기 위해 돈을 지불하는 것은 쓸데없는 일이다(역자주: 인증서를 사기 위해서는 돈을 지불해야 한다. 우리 나라에서 개인이 인터넷 뱅킹을 위해 사용하는 인증서는 무료이지만 다른 목적으로 사용하는 인증서들은 보통 돈을 주고 구입한다.).

대부분의 사용자들은 외부 고객과의 거래를 위해 신뢰된 인증기관인 Verisign(가장 큰 시장 규모를 가진)이나 다른 인증기관에서 인증서를 구입하는 것도 좋을 것이다. 대부분의 브라우저들은 신뢰된 CAs에 대한

정보를 이미 가지고 있기 때문에 클라이언트가 접속을 할 때 해당 CA에 접속하여 웹 서버의 인증서를

검증해 줄 것이다. 이런 것은 엔드유저가 접속과 관련된 처리에 따른 부가 작업을 줄여줄 것이다.

또한, 인증서 검증을 통해 여러분이 운영하는 사이트가 신뢰받는 사이트임을 엔드유저에게 알려준다.

CA로부터 서명된 인증서를 얻기 위해서는 먼저 키쌍을 생성하고 인증서 요청과 관련된 정보를

생성해야 한다.

 

openssl req -new -sha1 -newkey rsa:1024 -nodes   -keyout server.key -out www.example.com.csr   -subj '/O=Company/OU=Department/CN=www.example.com'

 

 

앞에서 봤던 예제랑 비슷하지만 여기서는 –x509 옵션을 사용하지 않았다.

따라서 인증서생성이 아닌 key와 인증서 요청에 대해 생성할 것이다.

만약 CN이나 기타 항목을 적을 때 명령 줄이 아닌 다른 방법을 쓴다면 email 주소나, 암호를 적어서는

안 된다.

서버 키(server.key-root에 의해서만 읽혀져야 한다)는 웹 서버에 둔다.

요청(www.exapmle.com.csr)은 CA에게로 간다. 원한다면 요청 파일(request file)을 사용할 수도 있지만,

도메인을 사용하는 것이 CA편에서는 처리하기에 편하다.

다음 단계는 CA에게 요금을 지불하고 www.example.com.csr 파일을 보내는 것이다.

여러분이 인증서 요청에 대해 필요한 정보를 잘 적었다면 CA는 가능한 한 빨리 응답을 줄 것이다.

여러분이 선택한 CA의 웹 페이지에서 인증서 발급에 관한 절차를 설명해 줄 것이다.

여러분은 인증서를 PEM format으로 바꾸어야 할지도 모르지만, Verisign 인증서의 경우에는

그럴 필요가 없다.

만약 여러분이 PEM format의 인증서를 받았다면, 이름을 server.crt 로 바꾸자.

(꼭 필요한 절차는 아니지만 Apache에서의 작업의 편의성을 위해 하자).

그리고 받은 인증서를 검증해 보자.

 openssl verify -CAfile /path/to/trusted_ca.crt -purpose sslserver server.crt

 

다음으로, 다음의 두 명령의 결과가 똑같은지 확인해 보자.

즉, 여러분이 가진 개인키에 대응되는 인증서인지 확인해 보는 것이다.

 

 openssl x509 -noout -modulus -in server.pem | openssl sha1 openssl rsa  -noout -modulus -in server.key | openssl sha1

 

 

 

생성한 개인키(server.key)와 인증서(server.crt)를 /etc/apache2/ssl에 설치하자.

여러분이 구성한 Apache2의 구성 디렉토리(config directory)는 이것과 다를 수도 있다.

그러면 그곳에 설치하자.

 

위에서 언급한 바와 같이 server.key는 root권한을 가진 자만이 읽을 수 있게 해야 한다는 것을 명심해라.

(역자주: 이것은 집 열쇠는 집 주인이 가져야만 한다는 것에 비유를 들 수 있다).

 

반면 서버의 인증서는 누구나 읽을 수 있도록 해야 한다. 대신 인증서의 소유와 쓰기권한은 오직 root권한을 가진 자만이 가능해야 한다. (역자주: 개인키와 인증서에 대한 개념은 PKI의 기본 개념을 참고하도록 한다.)

 


Compiling Apache with SSL

인증서가 만들어 졌다. 이제는 인증서를 사용하기 위해 서버를 세팅해 보자.

대부분의 사람들에게, Apache2와 Apache2의 모듈을 다루기 위한 가장 좋은 방법은 여러분의 배포 패키지 운영 시스템(distribution’s package management system)을 이용하는 것이다.

 

Debian Apache2 웹 서버는 SSL 모듈이 가능하도록 나와 있지만 자동적으로 기능이 활성화되어 있지는

않다. 이 모듈을 활성화 하기 위해서는 a2enmod ssl 을 실행해야 하고 웹 서버를 다시 기동해야 한다.

일반적인 방법은 /etc/apache2/apache2.conf(별칭: httpd.conf )에 다음을 삽입하는 것이다. Include /etc/apache2/mod_ssl.conf

여러분의 mod_ssl.conf 설정에 따라 위의 위치는 바뀌어야 할 것이다. 그리고 웹 서버를 다시 기동한다.

여러분이 Apache2를 소스에서 컴파일하기 바란다면, SSL에 대한 지원을 하게 했는지 안 했는지의 여부보다, 여러분이 전에 사용했던 옵션이 컴파일에 더 큰 영향을 준다. apache2 -l 명령으로 확인해 봐라. 재컴파일이 필요하다면 여러분이 전에 사용했던 모든 옵션에 추가적으로  --enable-ssl 과 --enable-setenvif(이 옵션은 일부 Internet Explorer와의 호환을 위한 것) 옵션을 넣고 ./configure 를 실행해라. 그리고 make를 이용해서 설치해라. 보통 make install  명령을 실행하면 설치가 된다. 설치할 때 소유자와 퍼미션이 올바르게 설정되어 있는지 확인하는 것도 잊지 말기 바란다.

 


Configuring Apache with SSL

이제는 Apache2의 환경 구성을 해야 한다. 여러분이 보안 서버(port 443이용)와 일반(regular) 서버(port 80 이용)를 동시에 운영하고 싶다면 다음과 같이 한다.

 

먼저 서버가 두 포트에 대해 리슨하도록 구성해야 한다. /etc/apache2/ports.conf(debian 인 경우에는 apache2.conf에 들어 있다.)를 수정하거나 /etc/apache2/apaceh2.conf에 다음의 라인을 넣는다. 

 

  Listen 80

 Listen 443

 

 

다음으로, /etc/apache2/sites-enabled/yoursite 을 수정하여 SSL 설정을 사용하도록 한다.

VirtualHosts를 사용해서 일반 서버와 보안 서버를 분리해서 관리하는 것도 시스템 관리적인 측면에서

좋은 방법이다. VirtualHosts 섹션(예를 들어, ServerAdmin)을 제외한 다른 모든 구성과 관련된 사항은 VirtualHosts 양쪽 모두에 적용을 해야 한다. 다음의 박스 안의 내용을 여러분의 설정 파일에 넣도록 해라. 

 

 

# =================================================
# SSL/TLS settings
# =================================================
NameVirtualHost *:443

 

    DocumentRoot "/local/www/ssl_html"

    SSLEngine on
    SSLOptions +StrictRequire

   
        SSLRequireSSL
   

    SSLProtocol -all +TLSv1 +SSLv3
    SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM

    SSLRandomSeed startup file:/dev/urandom 1024
    SSLRandomSeed connect file:/dev/urandom 1024

    SSLSessionCache shm:/usr/local/apache2/logs/ssl_cache_shm
    SSLSessionCacheTimeout 600   

    SSLCertificateFile /etc/apache2/ssl/server.crt
    SSLCertificateKeyFile /etc/apache2/ssl/server.key

    SSLVerifyClient none
    SSLProxyEngine off

   
        AddType application/x-x509-ca-cert      .crt
        AddType application/x-pkcs7-crl         .crl
   

    SetEnvIf User-Agent ".*MSIE.*"  
      nokeepalive ssl-unclean-shutdown  
      downgrade-1.0 force-response-1.0

 

 

 

 

 

위의 구성에 대해서 간략히 설명하겠다.

 

  • SSLEngine은 반드시 활성화해서 서버가 SSL을 사용하도록 한다.
  • DecumentRoot는 가상 호스트(virtual host)에 대해 root directory를 설정한다.
    이렇게 함으로써, 보안상 접근불가한 컨텐트(content)와 일반 컨텐트를 구별한다. 
  • SSLRequireSSL은 여기서의 가상 호스트에 대해 SSL을 사용하도록 규정한다.
    즉, 사용자가 일반 HTTP 요청으로 이 호스트에 접속하지 못하게 한다.
    이 때문에 우리가 ‘보안 root directory’와 ‘일반 root directory’를 구별하는 것이다.
  • SSLProtocol은 TLS v1.0과 SSL v3.0을 제외한 모든 프로토콜을 비활성화한다.
    현재 웹 서버에 대해서는 이 정도만 설정하면 된다. 
  • SSLCipherSuite는 HIGH, MEDIUM 레벨의 보안 암호 집합(security cipher suites)을 사용하도록
    설정한다. SHA1은 MD5보다 보안상 더 안전하므로 SHA1을 더 추천한다. 
  • SSLCertificateFile과 SSLCertificateKeyFile은 여러분의 인증서와 key파일의 위치를 지정해야 한다.
  • SSLVerifyClient는 클라이언트 인증을 사용하지 않는다면 설정하지 않는다.

 

 

포트 80으로 일반 서버를 돌리기 위하여 환경 파일에 다음 박스 안의 내용을 넣도록 한다. 

 

 
NameVirtualHost *:80
    DocumentRoot "/local/www/html"
    # Host-specific directory setup, options, etc
    # Most of these options are likely to be set outside the VirtualHosts
    # sections.

 

환경 설정 파일을 수정하고 저장한 뒤, 웹 서버를 다시 시작한다.

여러분이 인증서를 생성할 때 암호를 사용했다면, 서버를 다시 시작할 때 인증서 암호를 넣어야 할 것이다.

 


Testing

여러분의 웹 서버에 index.html을 만들어 보자(물론 처음 접속했을 때 뜨는 화면이다).

웹 브라우저의 주소창에 https://www.yoursite.com 을 넣어보자. 그러면 SSL접속이 이루어진 것과 전송된 페이지를 볼 수 있을 것이다. Self-signed 인증서를 사용했다면, 여러분의 브라우저는 서버에 대해 검증할 수 없다는 경고창을 띄울 것이다. 여러분은 인증서를 보고 그 인증서를 사용하는 서버에 대해서 접속을 허락할지를 결정해야 한다. 인증된 기관의 인증서를 사용한다면, 이런 경고는 뜨지 않을 것이다.
‘http://’를 사용해서 보안된 컨텐트에 접속하지 않도록 해라. 그렇게 하면 에러 메시지가 나온다.  

 


Troubleshooting

생각했던 되로 진행이 되지 않으면 먼저 ps -a | grep apache 명령을 사용하여 apache 서버가 돌아가는지 확인해라. 창에 아무 메시지도 나오지 않는다면 apache를 재 기동해서 터미널에 나오는 에러 메시지를 확인하도록 해라.

여러분의 키와 인증서의 퍼미션이 올바르게 설정되어 있는지 확인해라. 또한 테스트 HTML 페이지와 부모 디렉토리의 퍼미션도 올바르게 설정되어 있는지 확인해라.

그 다음으로 로그를 확인해라. 주 서버 로그와 여러분이 설정한 SSL log를 둘 다 확인하도록 해라. 유용한 정보를 얻을 수 없다면 Apache2 구성 파일의 로그 레벨을 “debug”로 바꾸어서 Apache2를 재 기동하고 테스트를 해 보자. 이렇게 하면 더 많은 정보를 얻을 수 있다.

포트 80으로 일반 웹 서버를 기동하고 있다면 ‘https://’가 아닌 ‘http://’로 테스트 페이지를 접속해 봐라. 이렇게 하면 문제가 웹 서버 문제인지 아니면 SSL 접속문제인지를 파악하는데 도움을 준다. 위에서 구성한 설정을 확인해라. 웹 서버의 root directory는 ‘http://’와 ‘https://’에 대해 서로 다르다. 따라서 여러분은 같은 컨텐트에 접속할 수 없다(접속해서도 안된다). 여러분의 테스트 페이지가 ‘http://’ 의 root directory에서 잘 동작하고 ‘https://’의 root directory에서 잘 동작하지 않는다면 문제의 핵심을 파악할 수 있을 것이다.

SSL 커넥션 문제였다면, 유용한 툴로는 s_client가 있다. 이것은 TLS/SSL 커넥션 문제에 관한 진단 툴이다. /usr/bin/openssl s_client –connect localhost:443 명령을 하면 간단하게 이 툴을 사용해 볼 수 있다. 다른 많은 옵션도 있는데 이것은 문서에서 확인해 보도록 해라. 여러분이 에러 메시지를 받았다면, 문제를 찾는데 도움이 될 것이다.

 


Conclusion

축하한다! 여러분은 최신의 브라우저를 통해 검증할 수 있는 인증서를 가진 보안 서버를 갖게 되었다.
저자 Juliet Kemp는 어떤 역경을 만나더라도 극복할 수 있는 방법을 찾아낸 6년 경력의 Linux system 경험자이다. 그녀는 현재 UK(United Kingdom)의 런던 소재의 Imperial College의 Astrophysics group의 system admin으로서 Linux+Solaris network와 그 사용자에 대해 책임을 맡고 있다.
역자 고현영님은 광운대학교 전자통신공학과, 전자통신공학과 대학원을 졸업하고 드림시큐리티에서 PKI(Public Key Infrastructure) 서버/클라이언트 개발, PKI 시장 동향 분석 업무, 최적화, 여러 상용 DB를 위한 커스터마이징 작업, 시스템 이전 업무를 담당했습니다. 현재는 수펙스테크놀러지에서 근무하고 있으며 NMS(Network Management System) 개발을 담당하고 있습니다. 주요 관심사는 유닉스 기반 네트워크 프로그래밍과 보안 분야입니다.