SSH công khai qua relay thất bại ở hai ranh giới không liên quan, và sửa cái này thường để lộ cái kia. Hoặc biên trả về phản hồi HTTP thay vì mang luồng, hoặc relay thêm vào đầu một tiêu đề mà backend chưa bao giờ đồng ý đọc. Ba điều kiện quyết định bạn đang nhìn thấy trường hợp nào: bản ghi công khai thực sự trỏ tới đâu, khối luồng gửi gì lên thượng nguồn, và tên nào mà máy khách SSH xác minh. Hãy xử lý theo thứ tự đó.

Hai ranh giới, hai triệu chứng

Sự cố ở biên trông giống như một trang trạng thái HTTP đến nơi lẽ ra phải có biểu ngữ SSH. Kết nối hoàn tất ở tầng TCP và những byte đầu tiên là văn bản thuộc về một máy chủ web. Đó là sự không khớp giao thức, không phải gói tin bị mất. Nó cũng cho bạn biết rằng biên đang cố ý phục vụ thứ khác cho tên đó.

Sự cố ở thượng nguồn trông khác. Kết nối tới được sshd, sshd đọc những byte không phải là trao đổi nhận dạng mà nó mong đợi, và phiên chết hoặc treo mà không bao giờ đưa ra khóa.

Hai trường hợp dễ nhầm lẫn vì cả hai đều tạo ra một máy khách kết nối rồi thất bại. Phản hồi giao thức đầu tiên bạn nhận được chính là thứ phân biệt chúng, nên nó phải nằm trong phiếu.

Tiêu đề PROXY là một thông điệp, không phải công tắc

Trong mô-đun luồng, proxy_protocol on chỉ bảo NGINX ghi một tiêu đề giao thức PROXY về phía thượng nguồn trước phần tải. Nó không bật proxy TCP và không liên quan gì đến mã hóa SSH. Đó là một ghi chú gửi cho người nhận. Nếu người nhận không đọc được nó, nó trở thành rác ở đầu luồng.

Dịch vụ nhận phải chủ động tiêu thụ tiêu đề đó. Một sshd bình thường mong đợi trao đổi nhận dạng SSH là những byte đầu tiên trên kết nối, nên một phần mở đầu bất ngờ phá vỡ bắt tay theo cách trông giống máy chủ bị hỏng.

stream {
    server {
        listen 2222;
        proxy_pass 10.77.0.20:22;
    }
}

Đoạn đó là toàn bộ một relay hoạt động cho một backend có thể tiếp cận qua VPN. Không có chỉ thị PROXY nào xuất hiện vì người nhận không nói giao thức đó, và sự vắng mặt ấy là một quyết định, không phải thiếu sót.

Cũng hãy tách hai hướng. Đặt proxy_protocol trên dòng listen nghĩa là NGINX mong máy khách của chính nó gửi tiêu đề trước; bật nó cho một máy khách SSH thông thường tạo ra đúng điều ngược lại với vấn đề mà mọi người thường cố giải quyết.

Tên máy chủ công khai thực sự đến được đâu

Một trang HTTP 400 trong phiên SSH là bằng chứng về biên. Có gì đó trên đường đi nói HTTP, và không có công việc nào với khóa hay tài khoản ở backend thay đổi được điều đó. Hãy ngừng thay đổi backend cho đến khi biên được giải quyết.

Bản ghi được proxy thông thường của Cloudflare mang lưu lượng HTTP và HTTPS được hỗ trợ trên các cổng xác định. Bật proxy cho một tên máy chủ không tạo ra relay TCP tổng quát, và chuyển SSH sang cổng 443 không biến nó thành HTTPS.

Có hai hướng khả thi. Một bản ghi chỉ DNS có thể trỏ tới relay TCP của riêng bạn, điều này đặt quyết định phơi bày vào tay bạn. Ngoài ra, hãy dùng một sản phẩm ghi rõ việc mang SSH, với cấu hình nguồn gốc, máy khách và truy cập của chính nó.

Dù bạn chọn gì, relay vẫn cần một tuyến VPN tới backend, một kết nối được phép và một đường quay về. Tuyến không phải tùy chọn chỉ vì phía công khai hoạt động.

Giữ danh tính SSH ổn định qua một bí danh

Người dùng thường muốn tiếp tục gõ tên máy chủ hiện có của họ. Một bí danh trong cấu hình SSH có thể làm điều đó mà không thay đổi gì trên relay, và giữ thay đổi ở phía máy khách nơi nó thuộc về.

Host git.example.com
    HostName ssh-entry.example.net
    Port 2222
    User git
    HostKeyAlias git.example.com

Không có HostKeyAlias, OpenSSH tra khóa máy chủ dưới tên mà nó kết nối tới, nên mục nhập di chuyển và mỗi người dùng thấy cảnh báo khóa đã thay đổi trong lần dùng đầu tiên. Đặt bí danh giữ các mục known-hosts ổn định trong khi kết nối vẫn đi tới relay.

Bí danh này chỉ áp dụng cho các kho lưu trữ từ xa dựa trên SSH. URL Git qua HTTPS không tra cứu nó, và URL từ xa điển hình phải khớp với phương thức vận chuyển mà bạn thực sự đã chuẩn bị.

Điều bạn không được làm là tắt xác minh khóa máy chủ để cảnh báo biến mất. Điều đó gỡ bỏ một biện pháp bảo vệ mà việc sửa chuyển tiếp chưa bao giờ yêu cầu chạm vào, và biến một phiền toái về hình thức thành sự phơi bày thật sự.

Xác minh từng chặng riêng

Kiểm tra trình lắng nghe công khai một mình, rồi kết nối từ relay tới backend từ máy chủ relay, và chỉ sau đó mới kiểm tra máy khách từ đầu đến cuối. Mỗi một trong ba phép thử đó loại trừ một tầng khác nhau. Bỏ qua một phép nghĩa là hai kết quả còn lại không thể diễn giải. Ba quan sát, ba nơi mà sự cố có thể sống.

Giữ địa chỉ đích, cổng và những byte giao thức đầu tiên cùng với mỗi kết quả. Bộ ba đó phân biệt lỗi biên với vấn đề định tuyến VPN và với thất bại xác thực SSH, và đó là khác biệt giữa một sửa chữa và một phỏng đoán.

Cuối cùng, hãy ghi lại sự phơi bày dự kiến. Một relay TCP mang SSH tới backend riêng là một cửa mở có chủ đích trong vành đai công khai, và nó xứng đáng được xem xét như mọi dịch vụ vào khác.

Bài viết liên quan