Giữ địa chỉ của máy khách VPN cho đến tận ứng dụng khiến mỗi dòng nhật ký và mỗi mục trong danh sách cho phép đều mang cùng một nghĩa. Viết lại địa chỉ ở rìa đám mây khiến bảng định tuyến đơn giản hơn nhưng nhật ký kém hữu ích hơn. Không lựa chọn nào sai tự thân, và lập luận quyết định nó hiếm khi liên quan đến hiệu năng. Ba điều kiện quyết định: ứng dụng có cần biết người nào đã kết nối, kết cấu đám mây có chấp nhận nguồn bạn định gửi, và ai sẽ nhận trách nhiệm về đường về sau đó.

Ba điều kiện quyết định

Hãy bắt đầu từ yêu cầu của ứng dụng, không phải từ sơ đồ mạng. Nếu việc cấp quyền hoặc kiểm toán phụ thuộc vào địa chỉ của từng máy khách, thì việc giữ nguyên địa chỉ là yêu cầu chức năng và việc dịch địa chỉ là một bước thụt lùi. Nếu ứng dụng chỉ cần biết rằng lưu lượng đến qua đường truy cập từ xa, một địa chỉ đã dịch là đủ và rẻ hơn nhiều khi vận hành.

Điều kiện thứ hai mang tính cơ học. Mạng ảo không tự động tin một gói tin khẳng định một địa chỉ chưa được gán cho giao diện gửi. Hầu hết kết cấu đám mây đều áp đặt điều này, theo cách và tên khác nhau, và một thiết kế bỏ qua nó sẽ trông đúng trên sơ đồ và lặng lẽ mất gói trong môi trường thực.

Điều kiện thứ ba mang tính tổ chức. Giữ nguồn nghĩa là bảng định tuyến của mạng con ứng dụng phải trỏ ngược về cổng cho tiền tố máy khách, và mỗi nhóm thêm một mạng con sau đó phải giữ đường đó nhất quán. Đó là một chi phí nhỏ một lần, và là chi phí lặp lại trên hàng chục tài khoản. Hãy quyết định ai trả trước khi bạn hứa về hành vi đó.

Tuyến đường không phải là quyền giả mạo

Thêm một tuyến về cho mạng con của bạn biết câu trả lời phải đi đâu. Nó không nói với kết cấu rằng phiên bản chuyển tiếp các gói tin đó được phép phát chúng với nguồn ngoại lai. Trên AWS, kiểm soát liên quan là kiểm tra nguồn và đích, và nó hiển thị theo từng phiên bản:

aws ec2 describe-instances --instance-ids i-0a1b2c3d4e5f60718 \
  --query "Reservations[].Instances[].SourceDestCheck"
aws ec2 modify-instance-attribute --instance-id i-0a1b2c3d4e5f60718 \
  --no-source-dest-check

Chỉ tắt nó cho phiên bản có công việc được ghi nhận là chuyển tiếp, và không tắt cho bất cứ thứ gì khác. Mỗi máy ảo ứng dụng còn bật kiểm tra là một máy ít hơn có thể bị dùng để phát lưu lượng với nguồn đi vay. Nếu nền tảng của bạn không phải AWS, hãy tìm cấu hình chống giả mạo hoặc địa chỉ được phép tương đương thay vì cho rằng hành vi sẽ đi theo.

Một lần bắt gói nhanh chóng giải quyết câu hỏi nhanh hơn việc đọc bảng điều khiển. Nếu câu trả lời đi ra mà máy khách không bao giờ thấy, thì kết cấu đang bỏ nguồn giả, không phải ứng dụng đang lỗi.

Việc dịch mua được gì và mất gì

Viết lại nguồn tại cổng loại bỏ bài toán đường về. Ứng dụng thấy một địa chỉ mà nó đã biết cách tiếp cận, và tiền tố máy khách không bao giờ cần xuất hiện trong bảng định tuyến đám mây. Trên Linux quy tắc chỉ là một dòng, và đáng để viết phiên bản hẹp nhất mà bạn có thể:

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 172.20.8.0/24 -o ens5 -j SNAT --to-source 10.40.3.10

