← All posts

انقل حالة Terraform بعيدًا عن الإنترنت العام (من دون إقامة VPN)

Authagonal·June 22, 2026
terraformsecurityzero-trustdevopsazure

ملف حالة Terraform لديك هو القطعة الأكثر حساسية على الإطلاق في سحابتك. إنه خريطة كاملة لكل مورد تشغّله، وبحسب مزوّديك فإنه يحتوي أيضًا على أسرار بنص صريح: سلاسل الاتصال، وكلمات المرور المولّدة، والمفاتيح. وبشكل افتراضي يعيش هذا الملف في حساب تخزين سحابي بنقطة نهاية عامة، محميًا بما لا يزيد عن مفتاح وصول. وإذا تسرّب ذلك المفتاح، فلن يضطر المهاجم إلى تعداد بنيتك التحتية. فقد سلّمته المخطط بنفسك.

نحن نبيع المصادقة. ومزوّد مصادقة يترك مفاتيح مملكته الخاصة على الإنترنت المفتوح ليس له أن يحمل مفاتيحك. لذا فإن حساب الحالة الإنتاجي لدينا ليس له أي سطح عام على الإطلاق. والوصول إلى ذلك يحمل ثلاثة مزالق، وقد تلمّسنا شكل كلٍّ منها قبل أن نضبطه على الصواب.

المزلق الأول: مأزق البيضة والدجاجة

تحتاج الحالة البعيدة إلى backend موجود سلفًا قبل أن يتمكن Terraform من العمل. لكن الـ backend هو ذاته بنية تحتية، وتودّ أن يديره Terraform. لا يمكنك استخدام حساب التخزين لتخزين حالة حساب التخزين الذي لم يوجد بعد.

المخرج هو إقامة (bootstrap) مدروسة من مرحلتين. تعمل المرحلة الأولى بحالة محلية وتنشئ الأساس بالضبط: حساب تخزين الحالة، والشبكة التي سيعيش فيها، ومسار الوصول. ثم تقلب المرحلة الثانية كتلة الـ backend من المحلية إلى البعيدة، وتُرحّل ملف الحالة الموجود الآن إلى الحساب الذي أنشأته للتو. ومن تلك اللحظة فصاعدًا، تدير طبقة الإقامة تلك نفسها بنفسها عن بُعد مثل كل شيء آخر. إنها بضع دقائق تشعر فيها وكأنك واقف على سلّم لا تزال تبنيه، ثم تنتهي إلى الأبد.

المزلق الثاني: مشكلة الوصول، وضريبة بوابة VPN

جعل الحساب خاصًا يقتصر على سطر واحد: أطفئ الوصول العام للشبكة وضع نقطة نهاية خاصة أمامه. الآن صار حساب التخزين قابلًا للوصول فقط من داخل شبكتك الافتراضية. وهذا بالضبط هو المشكلة، لأن الشيء الذي يحتاج إلى الوصول إليه أكثر من غيره، أي خط أنابيب CI لديك، ليس داخل شبكتك الافتراضية. ولا أنت كذلك.

الجواب المدرسي هو إقامة VPN خاص بك. بوابة VPN مُدارة، أو مضيف bastion، أو point-to-site مع شهادات العميل. وكل من فعل هذا يعرف الضريبة: البوابة مكلفة وبطيئة في التجهيز، و point-to-site يعني سكّ شهادات عميل وتدويرها، وكل مشغّل جديد هو طقس إعداد، والـ bastion صندوق آخر يجب ترقيعه ودفع ثمنه. إنها كمية كبيرة من البنية التحتية القائمة التي وظيفتها كلها "إتاحة وصول الأشخاص الموثوقين إلى شيء خاص".

لقد تخطّيناها كلها. فبدلًا من بوابة VPN، يعمل موصل zero-trust صغير كحاوية داخل الـ VNet، وهي الفئة التي تشغلها Tailscale و Twingate و Cloudflare Access. ينضم إلى شبكة متداخلة واعية بالهوية. ويصل الأشخاص المخوّلون وخط أنابيب CI إلى نقطة النهاية الخاصة عبر تلك الشبكة المتداخلة، مع مصادقة لكل هوية، ووصول محدود النطاق بالضبط على المورد الواحد الذي يحتاجه. لا بوابة، ولا IP عام، ولا شهادات للتدوير، ولا صندوق قفز. يرفع الـ CI اتصاله طوال مدة التشغيل ثم يهدمه بعدها. تختفي مشكلة الوصول من دون فاتورة البنية التحتية القائمة.

