개발

폐쇄망에서 Web Server와 WAS 분리하기 + Session Clustering

뽀글뽀글 개발자 2024. 6. 13. 14:46

폐쇄망 환경에서 서버 이중화 구현하기

군 부대, 병원, 경찰, 소방, 금율 등의 보안이 중요한 환경은 내부에서만 접근할 수 있도록 페쇄망 환경에서 서버를 운영하는 경우가 많다.

 

목표는 인터넷 연결이 되지 않는 폐쇠망 환경에서 Apache(Web Server)와 Tomcat(WAS)를 분리해서 배포하고 WAS 서버를 이중화 하여 1번 WAS가 다운되더라도 2번 WAS가 이어서 작업을 수행할 수 있도록 서버 환경을 구성하는 것이다.

 

이를 위해서 필요한 것은 Apache가 Tomcat에게 요청을 고르게 분배할 수 있도록 LoadBalancer 역할을 할 수 있어야하며, 한쪽 Tomcat이 다운됐을 때 세션 정보를 유지하기 위해서 Session Clustering을 구현해야한다.

 

또한 웹 서버가 정적 파일에 대한 처리를 담당하고, WAS가 동적 파일을 처리할 수 있도록 요청을 구분해서 처리할 수 있어야한다.

 

폐쇄망
서버 이중화
정적 파일, 동적 파일 요청 분리

 

 


VM 생성

Virtualbox 설치

설치 프로그램 실행 시 C++을 설치하라는 에러가 발생하면 여기서 C++을 설치하고 다시 진행하면 된다.  

 

 

원하는 OS의 .iso 파일 다운 

VM으로 생성하고 싶은 OS의 .iso 파일을 해당 OS의 mirror 사이트에서 다운로드 받는다.

.iso 파일은 CD, DVD 이미지로 OS를 설치하는 부팅 디스크라고 생각하면 된다.

 

현재 예제: Rocky Linux  - Minimal 설치

Rocky Linux는 CentOS가 유로로 바뀌면서 나온 CentOS 기반의 Open Source Linux OS이다. 

 

 

Network mode 설정

현재 예제에서는 폐쇄망이기 떄문에 VM끼리만 통신이 가능하고 외부에서는 통신이 불가능하다.

하지만 개발한 파일을 배포해야하기 때문에 SSH로 외부 접속이 가능해야하고, 제대로 동작하는지 확인해야하기 apache 서버에 접근할 수 있어야하기 때문에 포트 포워딩으로 필요한 요청에 대해서만 VM에 접근할 수 있는 NAT network 방식을 사용한다.

Virtualbox network mode
네트워크 설정 위치
NAT Network 생성

 

 

VM 생성 

다운받은 iso 선택
VM network 설정

 

Rocky Linux VM 생성 시 Checksum 에러가 발생한다면? 

RockyLinux Forum VM 이미지 선택할 때 무인 설치 건너뛰기를 체크하면 된다.

 

체크를 하지 않고 생성했다면?

저장소에서 컨트롤러 IDE에 있는 .iso를 삭제하고 새로 등록하면 된다.

 

 

 

 

OS 설치

전부 확인하고 설치 목적지는 들어가서 완료만 눌러준 다음 root 비밀번호를 설정한다.

이때 ssh를 허용해야 나중에 터미널에서 편하게 작업할 수 있다.

계정을 생성하고 따로 SSH 포트 포워딩으로 접속하면 되겠지만, 계정을 미리 생성해서 작업하면 설정하는 과정에서 권한 문제가 떠서 불편할 수 있기 때문에 마지막에 하는 것을 추천한다. 

 

VM 복제

VM을 여러 개 생성할 때 위 과정 반복하지 않고 기존 VM을 복제해서 사용할 수 있다.

이때 주의 사항은 VM을 종료해야 복제할 수 있는데 종료할 때 현재 시스템 상태 저장을 하면 IP까지 동일하게 복제되는 문제가 발생한다.

따라서 복제를 할 때는 시스템 종료를 눌러서 종료한 다음 복제를 해야한다.

 

 

 


환경 구축을 위한 VM 세팅 

Virtualbox 마우스 커서 탈출

좌측 상단의 파일 -> 환경 설정 -> 입력 - >가상 머신 - >호스트 키 조합 원하는 단축키로 수정

 

 

SSH 연결

 

1. VM IP 확인 및 포트 포워딩

 

2. SSH 접속 

ssh -p [포트번호] [사용자 ID]@[접속하려는 컴퓨터의 IP주소 또는 도메인]
ssh -p 22 root@192.168.56.1

접속이 안되는 경우 C:\Users\사용자 이름\.ssh의 known_hosts를 삭제 후 다시 진행

 

붙여넣기 안될 때

 

 

 

 


Apache 생성

# 아파치 설치
yum install -y httpd

# /etc/httpd/conf가 아파치 설정 파일이 있는 위치이고, httpd.conf가 가장 중요한 설정 파일이다.
vi /etc/httpd/conf/httpd.conf