Hãy để ý điều ứng dụng ghi lại từ nay: 10.40.3.10 cho mọi người dùng, trên mọi kết nối, mãi mãi. Bất kỳ danh sách địa chỉ được phép nào xây trên giá trị đó nay cấp quyền truy cập cho toàn bộ nhóm người dùng truy cập từ xa, và mọi đợt rà soát sự cố đều phải quay lại cổng để trả lời đó là ai.

Cách khắc phục không phải là từ bỏ việc dịch, mà là ngừng giả vờ rằng địa chỉ là danh tính. Hãy mang danh tính máy khách trong một trường đã xác thực, ghi lại ở cổng cùng với bộ giá trị đã dịch, và để ứng dụng kết nối theo đó. Không có khóa kết nối, việc dịch biến một bài toán mạng thành một bài toán pháp y vĩnh viễn.

Bộ chuyển tiếp là một giao diện khác

Một proxy ngược trước ứng dụng né hoàn toàn câu hỏi về đường được định tuyến. Proxy mở kết nối phía sau của riêng nó, nên tiền tố máy khách không bao giờ cần định tuyến được bên trong mạng ảo, và ứng dụng có thể nhận danh tính trong một tiêu đề do proxy đặt.

Tiêu đề đó chỉ đáng tin khi phía sau chấp nhận nó từ proxy và không từ bất cứ nguồn nào khác. Theo thuật ngữ nginx, điều đó nghĩa là nêu tên rõ ràng đối tác tin cậy thay vì tin vào bất cứ thứ gì đến:

set_real_ip_from 10.40.3.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Bất kỳ máy khách nào tiếp cận được phía sau một cách trực tiếp đều có thể giả mạo cùng tiêu đề đó, nên phía sau phải không thể tiếp cận ngoài qua proxy. Đó là sự thật của tường lửa, không phải ý kiến cấu hình, và chính giả định đó là thứ người ta bỏ qua khi sao chép đoạn mã.

Bộ chuyển tiếp cũng thay đổi thứ bạn mua. Bạn có được danh tính ở tầng ứng dụng và một nơi tự nhiên để ghi lại; bạn mất tính tổng quát, vì mỗi giao thức mới cần hỗ trợ proxy riêng. Với dịch vụ HTTP, sự đánh đổi đó thường tốt, và với bất cứ thứ gì không phải HTTP thì thường hoàn toàn không có.

Ghi lại điều mỗi ranh giới nhìn thấy

Dù bạn chọn gì, buổi rà soát thiết kế nên kết thúc bằng một bảng nêu địa chỉ nguồn và danh tính có thể chứng minh ở mỗi chặng. Không có nó, sự cố đầu tiên sẽ tạo ra ba nhóm, mỗi nhóm mô tả một máy khách khác nhau.

BoundarySource the next hop seesWhat is actually proven
Client to gateway172.20.8.14A certificate or credential was presented
Gateway to app subnet, preserved172.20.8.14The same session, if the return route exists
Gateway to app subnet, translated10.40.3.10Only that traffic came through the gateway
Proxy to backend10.40.3.10 plus a headerThe proxy asserted an identity it authenticated

Rồi hãy chọn. Giữ nguồn khi việc cấp quyền của ứng dụng thật sự phụ thuộc vào địa chỉ máy khách và bạn có thể đảm nhận tuyến đường. Hãy dịch khi không như vậy và bạn có thể mang danh tính ra ngoài băng, và dùng hướng dẫn của AWS về các phiên bản chuyển tiếp cho các cấu hình chuyển tiếp riêng của nền tảng. Hãy dùng bộ chuyển tiếp khi dịch vụ nói HTTP và bạn muốn danh tính không còn là địa chỉ nữa.

Bài viết liên quan