Cloud/AWS

ALB로 WAF 도입기 (Application Load Balancer 구성)

Omoknooni 2023. 6. 24. 20:22

이전에 pfsense를 통해 간단한 인프라를 구성하고 suricata 패키지로 IDS/IPS 구동까지 진행했었다.

pfsense도 충분히 좋은 솔루션이긴 하지만, 실제로 이런 구성의 인프라를 운영하다 보니 몇가지 큰 문제가 있었다. 

 

1. HTTPS를 적용한 경우 suricata가 트래픽을 정상적으로 분석할 수 없음

이 점이 가장 치명적으로 다가왔었는데, 막상 다 구축해두고 Exploit을 날려보니 suricata의 alert에는 해당 내용이 없어서 계속 확인해 보니 HTTP로 들어온 공격은 잡았지만, HTTPS를 타고온 공격은 잡지 못한 것을 확인했다.

 

관련해서 내용을 찾은 결과, suricata는 ssl inspection을 제공해주지 않는다는 것을 알게되었다.

 

 

SSL inspection(SSL 가시성 확보)

기존의 HTTP 통신이 갖는 서버-클라이언트 통신 시 암호화가 되지않는 문제를 해결하기 위해 SSL Layer를 사용함으로써 서버-클라이언트간의 안전하게 암호화된 연결, HTTPS를 사용하게 되었다.

이렇게 HTTPS의 사용을 통해 전송된 데이터 패킷이 중간에 탈취당해도 암호화된 데이터를 읽을 수 없다.
위 같은 HTTPS의 특징을 이용해, SSL로 암호화된 패킷 내에 바이러스/공격 구문 등을 포함시켜 공격 탐지를 우회하는 경우가 발생하게 된다.
이런 경우를 위해 SSL로 암호화된 패킷의 내부데이터(payload 등)을 검사하기 위해 SSL inspection 기법이 사용된다.

 

 

 

2. SW License관련 비용

해당 운영중인 서비스는 클라우드 환경으로 migration한 것으로 서버 앞단에 보안장비를 두도록 되어있어서 pfsense를 사용했는데, pfsense의 경우 인스턴스 level에서 설치하는 것이 아닌 marketplace를 통해 설치 이미지(AMI)를 받아 사용하고 있었다.

 

근데 이 License 비용이 만만치 않게 나온것이 문제였다.

1달 단위로 봤을 때, EC2 전체 비용과 marketplace(pfsense) SW pricing이 거의 비슷하거나 SW 비용이 조금 더 나왔던 것으로 기억한다.

 

아무리 생각해도 이렇게까지 빌링이 되면서 pfsense를 써야하나라는 생각이 들었고, 클라우드 관련해서 best-practice 인프라들을 더 찾아본 결과, AWS WAF라는 것을 발견했다.

요금계산을 단순하게 생각해도 WAF를 사용한 인프라의 경우 현재에 비해 최소 30%이상 절감되고, pfsense보다 더 다양한 기능(bot control 등)과 HTTPS 트래픽도 문제없이 검사할 수 있다는 점에서 인상깊게 느꼈다.

 

 

FAQ - AWS WAF - Amazon Web Services(AWS)

 

aws.amazon.com

 

ALB 등의 AWS에서 제공하는 로드밸런서나 Cloudfront를 도입해 그 바로 앞단에 WAF를 두어야한다.

가장 보편적으로 사용되는 WAF-ALB 구성을 통해 유해트래픽을 차단해보자

 

 

최종적으로 구성하고자 하는 인프라 구조는 다음과 같다

 

우선 이번에 새롭게 도입할 ALB라는 것에 대해 조금 알아보자

ALB(Application Load Balancer)는 AWS 에서 제공하는 Elastic Load Balancer의 한 종류로 OSI 7계층의 Application Layer 레벨에서 동작하는 Load Balancer이다.

즉, Application Layer인 HTTP(S) / 웹 소켓과 같은 request들을 Load Balancing해주는 서비스다.

 

이러한 로드밸런싱 서비스를 이용하는 이유는 크게 트래픽 분할을 통한 부하분산, 서비스 장애 대비 등이 존재한다.

로드밸런싱에 대한 자세한 정리는 네트워크 개념 정리에서 마저하는 것으로 하고 ALB를 도입함으로써 얻을 수 있는 이점들을 확인해보자

 

1. 트래픽 분산

이는 곧 로드밸런서의 특징이며, 하나의 인스턴스가 죽어도 지속적인 Health Check를 통해 다른 살아있는 인스턴스로 트래픽을 넘겨준다.

 

2. SSL 인증서 활성화 가능

이 부분이 생각보다 크게 와닿았었는데, AWS의 자체적인 인증서 제공 서비스(ACM)을 통해 ELB나 Cloudfront같은 AWS 서비스에 SSL 인증서를 달 수 있다.

