OpenBSD VPN 게이트웨이에서 tun0을 통한 LAN NAT
OpenBSD tun0 출구를 떠나는 LAN 트래픽에 대해 소스 NAT와 반환 경로 중 하나를 고르고, pf가 여전히 통과시키는 위치에 nat-to 규칙을 배치합니다.
같은 OpenBSD 게이트웨이를 받은 두 엔지니어가 원격 네트워크에 도달하는 서로 다른 규칙 집합을 내놓는 일은 흔하며, 둘 다 근거가 있습니다. 소스 변환과 반환 경로 중 무엇을 고를지는 전혀 구문 문제가 아닙니다. 원격 측이 192.168.88.0/24에 대해 이미 무엇을 알고 있는지, 그리고 로그에 무엇을 남겨야 하는지에 달려 있습니다. 여기서 틀리면 nat-to 줄은 완벽해 보이는데 응답은 원격 기본 게이트웨이로 사라집니다.
라우팅과 재작성은 서로 다른 질문에 답한다
라우팅 테이블이 172.20.0.0/16이 tun0을 통해 도달 가능하다고 결정하며, 그 판단은 어떤 pf 변환도 참조되기 전에 내려집니다. 이어서 소스 변환이 패킷 헤더를 바꾸어 원격 측이 LAN 호스트 대신 게이트웨이의 터널 주소를 보게 합니다. 두 메커니즘은 서로를 대체하지 않습니다. nat 규칙은 경로를 만들 수 없고, 경로는 사설 서브넷을 들어본 적 없는 원격 라우터를 설득할 수 없습니다. 원격 측에 반환 경로가 없으면 응답은 버려지거나 상대의 기본 게이트웨이로 전달되며, 규칙을 아무리 조정해도 고쳐지지 않습니다.
쉽게 말해 전달은 트래픽이 어디로 가는지에 답하고 변환은 어디서 오는 것처럼 보이는지에 답합니다. 규칙 집합을 설계할 때 둘을 별개의 생각 상자에 넣어 두십시오.
결정하는 세 가지 조건
세 가지 질문을 순서대로 던지면 설계는 대개 스스로 정해집니다. 원격 네트워크에 192.168.88.0/24를 위한 터널 주소를 가리키는 정적 경로가 있는지, 또는 그 관리자가 그 경로의 라우터를 통제하는지. 답이 예라면 LAN 주소를 그대로 통과시키고 변환은 완전히 생략합니다. 원격 측에서 클라이언트별 가시성이 필요한지, 접근 정책을 위해서든 감사 추적을 위해서든. 필요하다면 소스를 보존할 가치가 라우팅 수고에 충분합니다. 터널 주소가 원격 경로에 적을 만큼 안정적인지, 아니면 재접속마다 바뀌는지.
어느 하나라도 아니오이거나 알 수 없으면 nat-to가 현실적인 선택이며 되돌릴 수도 있습니다. 원격 측이 제대로 된 경로를 추가하면 변환 규칙은 한 줄로 빠집니다. 설치된 적 없는 반환 경로는 터널이 왜 한 방향으로만 동작하는지 누군가 물을 때마다 지원 스레드 하나를 잡아먹습니다.
pf가 실제로 평가하도록 조각을 배치하기
아래 조각은 LAN이 192.168.88.0/24, 원격 네트워크가 172.20.0.0/16, 터널 인터페이스가 tun0라고 가정합니다. 그 안에서 다음 홉을 고르는 것은 없습니다. 이미 터널로 나가는 패킷의 소스만 다시 씁니다.
match out on tun0 inet from 192.168.88.0/24 to 172.20.0.0/16 nat-to (tun0)
pass in on em0 inet from 192.168.88.0/24 to any keep state
그 첫 줄의 두 가지 세부가 무게의 대부분을 집니다. tun0을 감싼 괄호는 상태 항목을 만들 때마다 인터페이스 주소를 읽으라고 pf에 지시하며, 재접속 후 터널 번호가 다시 매겨질 때 중요합니다. match라는 단어는 규칙이 다시 쓴 뒤 아래로 빠진다는 뜻이므로 별도의 pass 규칙이 여전히 흐름을 허용해야 합니다. match 줄에 적힌 인터페이스도 라우팅 테이블이 고르는 것과 같아야 하며, 그렇지 않으면 pf는 패킷이 실제로 지나는 경로와 다른 출력 경로에서 규칙을 평가합니다.
커널 쪽도 잊지 마십시오. IPv4 전달이 켜져 있어야 하고, 터널과 LAN을 위한 상태 기반 pass 규칙이 존재해야 이 모든 것이 의미를 갖습니다. 여기서 키워드 순서에 대한 올바른 참조는 OpenBSD FAQ의 PF NAT 절입니다.
트래픽을 신뢰하기 전에 규칙 집합을 검증하라
먼저 pfctl -nf /etc/pf.conf — 파일을 읽어 들이지 않고 구문 분석하는 명령 — 로 구문을 확인합니다. 다음으로 정책을 읽어 들이고 커널이 실제로 무엇을 들고 있는지 되읽으십시오. 깔끔하게 분석된 규칙도 가려지거나 잘못된 인터페이스에 붙을 수 있습니다. pfctl -sn은 변환 규칙을 읽어 들인 형태로 출력하고, pfctl -sr은 필터 규칙을 평가 순서대로 출력합니다.
다음은 회선을 관찰합니다. 게이트웨이에서 tcpdump -ni tun0 'host 172.20.0.10'을 실행하면 터널을 나가는 소스 주소가 터널 주소인지 LAN 호스트인지 보입니다. 빠른 netstat -rn -f inet로 목적지가 어느 인터페이스로 해석되는지 확인합니다. 트래픽이 흐르기 시작하면 pfctl -ss가 상태 항목을 나열합니다. 흐름이 상태를 만들지 않았다면 그 패킷은 상태를 만드는 규칙에 한 번도 걸리지 않았습니다.
터널 쪽이 맞아 보이는데도 응답이 오지 않으면 pf 편집을 멈추십시오. 남은 장애는 원격 라우터에 있으며, 응답이 그쪽이 도달할 수 없는 사설 주소로 보내지고 있습니다.
변환이 절약보다 비쌀 때
변환은 클라이언트를 숨기며, 때로는 그것이 정확히 잘못된 거래입니다. 겹치는 서브넷이 한 사례입니다. 원격 측도 내부에서 192.168.88.0/24를 쓴다면 LAN 호스트를 게이트웨이로 보여 주는 것은 충돌을 완화하는 대신 악화시킵니다. 주소 쌍으로 트래픽을 고르는 IPsec 정책도 다른 사례입니다. 보안 정책 데이터베이스는 변환 전에 대조되므로 다시 쓴 패킷을 결코 보지 못합니다. 사용자별로 과금하거나 제한하거나 감사하는 배포도 소스가 하나의 주소로 붕괴하는 순간 필요한 신원을 잃습니다.
이식된 pf 파생 제품은 별도의 함정입니다. 자체 규칙 파일을 생성하는 제품은 NAT를 자기 인터페이스로 설정하기를 기대하며, 손으로 고친 조각은 다음 재적재 때 덮어써집니다. match 키워드가 생기기 전에 쓰인 안내서에서 복사한 규칙 집합은 현재 커널에서 적재되지 않으므로 구문을 옮기고 추측하지 말고 오류를 읽으십시오.
실제 네트워크와 맞닥뜨려도 살아남는 결정 규칙은 짧습니다. 할 수 있으면 반환 경로를 넣고, 할 수 없으면 변환하며, 세 조건 중 무엇이 그 선택을 하게 했는지 적어 두십시오. 그 메모가 다음 사람의 반나절을 아껴 줍니다.