같은 호스트에서 NGINX와 OpenVPN을 함께 운영하면 클라이언트 주소가 세 가지로 나타나며, 각각 요청이 택할 수 있는 경로 하나에 대응합니다. 터널 주소로 들어오는 브라우저, 공인 주소로 들어오는 브라우저, 게이트웨이의 인터넷 경로로 나가는 프로그램은 대기 중인 소켓에서 모두 다르게 보입니다. 로그 줄을 해석하기 전에 어느 경로를 보고 있는지 정하십시오. 판단은 클라이언트가 사용한 목적지, 외부 VPN 엔드포인트에 대해 유지하는 예외, 그리고 도중에 무언가가 패킷을 변환하는지에 달려 있습니다.

누가 사용자인지가 아니라 목적지로 판단하십시오

요청이 전송된 주소에서 시작하십시오, 그 주소가 경로를 고르기 때문입니다. 호스트의 터널 주소로 간 요청은 클라이언트의 내부 주소를 원본으로 삼아 터널 인터페이스에 도착합니다. 호스트의 공인 주소로 간 요청은 보통 인터넷 쪽 인터페이스에 클라이언트의 공인 주소로 도착하며, 같은 노트북이 그 순간 터널을 맺고 있어도 마찬가지입니다. 따라서 VPN 풀 소속은 패킷 경로의 속성이지 사용자를 따라다니는 속성이 아닙니다.

Path the request tookSource the site normally records
Client reaches the site at its tunnel address, 10.24.0.1Client inner address, 10.24.0.20
Client reaches another internet site through the gatewayGateway public egress address, 192.0.2.44
Client reaches the gateway's public address through the endpoint exceptionClient's own public access address

터널과 아무 관계 없는 주소로 VPN 사용자가 로그에 나타날 때 가장 먼저 확인할 가치가 있는 줄이 바로 이 세 번째 줄입니다. 같은 프로필의 두 사용자가 서로 다른 기록을 만들 수 있는 이유도 설명하는데, 각자의 접속 네트워크가 다르고 터널 안의 무엇도 그것을 덮어쓰지 않습니다.

외부 엔드포인트가 두 번째 공인 경로를 만드는 이유

클라이언트는 터널을 세우기 위해 게이트웨이의 공인 주소에 도달해야 하므로 그 주소로 가는 경로가 터널 밖에 있어야 합니다. 클라이언트가 모든 트래픽을 안쪽으로 돌릴 때, 합리적인 구현은 자기 자신에 의존하는 터널을 피하려고 서버의 공인 주소에 대한 명시적 호스트 경로를 유지합니다. 그 예외는 서비스를 가리지 않으므로 같은 공인 주소로 가는 모든 요청이 그것을 따르며, 게이트웨이에서 호스팅되는 사이트로 가는 브라우저 요청도 포함됩니다.

이 분야의 혼란스러운 보고 대부분 뒤에 있는 원리가 이것이며, 서버가 아니라 클라이언트 구현에 달려 있습니다. 그래서 같은 프로필의 두 클라이언트가 다르게 동작할 수 있습니다. 로그를 고치려고 예외를 없애면 터널도 함께 무너지므로, 예외는 두고 그 주위에서 설계하십시오.

소켓, 테이블, 로그 형식을 함께 읽으십시오

세 가지 관찰이 어느 경로를 보고 있는지 결정합니다: 소켓이 어디에서 대기하는지, 어느 인터페이스가 목적지에 응답하는지, 로그 형식이 실제로 무엇을 기록하는지입니다. 대기 소켓이 터널 주소에만 묶여 있으면 공인 요청은 아예 닿을 수 없고, 이로써 두 줄이 즉시 제외됩니다. 클라이언트에 대한 조회가 터널 장치를 돌려주면 요청은 내부 원본으로 도착한 것이며 로그에 그렇게 나와야 합니다.

ss -lntp 'sport = :443'
ip route get 10.24.0.20
ip route get 192.0.2.44

다음에는 줄이 아니라 형식을 읽으십시오. 전달된 헤더로 채워지는 필드는 소켓 피어가 아니라 주장을 기록하며, 그 주장은 바로 앞 피어가 신뢰할 수 있는 프록시일 때만 의미가 있습니다. 두 값을 모두 로그에 남기면 나중 논쟁이 정리됩니다, 바로 앞 피어와 대체된 주소는 서로 다른 사실이고 네트워크에서 온 것은 둘 중 하나뿐이기 때문입니다.

log_format tunneled '$remote_addr $realip_remote_addr $request $status';
grep -n 'log_format' /etc/nginx/nginx.conf

원하는 진입점을 고르고 DNS를 맞추십시오

사이트가 터널 전용이어야 한다면 VPN 클라이언트에게는 터널 주소로 해석되는 이름을 주고, 대기 소켓에서 정책을 적용하십시오. 내부 이름에 대해 10.24.0.1을 돌려주는 분할 DNS 응답은 이름 해석의 세부 사항이라는 옷을 입은 경로 결정입니다. 사이트가 공개도 되어야 한다면 이름 두 개나 포트 두 개를 유지하고, 어느 쪽이 요청을 처리했는지 로그가 말하게 하십시오.

허용 규칙도 같은 논리를 따릅니다. 터널 풀을 허용해도 공인 요청이 승인되지는 않으며, 인터넷을 통해 들어온 연결에 내부 주소를 채우지도 않습니다. 두 진입점을 한 이름 아래 섞으면 기록되는 원본이 설계 선택이 아니라 클라이언트 경로의 부작용이 됩니다.

경로를 확인하고, 그다음 정책을 확인하십시오

게이트웨이에서의 캡처와 직접 통제하는 요청으로 경로를 확인하십시오. 터널 장치에서의 캡처와 공인 인터페이스에서의 캡처는 어느 쪽이 바이트를 실었는지 보여 주고, 패킷의 순서는 그 사이에 변환이 있었는지 알려 줍니다.

tcpdump -ni tun0 port 443 -c 5
tcpdump -ni eth0 port 443 -c 5

그다음 양방향 접근을 확인하십시오: 의도한 이름의 진입점이 의도한 클라이언트에서 동작하고, 승인되지 않은 공인 경로는 단지 느린 것이 아니라 거부되어야 합니다. 일반적인 IP 에코 사이트는 게이트웨이의 인터넷 출구에 대해 무엇인가를 증명할 뿐, 같은 호스트에 있는 이 사이트에 대해서는 아무것도 증명하지 않습니다. 페이지와 WebSocket이 서로 다를 때는 서버 구성을 건드리기 전에 URL, 주소 체계, DNS 응답을 비교하십시오.

관련 글