Clients quay số tới máy chủ OpenVPN trên một VM Compute Engine, cửa sổ trạng thái báo đã kết nối, nhưng ping tới một máy chủ trong VPC vẫn không đi tới đâu. Bản năng là thêm một dòng push nữa, và điều đó không bao giờ sửa được lỗi. Compute Engine quyết định gói tin đi đâu từ bảng route của chính nó và từ các địa chỉ mà giao diện của VM thực sự nắm giữ, nên một pool đường hầm không thuộc sở hữu của VM là pool không ai chuyển tới được.

Hãy đi theo gói tin đang chết thay vì đi theo tệp cấu hình, và những mảnh còn thiếu sẽ hiện ra theo thứ tự.

Bắt đầu từ gói tin đã chết

SYN rời client, vào đường hầm và đến VM dưới dạng một gói tin được đóng gói cho một đích bên trong VPC. OpenVPN giải đóng gói nó và cố chuyển tiếp ra eth0, nơi lớp hạ tầng đặt một câu hỏi trước mọi thứ khác: instance này có sở hữu địa chỉ đích hay không. Một pool đường hầm cắt ra từ subnet của người khác trượt câu hỏi đó, và gói tin bị bỏ trước khi bất kỳ route hay quy tắc tường lửa nào được xét đến.

Vậy chiều từ client tới VPC có hai yêu cầu riêng biệt, và không yêu cầu nào là một chỉ thị push. VM cần một dải alias bao phủ pool đường hầm, và chính điều đó khiến nó là chủ sở hữu hợp lệ của các địa chỉ ấy. VPC cần một route chỉ định VM làm next hop cho từng tiền tố được bảo vệ. Thiếu một trong hai thì gói tin chết ở một chỗ khác, trong khi client vẫn thấy sự im lặng như nhau.

Hãy đọc lỗi theo thứ tự đó, vì từ phía client hai điều kiện trông giống hệt nhau. Một đường hầm báo đã kết nối trong khi không có gì trả lời là dấu hiệu của vấn đề tô-pô, không phải của một cipher tồi.

Instance có sở hữu pool đường hầm không

Cấp cho VM một dải phụ bên trong subnet của chính nó, rồi để OpenVPN cấp địa chỉ đúng từ dải đó. Trên một instance có địa chỉ chính là 10.156.0.10/20, một alias /28 giữ pool tách khỏi các địa chỉ mà những instance khác đã nắm giữ:

gcloud compute instances network-interfaces update openvpn-vm \
  --zone=europe-west1-b \
  --aliases=eth0:10.156.1.0/28

Chỉ thị server sau đó phải mô tả đúng khối ấy. Địa chỉ đầu tiên của nó trở thành gateway của đường hầm, và các địa chỉ còn lại được cấp cho client. Hai con số mô tả một khối ở đây, một mạng và một netmask, đó là cú pháp pool mà OpenVPN vẫn mong đợi.

server 10.156.1.0 255.255.255.240

Xác nhận rằng địa chỉ thực sự đã nằm trên giao diện chứ không chỉ nằm trong cấu hình OpenVPN. Lớp hạ tầng chuyển tiếp theo những gì NIC báo cáo, không theo những gì daemon tin. Một lệnh là đủ:

ip -4 addr show dev eth0

Một địa chỉ phụ không bao giờ tới eth0, hoặc một pool chồng lấn với subnet khác, về sau sẽ xuất hiện dưới dạng rớt gói lẻ tẻ chứ không phải lỗi khởi động. Daemon khởi động, client kết nối được, và chỉ một số đích hoạt động sai. Giữ dải alias nhỏ để dễ nhận ra pool trong bảng route. Đừng bao giờ cắt nó ra từ một subnet mà instance khác đã dùng.

Cho lưu lượng quay về một next hop

Một phản hồi từ máy chủ trong VPC được gửi tới một địa chỉ client trong pool đường hầm, địa chỉ này không thuộc subnet nào mà VPC biết. Không có route cho pool đó, phản hồi dừng ở hop đầu tiên không có mục khớp, và yêu cầu rất có thể đã thành công ở đầu xa.

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=800

Route tương tự là cần thiết cho bất kỳ tiền tố nào nằm sau một client thay vì bên trong VPC. Những tiền tố đó cũng cần một mục iroute trong tệp ccd của client ấy. Mục đó là sổ sách phía máy chủ: nó cho máy chủ biết client nào sở hữu tiền tố, và nó không cài gì lên chính client.

Giữ danh sách push cho phía client của cuộc trò chuyện, vì nó chỉ thêm route vào máy đang kết nối. Một dòng push cho subnet VPC và một route VPC quay về pool là hai nửa của cùng một đường đi, và chỉ một nửa thì tạo ra đường hầm chở được yêu cầu nhưng không chở được phản hồi.

Tường lửa, chuyển tiếp và các hop ở giữa

Tường lửa VPC đánh giá gói tin sau khi giải đóng gói, nên một quy tắc ingress phải cho phép pool đường hầm và mọi tiền tố site đến VM theo cách đó. Thế phòng thủ mặc định từ chối sẽ thất bại âm thầm ở đây: gói tin bị bỏ sau khi giải đóng gói, và nhật ký OpenVPN hiển thị một phiên khỏe mạnh.

Trên bất kỳ máy Linux nào chuyển tiếp thay vì kết thúc, hãy kiểm tra net.ipv4.ip_forward có được bật. Quy tắc sở hữu cũng áp dụng ở đó: một máy chuyển tiếp cho subnet mà nó không nắm giữ sẽ bỏ gói tin y như VM vậy. Hãy đọc giá trị trước khi đổ lỗi cho đường hầm.

Khi đúng một tiền tố thất bại

Thất bại một phần là trường hợp dễ đọc nhất, vì mọi thứ khác trên đường đi đã được chứng minh. Bắt đầu với danh sách route và đọc dải đích cùng next hop của mục lẽ ra phải bao phủ tiền tố, rồi đọc mô tả instance và so dải alias của nó với pool mà máy chủ cấp.

gcloud compute routes list --filter=destination-range~10.164.0.0
 gcloud compute instances describe openvpn-vm --format=get(networkInterfaces[0].aliasIpRanges)

Một route thiếu hiện ra là không có next hop cho tiền tố, trong khi một alias thiếu hiện ra là gói tin bị bỏ tại giao diện; hai điều này trông giống nhau từ phía client và hoàn toàn khác nhau trong hai đầu ra đó. Nếu cả hai đều có, nghi phạm còn lại là iroute trong ccd của client đang nhận tiền tố.

Ghi bốn giá trị cạnh đường hầm: dải alias, pool máy chủ, các tiền tố được push, các route VPC. Một alias cũ phá mọi địa chỉ trong pool, một route cũ phá một chiều, một push thiếu giấu tiền tố khỏi client, và một iroute sai gửi tiền tố tới peer sai. Người tiếp theo thêm subnet cần cả bốn thứ ở một chỗ, và ghi chú đó rẻ hơn một buổi tối.

Bài viết liên quan