큐돈의 마스터는 보안 분야에 꽤나 오랜 시간 있었고 리눅스 서버 운영(sysop)도 십 년 넘게 하고 있습니다. 그 정도로 오래 발을 담그고 있다보니 남들이 보지 못하는 보안 취약점들을 발견하기도 합니다.
오늘은 큐돈을 운영하면서 어떤 보안조치를 취해 두었는지에 대해 기술적인 글을 써 보도록 하겠습니다.

외부 접속 차단

Qdon은 CloudFlare라는 CDN을 사용하고 있습니다. 그래서 기본적으로는 서버 IP가 아닌 CDN의 IP를 통해 접속하게 됩니다.

$ dig qdon.space
; <<>> DiG 9.11.4-3ubuntu5.1-Ubuntu <<>> qdon.space
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17149
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;qdon.space.                    IN      A

;; ANSWER SECTION:
qdon.space.             300     IN      A       104.27.168.97
qdon.space.             300     IN      A       104.27.169.97

;; Query time: 53 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 07 23:58:09 KST 2019
;; MSG SIZE  rcvd: 71

많은 사람들이 간과하는 사실이지만 이것만으로는 DDoS 공격 등을 막지 못 합니다. 서버의 원본 IP를 알아내는 방법은 많이 알려져 있고 이를 통해 원본 서버로 접속하게 되면 CloudFlare의 보호를 받지 못하는 것이죠. 하지만 큐돈의 서버 IP로 포트 스캔을 해 보면 아래와 같이 나옵니다.

$ nmap -Pn [redacted]