# vi에서 :/{검색어}를 입력하면 위치를 찾을 수 있다. 대소문자를 구분하기 때문에 정확히 입력해야한다.
# ServerName을 찾은 후 주석을 해제하고 아래와 같이 수정한다.
ServerName 127.0.0.1:80

# 80포트 방화벽에 80포트 허용
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --reload

# 아파치 실행 및 VM 실행 시 자동 실행 설정
systemctl start httpd
systemctl enable httpd

# 아파치 상태 확인
systemctl status httpd

# 포트포워딩으로 80 포트를 연결해준 다음 로컬에서 접속
# ex. 192.168.56.1

 


Tomcat 생성

wget으로 tomcat 다운로드 링크를 넣어 직접 설치하는 방법이 있지만, yum install -y tomcat으로 설치하는 것이 귀찮은 설정을 줄일 수 있기 때문에 예제에선 yum으로 설치를 진행하였다.

# yum으로 설치 시 최신 톰캣과 그에 맞는 JDK가 같이 설치된다. wget으로 설치 시 JDK를 따로 설치해야한다.
yum install -y tomcat

# 톰캣 실행
systemctl start tomcat

# VM 실행 시 자동으로 톰캣 실행
systemctl enable tomcat

# 상태 확인
systemctl status tomcat

 


Apache Tomcat 연결

연동 방법은 mod_jk, mod_proxy, mod_prox_ajp 세 가지가 존재한다. 

이 중에서 가장 쉽고 많이 사용되는 것이 mod_jk이다.

 

mod_jk 설정

mod_jk란 Apache에서 Tomcat으로 요청을 전달하고 응답을 다시 받아오는 기능을 제공하는 모듈로 AJP(Apache Jserv Protocol)라는 프로토콜을 통해서 apache와 tomcat 사이의 통신을 주고 받을 수 있다.

 

Apache 설정

# mod_jk 설치
yum install -y epel-release
yum install -y mod_jk

# workers.propertis에 연결할 WAS 정보 설정 = 아래 내용 추가 
vi /etc/httpd/conf/workers.properties

worker.list=loadbalancer

worker.tomcat1.type=ajp13
worker.tomcat1.host=10.0.2.21
worker.tomcat1.port=8009

worker.tomcat2.type=ajp13
worker.tomcat2.host=10.0.2.22
worker.tomcat2.port=8009

worker.loadbalancer.type=lb
worker.loadbalancer.balance_workers=tomcat1,tomcat2



# mod_jk 설정 아래 내용을 추가하면 된다.
vi /etc/httpd/conf/httpd.conf

