Kubernetes-এ OpenVPN পড কিছুই ফরওয়ার্ড করে না? ip_forward দেখুন
ক্লায়েন্টরা VPN পডে পিং করে আর তার পরে কিছুই পায় না। নেমস্পেসে ফরওয়ার্ডিং বন্ধ, আর সমাধানকে admission, রিস্টার্ট ও রিটার্ন পাথ পার হতে হবে।
আপনার ল্যাপটপ সবুজ টানেল দেখাচ্ছে, ক্লায়েন্ট লগ বলছে রুট পুশ হয়েছে, আর উত্তর দেয় একমাত্র VPN সার্ভারের নিজের টানেল IP। এর পরে যেকোনো লক্ষ্যেই পিং করুন না কেন তা মারা যায়, সেটি ClusterIP হোক, অন্য পডের ঠিকানা হোক বা পাবলিক হোস্টনেম হোক। এই সমন্বয়টা অস্পষ্ট নয়, নির্ণায়ক: ডিক্যাপসুলেশন কাজ করছে, আর দ্বিতীয় হপ করছে না।
আমি এটা পেয়েছি একটি Debian নোডে, যেখানে chart দিয়ে ইনস্টল করা OpenVPN ইমেজ চলছিল, আর টানেল ছিল সহজ অংশ। ক্লায়েন্ট 10.8.0.x লিজ নিল, 10.8.0.1 উত্তর দিল, আর 10.96.0.10, ক্লাস্টার DNS সার্ভিস, টাইমআউট হয়ে গেল। সার্ভার লগে কিছুই অসুস্থ দেখায়নি, আর ঠিক এজন্যই মানুষ iptables নিয়ম পুনর্লিখন শুরু করে যেগুলো তাদের কখনো দরকারই ছিল না।
একটি VPN পড হলো একটি রাউটার, আর এটা স্পষ্ট করে বলা দরকার। এনক্রিপ্টেড প্যাকেট আসে, পডের নিজের নেটওয়ার্ক নেমস্পেসে খোলা হয়, তারপর অন্য একটি ইন্টারফেস দিয়ে বেরোতে হয়। Linux এই দ্বিতীয় ধাপটি প্রত্যাখ্যান করে, যদি ওই নেমস্পেসের ভেতরে ফরওয়ার্ডিং চালু না থাকে।
ক্লায়েন্ট কী পৌঁছাতে পারে আর কী পারে না
যে ঠিকানাটি উত্তর দেয় সেটি টানেল এন্ডপয়েন্টের, আর VPN প্রসেসটি স্থানীয়ভাবে সেটির মালিক, তাই ফরওয়ার্ডিং একেবারেই জড়িত নয়। বাকি সবকিছু, অন্য পড, সার্ভিস VIP বা ইন্টারনেট, কার্নেলকে tun0 থেকে eth0 পর্যন্ত একটি প্যাকেট সরাতে হয়। এই সরানো প্রত্যাখ্যাত হলে লক্ষণটি প্রত্যাখ্যান নয়, সমান নীরবতা, কারণ টানেলের নিচে ফেরত কোনো ICMP ত্রুটি তৈরি হয় না। আপনি টাইমআউট পান, আনরিচেবল বার্তা নয়, আর এটাই ইঙ্গিত যে কেউ আদৌ রাউট করছে না।
দুই মিনিটের শ্রেণিবিন্যাস স্তরটিকে সংকুচিত করে। যদি DNS নাম ব্যর্থ হয় অথচ সার্ভিস IP-তে কাঁচা পিং সফল হয়, সমস্যাটি ফরওয়ার্ডিংয়ে নয়, DNS প্লাম্বিংয়ে। যদি পিয়ার ঠিকানার পরে প্রতিটি গন্তব্য টাইমআউট হয়, খালি IP সহ, তবে নেমস্পেস থেকে শুরু করুন।
নেমস্পেসের ভেতরের সেটিংটি পড়ুন
প্রতিটি পড নিজের নেটওয়ার্ক নেমস্পেস পায়, আর net.ipv4.ip_forward হলো প্রতি-নেমস্পেস sysctl। নোডে এটি বদলালে কনটেইনার সম্পর্কে কিছুই জানা যায় না, আর এটা ভুল মেশিনে বিকেল কাটানোর নির্ভরযোগ্য উপায়।
kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0
শূন্য নির্ণয় নিশ্চিত করে। মানটি নোডের রানটাইম কনফিগারেশন থেকেও উত্তরাধিকারসূত্রে আসে না: প্রতিবার কনটেইনার তৈরি হলে এটি ইমেজের ডিফল্ট থেকে শুরু হয়। তাই kubectl exec ... sysctl -w দিয়ে হাতে প্রয়োগ করা সমাধান পরের রিস্টার্টে হারিয়ে যায় এবং মাঝে মাঝে দেখা দেওয়া ত্রুটি হিসেবে ফিরে আসে।
ম্যানিফেস্ট যাতে ধরে রাখে সেভাবে চালু করা
টেকসই বিকল্প হলো একটি init কনটেইনার, যা একই পড স্যান্ডবক্সে চলে এবং VPN কনটেইনার শুরুর আগে মানটি লেখে। একটি পডের কনটেইনাররা একটি নেটওয়ার্ক নেমস্পেস ভাগ করে, তাই সেটিংটি মূল কনটেইনারে চলে যায়।
initContainers:
- name: enable-forwarding
image: busybox:1.36
command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
securityContext:
privileged: true
ওই privileged: true লাইনটিই রিভিউয়াররা আপত্তি করেন, আর তারা ঠিকই করেন। sysctl লেখার জন্য হয় প্রিভিলেজ, নয় সংকীর্ণ পরিসরের কোনো সক্ষমতা দরকার, আর সীমিত Pod Security Standard চালানো ক্লাস্টার প্রিভিলেজড init কনটেইনার সরাসরি প্রত্যাখ্যান করতে পারে। যদি admission পডটি প্রত্যাখ্যান করে, আপনি তৈরি হওয়ার সময়ই জানতে পারেন, যা অন্তত সৎ ও পড়তে সহজ।
আরও পরিষ্কার বিকল্প হলো পড-স্তরের securityContext.sysctls তালিকা, যা kubelet-কে কোনো কনটেইনারকে প্রিভিলেজ না দিয়েই নেমস্পেসড sysctl প্রয়োগ করতে দেয়। এটি কেবল ক্লাস্টারের অনুমোদিত তালিকার নামগুলোই কভার করে। net.ipv4.ip_forward ওই তালিকায় আছে কি না তা নির্ভর করে kubelet কীভাবে কনফিগার করা হয়েছে তার উপর, আর এর বাইরের sysctl চাওয়া পড admission-এ প্রত্যাখ্যাত হয় বা স্যান্ডবক্স পুনরায় চেষ্টা করার সময় CreateContainerConfigError-এ আটকে থাকে। ফিল্ডটি নষ্ট বলে ধরে নেওয়ার আগে অনুমোদিত তালিকা দেখুন।
যেকোনো একটি পদ্ধতি হাতে গড়ার আগে দেখুন chart-টি সুইচটি ইতিমধ্যে প্রকাশ করে কি না, প্রায়ই ipForwardInitContainer: true এর মতো কিছু হিসেবে। chart-এর মান ব্যবহার করলে আপনার override ফাইল ছোট থাকে এবং পরের আপগ্রেডে টিকে যায়, যা হাতে প্যাচ করা Deployment সম্পাদনা পারে না।
দ্বিতীয় অর্ধ: রিটার্ন পাথ ও নীতি
ফরওয়ার্ডিং চালু থাকা প্রয়োজনীয়, যথেষ্ট নয়। যদি ক্লায়েন্টরা এমন একটি প্রাইভেট পুল ব্যবহার করে যার জন্য ক্লাস্টার নেটওয়ার্কে কোনো রুট নেই, উত্তরগুলো টানেলে ফিরে যাওয়ার পথ খুঁজে পায় না, আর পডটিকে সেই ট্রাফিক তার গন্তব্যের দিকে মাস্কারেড করতে হয়।
নীতি তার উপরে বসে। NetworkPolicy অবজেক্ট ও ক্লাউড ফায়ারওয়াল নিয়মগুলি প্যাকেট অনুবাদের পরে যে সোর্স ঠিকানা বহন করে তার বিরুদ্ধে মূল্যায়ন করা হয়, তাই ক্লায়েন্ট পুলের জন্য লেখা একটি নিয়ম মাস্কারেড চালু হলে চুপচাপ মেলানো বন্ধ করতে পারে।
যখন ক্লায়েন্টদের কেবল ক্লাস্টারের ভেতরের সার্ভিসে পৌঁছাতে হয়, তখন VPN-কে সার্ভিস VIP-তে শেষ করানো পড নেটওয়ার্কে রাউট করার চেয়ে ছোট নকশা। এটি ক্লায়েন্ট পুলকে CNI-এর রাউটিং টেবিলের বাইরে রাখে।
ব্যর্থ হপটিকে ক্লায়েন্ট থেকে আলাদা করা
বাইরের দিকে কাজ করুন এবং প্রথম নীরব ধাপে থামুন। VPN পিয়ার দিয়ে শুরু করুন, তারপর কোনো পডের ঠিকানা, তারপর একটি সার্ভিস VIP, আর কেবল তারপর একটি পাবলিক গন্তব্য। প্রতিটি সাফল্য সীমান্তকে এক হপ এগিয়ে দেয়, আর প্রতিটি ব্যর্থতা যে স্তরটি দেখা দরকার তার নাম বলে। যেকোনো রোলআউটের পরে ভেতরে exec করে sysctl আবার পড়ুন, কারণ প্রতিস্থাপিত পড ইমেজের ডিফল্ট থেকে শুরু হয়, আর ম্যানিফেস্টে কখনো না থাকা সমাধান ইতিমধ্যেই চলে গেছে।
Kubernetes ডকুমেন্টেশন ক্লাস্টারে sysctl ব্যবহার সম্পর্কে তালিকা দেয় কোন নামগুলো পড সিকিউরিটি কনটেক্সটের মাধ্যমে সেট করা যায়, আর admission পরিবর্তনটি প্রত্যাখ্যান করলে সেটাই প্রথম দেখার জায়গা।