ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [AWS]EC2 톰켓(tomcat) https (SSL) 보안 연동
    Back-end 2014. 9. 5. 22:31
    728x90
    overview

    아마존 AWS를 이용해서 서버를 구축할때 HTTPS로 보안적용을 해보자.

     
    기본 서버 구축환경은 아래와 같이 되어 있다고 가정한다.


    간단히 설명하자면 최초 요청을 받는 곳은 로드벨런서(ELB (elastic load balancer))이고, ELB가 자기와 연결된 EC2 인스턴스에 설치되어 있는 웹 서버(nginx)로 요청을 넘긴다. 웹서버는 다시 웹 어플리케이션 서버(tomcat)로 요청을 넘겨 최종적으로 요청을 처리하게 된다.
    이미지등 단순 리소스는 웹서버(nginx)가 처리하고 그외 어플리케이션 로직 처리는 웹 어플리케이션 서버(tomcat)에서 할 수있도록 하는 구조이다.



    이과정에서 HTTPS 설정은 로드벨런서에서도 할 수 있고 웹서버에서도 할 수 있고 웹 어플리케이션 서버에서도 할 수 있다.

    어디에 설정하는것이 적절한지에 대한 판단은 개발자의 취향일 수도 있고, 서비스가 설치되는 고객사의 규칙에 따를 수도 있다.
    책임자의 스타일에 따라서 각 스타일에 대한 호불호가 갈릴것이다.


    이번 글에서는 아마존 웹 서비스를 최대한 활용하기 위해 로드 벨런서(ELB)에 http 설정을 해보겠다.
    설정이 완료되면 아래와 같은 구성이 된다.


    달리진 내용은
    1. 클라이언트에서 http로 요청을 날리면 web server (nginx)에서 https로 리다이렉트를 시킨다.
    2. HTTPS 로 요청이 들어왔을 경우에 web application server에서 바로 처리하도록 보낸다.

     AWS 메뉴얼에 보면 ELB 에서 EC2로 요청이 전달되는 과정에서는 해킹이나 인젝
    션등이 불가능하기때문에 ELB 뒤로는 https 같은 별도의 설정을 하지 않아도 안심해도 된다고 설명하고 있다.


    아마존의 웹콘솔 UI를 보면서 작업하기때문에 이해하기 쉽고, 복잡한 SSL 설정 문자들을 어딘가에 복사/붙여넣기 하지 않아도 된다는 장점이 있다


    진행 서버 OS: centOS 6.5



    1. 로드벨런서에 SSL 인증서 등록

    HTTPS는 SSL 인증서가 잇어야만 사용가능하다. 테스트용 사설 SSL 인증서는 openSSL 을 이용해서 만들고 공인 SSL 인증서는 인증서 판매업체에서 구입한다.

    생성/구입이 완료 되면 이를 아마존의 로드 벨런서(ELB)에  등록하는 것으로 SSL 인증서 관련 모든 설정이 완료 된다.

    web server(nginx)나 web application server (tomcat) 에서 설정하는것 보다 간단하고 군더더기가 없어서 좋다.








    2. EC2 인스턴스의 웹 서버 (nginx)로 들어온 요청을 https로 리다이렉트 하도록 설정

    위 그림과 같이 되기 위해 web server(nginx)에서 일반 http로 들어온 요청을 모두 https 로 요청하도록 되돌려 보낸다.

    nginx의 설정 파일을 연다. (yum 으로 설치시 기본 경로: /etc/nginx/conf.d/default.xml)

    location 설정에 아래와 같이 추가한다.

    location / {
        ....
        rewrite ^ https://$server_name$request_uri? permanent;
    }



    rewrite는 리다이렉트 와 같은 의미로
    rewrite ^ https://$server_name$request_uri? permanent; 의 의미는 들어오는 모든 요청을 https로 리다이렉트 시키라는 의미이다.
    별도의 설정없이 이렇게만 하면 리다이렉션 순환 오류가 발생한다. 

    들어오는 요청을 https로 리다이렉트 하고 또 리다이렉트 하고를  계속 반복 하기 때문이다.



    (만약web server(nginx)에서 https로 들어온 요청만 골라서 8080으로 보낼 수 있는 방법이 있다면 설정이 훨씬 간단해 질것이다.
    rewrite의 적용 경로를 정규식 방식으로 지장 할 수 있기 때문에 rewrite ^https https://$server_name$request_uri? permanent;
    와 같은 설정으로 처리가능할것으로 생각하였으나, ELB에서 nginx로 요청이 넘어올때https도 http로 넘어오기때문에 nginx에서는 https인지 확인이 불가능하였다.
    이와 같은 이유로 3, 4, 5번과 같은 추가 처리가 필요하였다.

    https요청만 골라서 바로 8080 포트로 포워딩 되도록 처리가 가능한 분은 연락을 부탁드린다.)


    만약 특정 경로만 https가 되어야 한다면 아래와 같이 해당 경로의 location 설정을 추가 하면 된다.

    location /<특정경로> {
        ....
        rewrite ^ https://$server_name$request_uri? permanent;
    }






    3. 로드 벨런서에서 HTTPS 포트 (443) 는 EC2의 8080 포트로 포워딩

    위에서 SSL 인증서가 등록된 로드 벨런서의 리스너에 HTTPS(443) -> 8080 규칙을 추가한다.

    아래와 같이 될것이다.


    이 설정을 통해서 2번의 과정으로 https로 리다이렉트 된 요청이 8080의 web application server (tomcat)으로 바로 전달되면서

    리다이렉션 순환오류가 발생하지 않고 https 로 들어온 요청은 web application server (tomcat)가 처리하게 된다.




    4. EC2 인스턴스의 시큐리티 그룹 설정(방화벽)

    만약 EC2 인스턴스에서 8080 포트의 방화벽이 열려 있지 않으면 로드벨런서(ELB)에서 8080의 web application server(tomcat)으로의 
    요청전달이 되지 않는다. 로드벨런서(ELB)와 연결된 EC2인스턴스의 시큐리티 그룹에서 8080포트를 열어준다.

    위와 비슷한 상태가 될것이다.


    참고로 EC2 인스턴스의 OS에서 방화벽이 켜져있다면 그쪽에서도 위와 같이 설정해야 한다. 아니면 위와 같이 아마존에서 포트관리를 해주므로 OS 방화벽은 꺼두어도 될듯하다.
    centOS 기본 방화벽 끄는 방법
    쉘에서 아래와 같이 실행.

    service iptables stop
    chkconfig iptables off




    5. EC2 인스턴스 웹 어플리케이션 서버(tomcat)에 로컬에서만 접속 가능하도록 설정

    4.번 과정까지 하고 나면 완벽하게 설정이 끝난것 처럼 보인다. 도메인으로 http로 접속하는것이 불가능 하기 때문이다.

    그러나 한군대 구멍이 있었다. 바로 EC2 인스턴스의 아이피로 웹 어플리케이션 서버 바로 접속하는 것이다.  도메인으로는 ELB의 8080이 막혀 있기때문에 접속이 불가능하지만 EC2 인스턴스의 8080 포트가 열려 있기때문에 EC2 인스턴스의 아이피로 직접 요청하면 8080포트 접속이 가능하다!

    누군가 아이피로 직접 접속후 중요한 정보를 담은 데이터를 주고 받는 다면 보안에 결함이 생길 수 있게 된다.

    이것을 해결하는 방법으로 tomcat의 특정 IP/호스트에의 접속을 허용/차단 할 수 있는 request filers 기능을 이용한다.




    • remote address filter: 특정 IP의 접속 허용/차단
    • remote host filter: 특정 도메인 주소의 접속 허용/차단

    위와 같이 두가지방법이 있는데 이번에는 remote address filter를 이용해서 진행을 해본다.

    추가할 코드

    <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="<IP>" deny="<IP>" />


    allow: 접속 가능한 클라이언트의 IP를 명시. "," 로 분리된 regular expression 패턴.
    allow값이 명시되어 있는 경우 접속 클라이언트의 IP가 패턴과 일치할 경우에만 접속 가능.
    명시되지 않으면 deny 패턴에 일치하지 않을 경우에 접속 가능.

    deny: 접속 허용하지 않는 클라이언트의 IP를 명시. "," 로 분리된 regular expression 패턴.
    deny 값이 명시되어 있는 경우 이 패턴과 일치하지 않는 클라이언트 IP만 접속 가능.
    명시되지 않으면 allow 설정을 따름.


    위의 코드를 톰켓 설정 방버에 따라 server.xml이나 context.xml 파일에 추가 한다.

    server.xml
    위치 <톰켓 홈 경로>/conf/server.xml 파일의 해당<Host> 안쪽

    context.xml
    어플리케이션 war 파일의 /META-INF/context.xml 파일의 <Context> 안쪽


    아래는 server.xml에 설정한 예이다.

    ...

    <Host name="localhost"  appBase="webapps"
                unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="<허용 아이피>" />

            <!-- SingleSignOn valve, share authentication between web applications
                 Documentation at: /docs/config/valve.html -->
            <!--
            <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
            -->

            <!-- Access log processes all example.
                 Documentation at: /docs/config/valve.html
                 Note: The pattern used is equivalent to using pattern="common" -->
            <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                   prefix="localhost_access_log." suffix=".txt"
                   pattern="%h %l %u %t &quot;%r&quot; %s %b" />

          </Host>

    ...


    위의 <허용 아이피>에 ELB의 아이피를 적어 주면 된다. ELB -> web server -> web application server (tomcat)의 경로를
    통해 들어온 경우만 접속을 허용해 주어야 한다. 

    AWS 관리 콘솔에는 ELB의 도메인 주소만 나와있고 아이피는 나와 있지 않아서 허용할 아이피를 알기 어렵다.
    이때 톰켓의 엑세스 로그를 보면  어떤 IP를 통해서 들어오는지 확인할  수 있다.


    엑세스 로그 파일의 경로

    <톰켓 홈 경로>/logs/<host 주소>_access)_log.<로그날짜>.txt


    위 파일을 감시하면(tail -f) 도메인 주소로 ELB를 통해 들어오는 요청의 IP를 확인할 수 있다. 참고로 ELB의 IP는 일정하지 않았지만 앞의 두단계 까지는 변하지 않는 것으로 확인 되었다.


    그래서 allow="xxx.xxx.*" 이런식으로 처리하고 톰켓을 제시작하면 이제ELB를 통해서만 접속이 가능하고,  EC2 IP:8080으로 접속이 불가능해진다.
    (ELB의 아이피는 만들때 마다 다를 수 있으므로 직접 확인해보자.)


    이렇게 해서 HTTPS로 완벽 설정 끝!











Designed by Tistory.