소개
안녕하십니까, GS네오텍 최준승입니다.
요즘 보면 써버리스(serverless)한 아키텍쳐 얘기가 간간히 나오는데요. 사실 저는 개발자도 아니고 인프라 엔지니어도 아니고 뭣도 아닌지라 "써버가 없다!" 이상의 의미는 잘 모르겠습니다. 참고로 AWS에서는 람다(Lambda)라는 서비스가 있죠. 단순히 실행 코드만 붙여넣으면 기반 OS환경(EC2)이 없이도 알아서 실행해서 결과값을 반환해 줍니다.
그럼 등록한 Lambda 함수는 누가 실행해줄까요? AWS에서 제공하는 API나 CLI를 써서 수동으로 실행해도 되고, 범용적인 API 형태로 빼고 싶으면 앞에 API Gateway를 구성해도 되겠죠. 만일 비정기적인 실행이 아닌 1시간이면 1시간, 5분이면 5분마다 주기적으로 실행하는 것으로 충분하다고 하면? 바로 Cloudwatch Events의 스케줄 기능을 사용하면 됩니다.
오늘의 목표
오늘의 목표는 Cloudwatch Events와 Lambda를 사용하여 써버 없이 주기적으로 무엇인가를 실행하는 것입니다. 그럼 무엇을 실행해야 할까요? 적합한 일을 생각해 봅시다.
- 주기적으로 실행?
- 주기적으로 갱신?
- 주기적으로 (정책을) 갱신?
- 주기적으로 (보안정책을) 갱신?
- 주기적으로 (WAF정책을) 갱신?
- 주기적으로 악성 IP리스트를 (WAF정책에) 갱신?
하는 것을 오늘 실습하도록 하겠습니다. 마치 제 맘을 누가 미리 읽은 것처럼 누군가 그런 형태를 구현해 놓았습니다.
- How to Import IP Address Reputation Lists to Automatically Update AWS WAF IP Blacklists: 링크
WAF는 AWS에서 제공하는 웹방화벽(Web Application Firewall) 서비스입니다. 현재 Cloudfront 서비스에만 붙일 수 있구요.(변경!: 2017년 1월부터 ELB(ALB)에도 붙일 수 있게 되었습니다.) 일부 사용자들은 오직 WAF를 구성할 목적으로 기존에 사용하지 않는 Cloudfront 계층을 앞단에 구성(+WAF)하고 캐시 정책을 bypass하는 식으로 쓰는 곳도 있다고 하네요. 단, WAF가 서비스 초기 단계이기 때문에 제공하는 기능 범위가 제한적이고 제약사항도 많은 편이라고 합니다. 하지만 점점 개선중이긴 해요. 특정 IP그룹을 지정하여 Block하는 기능 정도는 지원합니다.
동작 흐름
미국 아저씨가 그린 그림을 조금 바꿔서 다시 그려봤습니다.
서비스 흐름은 다음과 같습니다.
- 앞단에 Cloudfront가 있고 백엔드 Origin으로는 S3가 있습니다. (원래 웹서버나 ELB가 있어야 되는데 귀찮아서 S3로 구성함)
- 그리고 해당 Cloudfront 배포에는 WAF의 특정 정책(룰)이 적용되어 있습니다.
WAF 정책 갱신 흐름은 다음과 같습니다.
- Cloudwatch Events에서 주기적으로 Lambda 함수를 실행합니다.
- 지정된 Lambda 함수는 지정한 S3 버킷의 특정 경로에서 IP List를 받아와서 WAF의 해당 정책을 갱신합니다. (이 부분도 원래는 외부에서 수집된 악성IP 리스트를 받아오는 로직이 있는데, 테스트를 위해서 제가 수동으로 목록을 제공하는 형태로 변경했습니다.)
환경 구성
WAF 정책, Lambda 함수 설정, Cloudwatch Events 설정까지는 모두 하나의 Cloudformation 템플릿으로 구성할 수 있습니다.
미국 아저씨 글 링크 주소에는 오타가 있는데, Tokyo Region의 경우 대신 이 링크를 템플릿 URL에 넣어주면 됩니다.
이후 설정항목으로 테스트 편의상 저는 2가지 항목을 수정했습니다.
- IP List가 있는 URL 주소: 제 버킷에 TEXT 파일을 하나 넣어서 해당 파일 주소를 사용
- Cloudwatch events 실행 주기: 1시간에서 2분으로 수정
Cloudformation의 스택 생성이 완료되었습니다. 이제 우리는 2분 주기로 Black IP 리스트를 갱신하는 WAF:WebACL이라는 WAF 정책을 획득한 셈입니다.
이제 미리 만들어 놓은 Cloudfront 배포에 해당 정책을 매핑시켜야 겠죠. 그냥 매핑하면 됩니다. 매핑할 객체 이름은 WebACL입니다.
구성환경 테스트
드디어 모든 테스트 준비가 완료되었습니다.
우선 IP List에 제 Client IP가 포함되지 않은 상태로 CLoudfront 주소로 HTTP 요청을 하나 해보겠습니다.
역시 S3를 통해 성공적으로 응답합니다.
이번엔 제가 관리하는 IP List에 제 Client IP를 포함하여 업로드하고 WAF 정책이 갱신되기까지 좀 기다려보겠습니다. (2분 이상)
Cloudwatch Logs에 들어가서 살펴보니 Lambda 함수가 잘 실행되었네요. Block하는 IP List로 WAF에 잘 갱신되었습니다.
자, 이제 다시 블락이 되는지 다시 한번 동일한 주소로 요청을 해보겠습니다.
오, 역시 잘 되는군요.. WAF 룰에 걸린 이벤트 히스토리도 아래처럼 WAF 메뉴에서 확인할 수 있습니다.
정리
오늘 보여드린 과정은 좀 복잡해 보일 수도 있습니다. 무엇보다 오늘 포스팅의 목적은 "이런식으로 WAF를 쓰시면 되요"가 아니라 이런식으로 "Cloudwatch와 Lambda와 WAF 서비스를 연동할 수 있어요"를 보여드리는 것이죠. 물론 자유도가 높은 만큼 설정할 것은 늘어납니다.
마지막으로 Github의 awslabs 에 가니 access log기반으로 IP list를 만들어주는 예시도 있네요. 관심있으신 분은 한번 살펴보시면 좋을 것 같아요.
링크
마칩니다.