المزلق الثالث: الإغلاق الذي لا يمكنك فعله بخطوة واحدة

الغريزة الواضحة هي إعلان الحساب خاصًا منذ البداية، في نفس عملية apply لـ Terraform التي تنشئه. افعل ذلك تقطع الحبل قبل أن يوجد المسار الخاص: تحتاج عملية الـ apply إلى كتابة الحالة عبر نقطة النهاية العامة، ونقطة النهاية الخاصة و DNS غير موصولين بعد، فتحبس Terraform، وتحبس نفسك، خارج الحساب ذاته الذي تنشئه. لقد فكّرنا في هذا بتروٍّ قبل أن نطلقه، وهي المرة الوحيدة التي يعيش فيها التشغيل التجريبي في رأسك بدلًا من الطرفية.

لذا فإن الإغلاق هو خطوة منفصلة مدروسة، لا تُنفَّذ إلا بعد أن تكون الشبكة، ونقطة النهاية الخاصة، والموصل كلها قائمة ومُثبَتة. أمر واحد يقلب الوصول العام للشبكة إلى معطّل. وفي اللحظة التي ينزل فيها، تختفي نقطة النهاية العامة، وتصبح قائمة السماح القديمة للـ IP بلا معنى لأنه لم يعد هناك أي سطح عام يُسمح لأي شيء بالدخول إليه، ويصل كل تشغيل مستقبلي إلى الحالة عبر الشبكة المتداخلة. وقد تحقّقنا منه بالطريقة الوحيدة التي تُحتسب: بالتأكد من أن الحساب صار يستجيب من المسار الخاص ويرفض المسار العام.

النصف الآخر: لا كلمة مرور تُسرَق

قتل نقطة النهاية العامة يزيل باب الشبكة. والخطوة المقابلة هي التأكد من أنه لا يوجد مفتاح قائم خلفه كذلك. خط أنابيبنا لا يحمل أي بيانات اعتماد سحابية. إنه يصادق باستخدام workload identity federation: يقدّم نظام الـ CI رمز OIDC قصير العمر، وتثق السحابة بذلك الرمز لمستودع واحد محدد، وتعيد وصولًا ينتهي خلال دقائق. لا يوجد سرّ service principal قابع في خزنة بانتظار التسرّب، لأنه لا يوجد سرّ من الأساس.

ويتبع الوصول إلى الحالة القاعدة نفسها. فـ Terraform يقرأ ويكتب كتلة (blob) الحالة برمز دليل قصير العمر مرتبط بتلك الهوية، لا بمفتاح وصول حساب التخزين. وهكذا فإن الشيئين اللذين يريدهما المهاجم أكثر من غيرهما، أي طريقة للدخول وبيانات اعتماد لاستخدامها، يخرجان في صورة نقطة نهاية خاصة فقط ورمز كان ينتهي صلاحيته أصلًا بينما هو يقرؤه. لا شيء ساكن لانتزاعه.

لماذا نتكبّد العناء

ملفات الحالة لا تتسرّب عادةً لأن أحدًا كسر التشفير. إنها تتسرّب لأن الحساب كان عامًا، وانتهى مفتاح إلى سجلٍّ أو fork أو حاسوب محمول، ولم يقف شيء آخر في الطريق. وإزالة نقطة النهاية العامة تُخرج صنف "تسرّب المفتاح" بأكمله من نموذج التهديد. فيصير المفتاح عديم الفائدة من دون أن يكون أيضًا على الشبكة المتداخلة.

إنه المبدأ نفسه الذي نبني عليه المنتج: لا تضع الأمان خلف بوّابة من الجهد أو الفئة، بل افعله فحسب، لأن البديل هو ما تندم عليه في الثانية صباحًا. كل ميزة أمان نطرحها للعملاء، SSO و SAML، و SCIM، و MFA، و webhooks المفروضة، وتصدير التدقيق، مفعّلة في كل خطة، وليست محجوزة لترقية مؤسسية. اطّلع على ما هو مُضمَّن.