Starting Nmap 7.60 ( https://nmap.org  ) at 2019-04-08 00:01 KST
Nmap scan report for [redacted] ([redacted])
Host is up (0.089s latency).
rDNS record for [redacted]: qdon.space
Not shown: 999 filtered ports
PORT   STATE  SERVICE
25/tcp closed smtp

Nmap done: 1 IP address (1 host up) scanned in 15.25 seconds

아무런 포트도 열려 있지 않다고 나옵니다. 그럼 도대체 어떻게 웹서비스를 할 수 있는 걸까요?
답은 CloudFlare로부터의 접속 이외에는 접속을 차단하는 것입니다. 실제로 CloudFlare의 가이드를 보면 그렇게 하라고 나와 있습니다.

CloudFlare에서 사용하는 프록시의 목록은 이런 용도를 위해 미리 알려져 있습니다. 미리 방화벽 설정을 통해 80, 443 포트를 막은 뒤에 아래의 스크립트를 실행하면 CloudFlare로부터의 접속은 허용할 수 있게 됩니다.

#!/bin/bash

DIR="$(dirname $(readlink -f $0))"
cd $DIR

wget https://www.cloudflare.com/ips-v4 -O ips-v4.tmp
wget https://www.cloudflare.com/ips-v6 -O ips-v6.tmp
mv ips-v4.tmp ips-v4
mv ips-v6.tmp ips-v6

for cfip in `cat ips-v4`; do
    ufw allow from $cfip to any port 80,443 proto tcp comment "CloudFlare"
done

for cfip in `cat ips-v6`; do
    ufw allow from $cfip to any port 80,443 proto tcp comment "CloudFlare"
done

ufw reload > /dev/null

마찬가지로 SMTP 서버나 SSH도 쉽게 차단 가능하지만 SSH는 자체 방화벽으로 막는 것보다는 VPS 업체에서 제공하는 외부 방화벽을 사용하는 것을 추천합니다. 허용 되지 않은 곳에서도 웹 대시보드로 접속해 SSH 포트를 열어 원격 접속이 가능하기 때문입니다.

ElasticSearch

ES라고도 불리는 이 ElasticSearch는 마스토돈의 검색 기능을 위해(툿 한정) 사용 됩니다. 다만 이 ES는 쓰레기라고 해도 될 정도로 보안에 취약한데 그 이유를 먼저 알아봅시다.

ES에는 기본적으로 인증 모듈이 없습니다

DB 같은 걸 설정하면 기본적으로 사용자 이름과 패스워드를 설정하죠? ES의 세계에는 그런 게 없습니다. 그냥 9200(기본 포트)으로 접속하면 누구나 사용할 수 있습니다.

X-Pack이라는 모듈이 있긴 합니다만

이게 ACL 기능을 해 주는 공식 모듈이긴 한데 문제는 ES 자체와 달리 이 모듈은 엔터프라이즈급 유료 모듈입니다. 일반 개인이나 작은 곳에서는 못 달아요.

Elastic의 구독 서비스 표를 봅시다. 무료에는 Security가 없는 것 보이시죠?

Elastic subscriptions

이런 상황이니까 맨날 ES 서버에서 유츌이 일어났다느니 하는 뉴스가 자주 보이는 겁니다. 애초에 보안 설정을 할래야 할 수가 없는데 기사 마지막에 보면 “인증 없이는 접근이 불가능 하도록 설정해야 한다고 보안 전문가는 말한다” 같은 식으로 써 있습니다. 화가 나지요.

그럼 어떻게 합니까

방법이 아예 없는 건 아닙니다.

  • 서버 내부에서 로컬호스트에만 바인딩 해서 외부 접속을 막고 쓰든가
  • 사설 IP 대역 안에서만 열어 놓고 쓰든가
  • 공인 IP를 쓰긴 하지만 특정 IP로만 방화벽을 열고 쓰든가

1번째 방법은 ES가 리소스를 엄청나게 많이 먹는 관계로 VPS에서 쓰기는 힘듭니다. 2번째 방법은 같은 VPS 업체를 쓴다면 내부 IP를 연결하는 기능이 있습니다. 그걸 쓰면 외부 노출을 막을 수 있습니다. 3번째 방법은 가장 범용적입니다. 하지만 세 가지 방법 모두 근본적인 해결책은 아닌데, 패스워드 기반의 보안과 달리 접속 가능한 IP만 얻으면 누구든지 접속이 가능합니다. 기본적으로는 그 IP를 얻는 과정도 보안이 되어 있으니 정말로 누구나 접근할 수는 없을 정도의 보안이라는 것 뿐이죠.

아무튼 방화벽으로 마스토돈 서버가 돌아가고 있는 IP만 허용해 주고 막아 줍시다.

Docker를 사용할 때 방화벽 주의

요즘은 모든 서비스를 Docker로 돌리는 게 대세입니다. 큐돈도 마스토돈과 ES 서버가 도커 위에서 돌아갑니다만 이게 방화벽이랑 상성이 안 맞아서 방화벽상에선 막혀 있는데 실제로는 열려 있는 그런 경우가 발생합니다.

결론부터 말하자면 원인은 iptables입니다. UFW도 iptables를 사용하고 Docker도 내부적으로 iptables 엔트리를 추가합니다. 방화벽으로 막았어도 Docker에서 포트를 열면 iptables 엔트리가 추가되고, 결국은 열리게 되는 겁니다.

해결 방법은 조금 복잡합니다. 쉽게 설명하면 다음과 같은 두 가지 절차를 따르게 되는데 같이 차근차근 따라해 봅시다

  • Docker에서 iptables를 사용하지 않도록 한다
  • NAT 포워딩을 허용한다

일단 Docker에서 iptables를 끕니다./etc/docker/daemon.json"iptables": false를 추가하면 됩니다. 이렇게 하면 도커는 iptables를 이용하지 않고 프록시용 프로세스를 하나 더 띄우는 방식으로 포트포워딩을 하게 됩니다.

여기까지만 하면 문제는 해결 된 것처럼 보이지만 재부팅을 해 보면 문제가 발생합니다. 도커 내부에서 외부로 나가는 패킷이 전달이 안 됩니다. 이것도 도커 데몬이 실행 될 때 iptables로 설정을 해 주는데 그걸 껐으니 설정이 되지 않는 것이죠. UFW를 사용한다면 /etc/default/ufw 파일을 수정해 DEFAULT_FORWARD_POLICYACCEPT로 바꿔주거나 상황에 맞게 포워드 룰을 추가해 주시면 됩니다. 이런 글을 참고하는 것도 도움이 되겠죠.

*filter
-A FORWARD -i docker0 -j ACCEPT
-A FORWARD -o docker0 -j ACCEPT
COMMIT

*nat
-A POSTROUTING -s 172.16.0.0/16 !-o docker0 -j MASQUERADE
COMMIT

이렇게 큐돈에서 적용 중인 보안 조치를 간략하게나마 알아보았습니다. 다른 분들이 마스토돈 서버를 운영할 때 참고가 되었으면 좋겠습니다.

서비스 운영이나 보안은 책임감이 중요합니다. 타인의 개인정보 유출로 이어질 수 있는만큼 기본적인 지식과 자세가 되어있지 않다면 아무나 맡으면 안 되는 게 서비스 운영의 보안이라 생각합니다.

살면서 기본적인 보안 수칙도 모르며 기본적인 자세도 안 되어있는 보안 담당자를 많이 봐 왔습니다. 그런 일을 방지하기 위해서라도 보안에 대해서는 강한 규제가 필요하다 생각 합니다.