فرستادن بایت‌های رمزگذاری‌شده بدون آنکه هرگز گواهی در دست باشد کاری است که یک رله TLS passthrough انجام می‌دهد، و این چیدمان هم راحت است و هم کمی گیج‌کننده. چون چیزی رمزگشایی نمی‌شود، هیچ چیز به شکل HTTP برای فیلتر کردن وجود ندارد، پس بلوک location معمول و قواعد دسترسی آن اینجا به کار نمی‌آید. تصمیمی که NGINX می‌تواند بگیرد درباره خود اتصال است: کدام peer شبکه در زده است و آیا باید اصلاً عبور داده شود.

تصمیم به stream تعلق دارد، نه به HTTP

در بستر stream، NGINX با نشست‌های TCP کار می‌کند. نشانی peer اتصال را می‌بیند و می‌تواند قواعد allow و deny مرتب‌شده را پیش از رسیدن هر بایتی به backend روی آن اعمال کند. این یک تصمیم کامل پذیرش است و به کلید خصوصی، گواهی یا تجزیه HTTP نیازی ندارد.

MechanismWhat it decidesWhere it lives
stream allow/denyWhether this TCP peer is relayedstream server block
ssl_preread mapWhich backend a named connection goes tostream, with the preread module
HTTP location ruleWhether an HTTP request is servedhttp server block

آن سه ردیف هرگز جای یکدیگر را نمی‌گیرند. کپی کردن یک دستور دسترسی HTTP در هر پرونده‌ای که پورت 443 را ذکر می‌کند چیزی را تغییر نمی‌دهد، چون سرور stream هرگز بستر http را نمی‌خواند.

پیش از عبور دادن، اتصال را بپذیرید

فرض کنید نصب موجودی با ماژول‌های stream و stream-access در دسترس است، کارخواهان VPN نشانی‌های مبدأ را در 10.90.0.0/24 نگه می‌دارند، و backendی در 192.168.50.20:443 از قبل هویت HTTPS موردنظر را ارائه می‌دهد.

stream {
    server {
        listen 443;

        allow 10.90.0.0/24;
        deny all;

        proxy_pass 192.168.50.20:443;
    }
}

این را به‌عنوان قطعه‌ای از یک listener جدید بخوانید، نه جایگزین مستقیم یک پیکربندی در حال کار. ابتدا listenerها و includeهای موجود را بررسی کنید، چون listener دوم روی پورتی که از قبل اشغال شده در reload شکست می‌خورد، نه در زمان درخواست.

به آنچه غایب است توجه کنید: هیچ listen ... ssl، هیچ دستور گواهی. NGINX جریان رمزگذاری‌شده را عبور می‌دهد و backend TLS را پایان می‌دهد و گواهی‌ای را ارائه می‌کند که کارخواه اعتبارسنجی می‌کند. کارخواهی که در allowlist رد شود نشست TCP‌اش رد می‌شود، نه صفحه HTTP 403، و هر ابزاری که انتظار کد وضعیت داشته باشد چیز بی‌فایده‌ای گزارش می‌کند.

allowlist چه چیزی را پوشش می‌دهد و چه چیزی را نه

اگر رله از قبل backendها را با نام سرور انتخاب می‌کند، ssl_preread و یک map می‌توانند آن کار را ادامه دهند، به شرط در دسترس بودن ماژول. نام هنوز توسط کارخواه ارائه می‌شود و هیچ چیز در ارائه یک نام اثبات نمی‌کند که کارخواه به VPN پیوسته است.

قاعده نمونه کل listener مربوط به stream را پوشش می‌دهد. این آن را برای یک نقطه ورود که ترکیبی از سایت‌های عمومی و سایت‌های فقط VPN را سرو می‌کند نامناسب می‌کند، جایی که استثنا برای هر نام لازم می‌شد؛ listenerهای جدا معمولاً از سیاستی وابسته به نام که هیچ‌کس نمی‌تواند بخواند روشن‌ترند.

ارزش دارد دو شکاف دیگر را نام ببریم. تطابق پیشوند چیزی درباره این که بسته از کدام رابط آمده نمی‌گوید، و یک قاعده HTTP در جای دیگر نمی‌تواند این listener را محدود کند. هر دو دلیلی برای نگه داشتن سیاست ورود در سطح میزبان در تصویر است، به‌جای آنکه یک خط allow را تمام مرز بدانیم. مرز را به‌صورت دو کنترلی بنویسید که باید هم‌خوان باشند، تا تغییر در هر یک از آن‌ها بازبینی شود.

NGINX در واقع نشانی چه کسی را می‌بیند؟

یک متعادل‌کننده بار، پراکسی دیگر یا source NAT می‌تواند واسطه‌ای جلوی NGINX بگذارد، پس peerی که می‌بیند نشانی داخلی کارخواه VPN نیست. پیش از انتخاب پیشوند مسیر واقعی را بررسی کنید، چون allowlistی که برای نشانی اشتباه نوشته شده یا همه را پشت مترجم می‌پذیرد یا هیچ‌کس را.

پروتکل PROXY و مدیریت IP واقعی پاسخ‌های مشروعی هستند و باید فقط برای فرستنده‌های سازگار و صریحاً مورد اعتماد پیکربندی شوند. هر دو سازوکار آنچه فرستنده می‌گوید را باور می‌کنند، و دقیقاً به همین دلیل فهرست فرستنده‌ها باید کوتاه باشد. اعتماد به سرصفحه هویت از هر کارخواه اینترنتی اطلاعات مبدأ را دوباره قابل اعتماد نمی‌کند؛ رد درست را به پذیرش جعلی تبدیل می‌کند.

هر دو نتیجه را پیش از reload آزمایش کنید

پیکربندی را اعتبارسنجی کنید، reload کنید و سپس دو بار آزمایش کنید: یک نشست مجاز تازه که باید کار کند، و یکی ردشده که نباید. اعتبارسنجی معمول گواهی backend را در آزمایش مجاز نگه دارید، چون رله‌ای که وصل می‌شود اما نمی‌تواند backend را اعتبارسنجی کند یک مشکل را حل کرده و مشکل دیگری ساخته است.

nginx -t
ss -tnp | grep ':443'

مسیر backend و پاسخ را هم جداگانه بررسی کنید. عبور از allowlist فقط ثابت می‌کند که NGINX نشست را پذیرفته است؛ نمی‌تواند backendی که در دسترس نیست را به پاسخ وادار کند و نمی‌تواند مسیر بازگشتی را که پیش از شروع شما نبود تعمیر کند.

مقالات مرتبط