LoadModule    jk_module  modules/mod_jk.so
JkWorkersFile /etc/httpd/conf/workers.properties
JkShmFile     /var/log/httpd/mod_jk.shm
JkLogFile     /var/log/httpd/mod_jk.log
JkLogLevel    info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkMount  /*.do loadbalancer


# SELinux를 비활성화 하고 httpd restart.
sudo setenforce 0
systemctl restart httpd

 

Tomcat 설정

# server.xml 설정
vi /usr/share/tomcat/conf/server.xml

# 8009 Connector를 찾아서 아래 내용으로 수정하고 기존 8080포트 Connector를 주석처리
# 8080으로 직접 접속하지 않고 Apache를 통해서 AJP로 요청을 주고 받기 위함
<Connector protocol="AJP/1.3"
               address="0.0.0.0"
               port="8009"
               redirectPort="8443"
               secretRequired ="false"
               />
               
# 방화벽에 AJP 통신할 포트 허용 
firewall-cmd --permanent --zone=public --add-port=8009/tcp	
firewall-cmd --reload
# 방화벽 조회
firewall-cmd --list-all

 

 


War 배포

배포하기 전에 DB datasource를 localhost로 잡았다면 다음과 같이 본인 IP로 변경해줘야하며, SSL을 사용하지 않으면 useSSL과 allowPublicKeyRetrieval도false로 줘야한다.

<property name="url" value="jdbc:mysql://192.168.10.125:3306/session?useSSL=false&amp;allowPublicKeyRetrieval=true" />

 

 

빌드해서 생성한 war 파일을 scp로 tomcat의 webapps에 전송한다.

 -r 옵션을 생략하면 not a regular file 에러가 나올 수 있다.

scp -P {ssh port} -r "{war 파일 경로}" root@{virtualbox ip}:/usr/share/tomcat/webapps/

 

 

server.xml의 <Host> 안에 아래 내용 추가 -> 추가하지 않으면 ROOT 디렉터리를 기본으로 사용한다,

<Context path="/" docBase="{war파일의 이름}"  reloadable="false" > </Context>

 

 

 


세션 클러스터링

Tomcat Clustering Doc

 

프로젝트의 세션 객체는 반드시 Serializable 인터페이스를 구현해야한다.

 

Apache workers.properties에 아래 내용 추가

worker.loadbalancer.method=S
worker.loadbalancer.sticky_session=true

 

Tomcat Server.xml의 <Engine> 내부의 아래 태그 주석 해제

Receiver ip에 VM ip를 적어줘야한다.  

공식 문서에서는 auto로 지정되어있지만 VM에서 ip를 검색해보면 아래와 같이 2개의 네트워크 인터페이스를 가지고 있기 때문에 여러 번 실행했을 때 어떤 경우에는 성공하고, 어떤 경우에는 실패했다.

그렇기 때문에 VM의 IP를 고정으로 주는 것이 더 낫다고 생각된다.

# Engine에 jvmRoute 설정
# 쿠키에 있는 세션 정보가 Session.tomcat1 처럼 표시 되어 어떤 서버에 연결됐는지 파악하기 쉽다
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">


       <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">

          <Manager className="org.apache.catalina.ha.session.DeltaManager"
                   expireSessionsOnShutdown="false"
                   notifyListenersOnReplication="true"/>

          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"
                        address="228.0.0.4"
                        port="45564"
                        frequency="500"
                        dropTime="3000"/>
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
                      address="{본인 VM IP}"
                      port="4000"
                      autoBind="100"
                      selectorTimeout="5000"
                      maxThreads="6"/>

            <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
              <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
            </Sender>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
            <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/>
          </Channel>

          <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
                 filter=""/>
          <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>

          <Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
                    tempDir="/tmp/war-temp/"
                    deployDir="/tmp/war-deploy/"
                    watchDir="/tmp/war-listen/"
                    watchEnabled="false"/>

          <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
        </Cluster>

# 톰캣 세션 송수신을 위해 45564(송신) 포트와 4000~4100(수신) 포트까지 허용해줘야한다.
firewall-cmd --permanent --zone=public --add-port=45564/udp
firewall-cmd --permanent --zone=public --add-port=4000-4100/tcp
firewall-cmd --reload

 

Tomcat webapps의 web.xml에 아래 내용 추가

 <distributable/>

 

 

 

로그 

클러스터링 및 AJP 연동 시 잘 안된다면 로그부터 확인해보고 천천히 해결하면 된다.

 

아파치 로그 파일 위치

/var/log/httpd

 

톰캣 로그 파일 위치

# 날짜별 로그 위치
/usr/share/tomcat/logs

# 원래는 catalina.out에 로그가 나오지만 yum으로 설치하니 .sh 파일도 없고 .out 파일도 없다
# journalctl로 로그를 확인할 수 있다.
journalctl -xeu tomcat.service

 

 

 


계정 관리 

실행 계정

  • 서버가 root 계정으로 실행되고 있을 때 공격을 당하면 root 권한으로 더 치명적인 피해가 발생할 수 있다.
  • 서버 실행 계정을 따로 만들어서 실행해야한다.
  • ps aux | grep tomcat 명령을 통해서 실행 중인 톰캣의 계정과 권한을 볼 수 있으며, yum으로 설치했을 때 따로 설정하지 않아도 tomcat 계정으로 실행되고 있는 것을 볼 수 있다.
  • cat /etc/passwd 명령을 통해 권한을 확인할 수 있다.
  • tomcat:x:53:53:Apache Tomcat:/usr/share/tomcat:/sbin/nologin
    • /usr/share/tomcat에 대한 읽기 권한만을 가지고 있고, login을 할 수 없는 계정이다.
    • 공격을 당해도 해당 계정으로 로그인할 수 없기 때문에 로그인을 했을 때 할 수 있는 명령들을 실행할 수 없다.

 

개발 계정

  • root 계정은 시스템 내부의 설정을 마음대로 바꿀 수 있기 때문에 목적에 맞는 최소 권한만 가진 계정을 생성해서 사용해야 안전하다. 
  • linux의 서버 관리를 한명이 맞는 것이라면 모르지만, 예를 들어 apache 관리자와 tomcat 관리자가 따로 있는 상황이라면 apache 관리자가 tomcat에 접근하고, 수정할 수 있다면 문제가 발생할 확률이 높다.

 

Apache

# 유저 생성
sudo adduser tomcat-dev

# 유저 그룹 생성 및 그룹에 유저 추가
sudo addgroup tomcat-developers
sudo adduser apache-dev tomcat-developers

# 유저의 권한 추가
# chown = 소유자 변경, chmod = 권한 변경,   -R = Recursive = 하위 디렉터리에도 동일하게 적용
# 7: 모든권한, 5: 읽기 및 실행 권한,   3자리는 앞에서부터 [유저, 그룹, 그 외]를 뜻한다.
# 755 = tomcat-dev는 모든 권한, tomcat-developers의 계정들과 그 외 계정들은 읽기 및 실행 권한 
sudo chown -R tomcat-dev:tomcat-dev /var/www/html/myproject
sudo chmod -R 755 /var/www/html/myproject		# tomcat의 권한을 줄 파일로 수정

sudo passwd tomcat-dev

# httpd.conf와 같은 중요한 설정 파일에 대한 권한은 root로 두고 필요할 때 sudo 명령을 사용한다.

 

 

Tomcat ..