GCE에서 OpenVPN: 라우트를 push하기 전에 별칭 IP 추가
push된 라우트만으로는 VM이 다음 홉이 되지 않습니다. 별칭 IP 범위를 추가하고 서버 풀과 맞춘 뒤 VPC 반환 라우트를 만든 후 클라이언트를 테스트하세요.
클라이언트가 Compute Engine VM의 OpenVPN 서버에 접속하고 상태 창에는 연결됨이 표시되는데도 VPC 안의 호스트로 보낸 ping은 여전히 아무 데도 도달하지 않습니다.본능적으로 push 줄을 하나 더 추가하고 싶어지지만, 그것으로 해결된 적은 없습니다.Compute Engine은 자체 라우트 테이블과 VM 인터페이스가 실제로 보유한 주소를 기준으로 패킷의 목적지를 정하므로, VM이 소유하지 않은 터널 풀은 아무도 전달할 수 없는 풀입니다.
설정 파일이 아니라 죽어 가는 패킷을 따라가면 빠진 조각들이 순서대로 드러납니다.
죽은 패킷에서 시작하기
SYN은 클라이언트를 떠나 터널로 들어가고, VPC 내부 목적지로 향하는 캡슐화된 패킷으로 VM에 도착합니다.OpenVPN은 이를 역캡슐화한 뒤 eth0으로 전달하려 하는데, 여기서 패브릭이 무엇보다 먼저 한 가지를 묻습니다: 이 인스턴스가 목적지 주소를 소유하고 있는가.다른 사람의 서브넷에서 잘라낸 터널 풀은 이 질문에서 실패하고, 패킷은 어떤 라우트나 방화벽 규칙도 참조되기 전에 버려집니다.
따라서 클라이언트에서 VPC로 가는 방향에는 두 가지 별개의 요구 사항이 있고, 어느 것도 push 지시어가 아닙니다.VM에는 터널 풀을 덮는 별칭 범위가 필요하며, 그것이 이 주소들의 정당한 소유자가 되게 합니다.VPC에는 보호되는 각 프리픽스마다 VM을 다음 홉으로 지정하는 라우트가 필요합니다.둘 중 하나만 빠져도 패킷은 다른 지점에서 죽고, 클라이언트는 똑같은 침묵만 봅니다.
그 순서대로 장애를 읽으세요: 클라이언트 쪽에서는 두 조건이 똑같이 보이기 때문입니다.연결됨을 보고하면서 아무것도 응답하지 않는 터널은 암호 방식의 문제가 아니라 토폴로지 문제의 특징입니다.
인스턴스가 터널 풀을 소유하는가
VM에 자기 서브넷 안의 보조 범위를 주고, OpenVPN이 정확히 그 범위에서 주소를 할당하게 하세요.기본 주소가 10.156.0.10/20인 인스턴스에서 /28 별칭을 쓰면 풀을 다른 인스턴스가 이미 보유한 주소와 분리할 수 있습니다:
gcloud compute instances network-interfaces update openvpn-vm \
--zone=europe-west1-b \
--aliases=eth0:10.156.1.0/28그다음 server 지시어가 같은 블록을 설명해야 합니다.첫 번째 주소가 터널 게이트웨이가 되고 나머지 주소는 클라이언트에 할당됩니다.여기서는 두 숫자가 하나의 블록을 설명합니다: 네트워크와 넷마스크이며, 이것이 OpenVPN이 여전히 기대하는 풀 문법입니다.
server 10.156.1.0 255.255.255.240주소가 OpenVPN 설정 안에만 있는 것이 아니라 실제로 인터페이스에 올라갔는지 확인하세요.패브릭은 NIC가 보고하는 주소로 전달하며, 데몬이 믿는 주소로 전달하지 않습니다.명령 하나면 확인됩니다:
ip -4 addr show dev eth0eth0에 도달하지 못한 보조 주소나 다른 서브넷과 겹치는 풀은 시작 오류가 아니라 나중에 간헐적 드롭으로 나타납니다.데몬은 뜨고 클라이언트도 연결되며, 일부 목적지만 이상 동작합니다.별칭 범위를 작게 유지하면 라우트 테이블에서 풀을 알아보기 쉽습니다.다른 인스턴스가 이미 쓰는 서브넷에서 잘라내지 마세요.
반환 트래픽에 다음 홉 주기
VPC 호스트의 응답은 터널 풀의 클라이언트 주소로 향하며, 그 주소는 VPC가 아는 어떤 서브넷에도 속하지 않습니다.그 풀에 대한 라우트가 없으면 응답은 일치하는 항목이 없는 첫 홉에서 멈추고, 요청은 먼 쪽에서 성공했을 가능성이 큽니다.
gcloud compute routes create openvpn-return \
--network=prod-vpc \
--destination-range=192.168.127.0/24 \
--next-hop-instance=openvpn-vm \
--next-hop-instance-zone=europe-west1-b \
--priority=800VPC 내부가 아니라 클라이언트 뒤에 있는 프리픽스에도 같은 라우트가 필요합니다.그런 프리픽스에는 해당 클라이언트의 ccd 파일에 iroute 항목도 필요합니다.그 항목은 서버 측 기록으로, 어떤 클라이언트가 그 프리픽스를 소유하는지 서버에 알려 줄 뿐 클라이언트 자체에는 아무것도 설치하지 않습니다.
push 목록은 접속하는 머신에 라우트를 추가할 뿐이므로 대화의 클라이언트 쪽에 남겨 두세요.VPC 서브넷을 위한 push 줄과 풀로 돌아가는 VPC 라우트는 같은 경로의 두 반쪽이며, 어느 한 반쪽만으로는 요청은 나르지만 응답은 나르지 못하는 터널이 됩니다.
방화벽, 포워딩, 그 사이의 홉
VPC 방화벽은 역캡슐화된 패킷을 평가하므로, 인그레스 규칙은 터널 풀과 그 경로로 VM에 도달하는 모든 사이트 프리픽스를 허용해야 합니다.기본 거부 태세는 여기서 조용히 실패합니다: 패킷은 역캡슐화 후 버려지고 OpenVPN 로그에는 건강한 세션이 보입니다.
종료가 아니라 전달을 하는 모든 Linux 호스트에서는 net.ipv4.ip_forward가 켜져 있는지 확인하세요.소유 규칙은 거기에도 적용됩니다: 자기가 보유하지 않은 서브넷을 위해 전달하는 장비는 그 VM과 똑같이 패킷을 버립니다.터널을 탓하기 전에 값을 읽으세요.
프리픽스 하나만 실패할 때
부분 실패는 경로의 나머지가 이미 입증되었기 때문에 읽기 가장 쉬운 경우입니다.먼저 라우트 목록을 보고 그 프리픽스를 덮어야 할 항목의 목적지 범위와 다음 홉을 읽은 뒤, 인스턴스 설명을 보고 그 별칭 범위를 서버가 할당하는 풀과 비교하세요.
gcloud compute routes list --filter=destination-range~10.164.0.0
gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)라우트가 없으면 그 프리픽스에 다음 홉이 없는 형태로 드러나고, 별칭이 없으면 패킷이 인터페이스에서 버려지는 형태로 드러납니다; 클라이언트에서는 비슷해 보이지만 그 두 출력에서는 완전히 다릅니다.둘 다 있으면 남은 용의자는 그 프리픽스를 주장하는 클라이언트의 ccd iroute입니다.
네 가지 값을 터널 옆에 적어 두세요: 별칭 범위, 서버 풀, push하는 프리픽스, VPC 라우트입니다.오래된 별칭은 풀의 모든 주소를 깨고, 오래된 라우트는 한 방향을 깨고, 빠진 push는 클라이언트에서 프리픽스를 숨기고, 잘못된 iroute는 프리픽스를 엉뚱한 피어로 보냅니다.다음에 서브넷을 추가할 사람은 이 네 가지를 한곳에서 필요로 하며, 그 메모는 저녁 한 끼보다 쌉니다.