nftables 가 OpenVPN 클라이언트 간 트래픽을 볼 수 없는 이유
피어 간 트래픽은 VPN 프로세스 내부에서 전달되므로 포워드 카운터가 절대 움직이지 않는다. 이를 세려면 커널 경로와 프로세스 경로 중 하나를 골라야 한다.
한 서버의 두 클라이언트가 파일을 주고받고 전송은 성공하는데, 터널을 향한 모든 포워드 규칙은 제로 패킷을 보고한다. 규칙이 망가진 것도 아니고 체인이 잘못 놓인 것도 아니다. 피어 간 포워드가 켜져 있으면 패킷은 서버 프로세스 내부에서 전달되고 호스트 스택은 라우터가 되지 않으므로, 커널 방화벽이 셀 대상이 존재하지 않는다. 이 분기를 이해하는지가 지름길을 유지할지 커널을 거쳐 경로를 다시 세울지를 결정한다.
서버를 지나는 패킷 하나를 따라가 보자
라우팅되는 터널에서 데몬은 각 클라이언트의 복호화된 패킷을 터널 장치에 넘긴다. 거기서 호스트가 경로를 정하고 포워드 훅이 실행되며, 터널 장치와 일치하는 규칙이 트래픽을 세거나 버릴 수 있다. 대부분의 방화벽 예제가 가정하는 경로가 이것이다.
| Forwarding path | Who decides | What the host firewall sees |
|---|---|---|
| Kernel routing between clients | Host routing table and forward rules | Every inner packet, with interface names |
| Peer forwarding inside the server process | The VPN daemon's own peer table | Only the outer encrypted transport |
지름길은 호스트를 중간에서 빼낸다. 한 세션의 복호화된 패킷은 데몬 내부에서 다른 세션으로 넘겨지고, 안쪽 패킷은 터널 장치로 나가지도 않고 호스트가 경로를 정하지도 않는다. 캡슐화된 트래픽은 여전히 물리 인터페이스를 지나므로 바깥쪽 캡처는 바쁘게 보이지만 안쪽 규칙은 조용하다. 터널 장치에서 뜬 캡처에는 아무것도 나타나지 않으며, 그곳에서 전송을 보려던 사람은 당황한다. 이 비대칭이 데몬 바깥에서 지름길을 알아보는 가장 빠른 단서다.
어느 경로가 실행되었는지 판정하는 카운터 시험
적용되어야 할 규칙에 카운터를 달고, 그 규칙이 막아야 할 두 클라이언트 사이에서 전송을 실행한 뒤 카운터를 읽는다.
sudo nft list ruleset
sudo nft add rule inet filter forward iifname "tun0" oifname "tun0" counter accept
sudo nft list chain inet filter forward
전송이 성공하고 카운터가 영에 머물면 커널은 그 패킷을 한 번도 다루지 않았고, 규칙을 어떻게 고쳐도 바뀌지 않는다. 같은 시험을 서버 자체의 서비스에 대해 반복하면 그 흐름은 실제로 호스트 스택을 지나므로 카운터가 움직인다. 두 결과를 비교하는 것이 답을 만든다.
오독을 막는 세부 사항이 둘 있다. 체인 레이블에 적은 인터페이스 이름만으로는 아무것도 걸러지지 않는다. 일치는 규칙 내부의 인터페이스 필드에서 이루어지기 때문이다. 또한 브리지로 구성한 레이어 2 설계는 또 다르게 동작한다. 거기서는 클라이언트가 하나의 브로드캐스트 도메인을 공유하므로 피어 발견은 예상된 일이며 라우팅 결함이 아니다.
스위치는 액세스 목록이 아니다
여기가 반나절을 잡아먹는 부분이다. 피어 간 포워드는 켜고 끄는 하나의 설정이며, 켜져 있는 동안 데몬이 유일한 포워드 지점이다. 호스트 방화벽은 누가 누구에게 닿을 수 있는지 표현할 수 없고, 클라이언트별 파일도 스위치를 정책 행렬로 바꾸지 않는다.
피어별 규칙이 필요하다면 지름길을 포기하는 것과 제어 수단으로서 호스트 방화벽을 포기하는 것 사이에서 골라야 한다. 끄면 커널 포워드가 돌아오지만, 서버에서 IP 포워드를 켜고 원하는 흐름에 대한 명시적 규칙이 필요하다. 켜 두면 정책이 데몬 설정에 살게 되며, 실제로는 모든 피어 아니면 어떤 피어도 아니다.
자체 주소 풀과 포트를 가진 별도 서버 프로세스가 현실적인 중간안이다. 각 프로세스는 접근 결정을 정확히 하나만 지니므로, 두 그룹이 정책 행렬 없이 서로 다른 규칙을 가질 수 있다. 의도한 경우 호스트가 풀 사이를 라우팅할 수 있고, 그러면 방화벽은 호스트를 지나는 그 흐름을 본다. 대가는 추가 포트, 추가 인증서, 그룹별 프로필이다.
포워드 지점 선택
방화벽이 정책 엔진일 때, 흐름별 기록이 필요할 때, 또는 회계가 중요할 때 커널 포워드를 고른다. 대가는 호스트 스택을 지나는 처리량과 유지할 규칙의 증가다. 이점은 카운터에서 흐름 내보내기 도구까지 기존의 모든 수단이 트래픽을 다시 설명한다는 것이다. 작은 서버에서는 이 대가가 보이지 않지만 바쁜 릴레이에서는 그렇지 않다.
피어 간 트래픽이 전부 허용이거나 전부 차단이고 서버가 그에 맞게 산정되어 있다면 프로세스 내부 포워드를 고른다. 대가는 카운터, 큐 규율, 연결 추적이 더 이상 내부 흐름을 설명하지 못한다는 것이며, 나중에 아무도 그것에 의존하지 않을 때만 받아들일 수 있다.
무엇을 고르든 방화벽 규칙 옆에 적어 두어라. 피어 간 트래픽을 허용하는 것처럼 보이지만 실제로는 데몬이 판단하는 규칙 묶음은 실패한 전송을 조사할 다음 사람을 잘못 인도한다. 규칙만 읽는 사람은 커널이 관문이라고 여긴다.
규칙을 바꾸기 전에 확인할 것
서버가 실제로 읽어 들인 설정을 읽고, 편집했다고 기억하는 파일을 읽지 말며, 피어 옵션이 있는지 확인한다. 변경했다면 서비스가 디스크의 파일을 다시 쓴 것만이 아니라 다시 읽어 들였는지 확인한다.
그다음 클라이언트에서 서버로 가는 흐름으로 같은 시험을 반복해 규칙이 애초에 일치하는지 보이고, 밀어 넣은 경로를 확인한다. 경로 누락은 클라이언트 쪽에서 방화벽 차단과 똑같이 보이기 때문이다. 규칙 순서는 어느 포워드 지점이 판단을 가졌는지 안 뒤에 바꾼다.