당연히 SSL 인증서를 발급받기 위해 도메인이 있어야하며, 도메인 레코드를 수정할 수 있어야한다.

 

 

ALB를 생성하기 전, VPC와 인스턴스 설정을 먼저 해준다. 환경들은 다음과 같이 생성해주었다.

 

VPC

로드밸런서의 사용을 위해 2개의 가용영역을 설정해주었다.

VPC 생성에서 간단하게 VPC 설정을 한번에 완료할 수 있다.

 

인스턴스

인스턴스는 각각 private1, private2 서브넷에 넣어 외부로부터 직접 접근을 제한한다.

 

 

다음으로 로드밸런서가 바라볼 대상 그룹을 설정해준다. (대상 그룹 : 외부로부터 로드밸런서의 트래픽이 전달될 곳)

 

대상 유형 : 로드밸런서와 연결될 대상의 유형, 인스턴스, IP주소, Lambda 함수

우리는 처음에 생성한 Private Subnet의 인스턴스 2개를 연결해줄 것이므로 인스턴스 유형을 선택했다. 

 

로드밸런서에 연결된 대상 그룹은 지속적으로 상태검사(Health check)를 진행한다.

로드밸런서와 내부 서비스간의 연결문제나 내부 서비스 자체가 문제가 되는 경우(서비스가 죽는 등), health check failed로 간주해 로그를 남긴다. (이후 Cloudwatch와 연계가능한 부분)

바로 밑의 고급 상태검사 설정에서, 이러한 상태검사를 상세화해 설정할 수 있다.

(검사시 타임아웃 시간 설정, 검사 성공으로 판단할 응답코드 등)

 

다음으로 대상 그룹에 포함될 연결대상을 지정해준다.

'선택한 인스턴스를 위한 포트'에서는 해당 인스턴스에 오픈되어있는 서비스의 포트를 적어준다

(인스턴스에서 80으로 웹서비스를 열었으면 80, 8080으로 tomcat 등을 열었으면 8080 등등...) 

 

대상그룹을 생성하면 아래와 같이 대상들의 상태확인을 할 수 있다.

현재는 대상그룹 생성만 하고 연결은 하지 않았기 때문에 unused로 나타난 것을 볼 수 있다.

 

다음으로 로드밸런서를 생성하고 방금 만들어준 대상그룹을 연결해준다.

EC2 > 로드 밸런싱 > 로드 밸런서, 로드밸런서 생성에서 Application Load Balancer를 선택

 

다음으로 로드밸런서 생성 탭으로 넘어온다

 

기본 구성

- 로드밸런서 이름

- 체계 : 인터넷 경계

- IP주소 유형 : IPv4

 

인터넷 경계 위치로 로드밸런서를 생성해야 외부 인터넷에서 이 로드밸런서를 바라볼수 있고, 로드밸런서를 통해 내부의 인스턴스(대상그룹)으로 트래픽을 전달할 수 있다.

 

네트워크 매핑

- VPC : 위에서 생성한 VPC를 선택

- 매핑 : 로드밸런서로 들어온 트래픽이 라우팅될 가용영역을 지정해주는 부분

생성할 로드밸런서가 인터넷 경계 위치에 존재하므로, public subnet으로 지정

 

다음으로 로드밸런서의 보안그룹을 지정 후, 로드밸런서가 리스닝을 할 포트라우팅될 대상을 지정해준다

리스닝포트와 대상그룹 포트는 자칫 햇갈릴수 있는 항목이므로 다음과 같이 정리한다.

리스닝포트 : 로드밸런서가 리스닝, 로드밸런서로 들어오는 포트
대상그룹 포트 : 로드밸런서가 대상그룹으로 라우팅, 대상그룹으로 지정한 항목으로 들어오는 포트

리스닝 포트를 8081로 지정하고 로드밸런서를 생성해본다.

(물론 로드밸런서의 보안그룹에서도 8081을 열어줘야한다)

 

로드밸런서를 생성 후, 몇 분 이내로 활성화가 되며 부여된 DNS 이름을 통해 접속할 수 있다.

 

로드밸런서의 리스너 포트를 8081로 열었으므로, 로드밸런서 DNS에 8081로 접속할 수 있는 것을 볼 수 있다.

또한, 새로고침 시 마다 대상그룹의 각 인스턴스로 로드밸런싱이 되고있는 것도 볼 수 있다.

 

이렇게 2개의 private 서브넷에 위치한 인스턴스 2개를 로드밸런서로 연결하고 외부 접속까지 확인해 보았다.

다음 글에서 생성한 로드밸런서 위에 WAF를 추가해본다.