თქვენი ლეპტოპი მწვანე გვირაბს აჩვენებს, კლიენტის ჟურნალი ამბობს, რომ მარშრუტები გაიგზავნა, და ერთადერთი მისამართი, რომელიც პასუხობს, თავად VPN სერვერის გვირაბის IP-ია. მის მიღმა პინგები იღუპება, რასაც არ უნდა დაუმიზნოთ, იქნება ეს ClusterIP, სხვა pod-ის მისამართი თუ საჯარო ჰოსტის სახელი. ეს კომბინაცია ბუნდოვანი არ არის, არამედ დიაგნოსტიკურია: დეკაპსულაცია მუშაობს, ხოლო მეორე ნახტომი — არა.

ამას შევხვდი Debian-ის კვანძზე, რომელზეც chart-ით დაყენებული OpenVPN-ის იმიჯი მუშაობდა, და გვირაბი მარტივი ნაწილი იყო. კლიენტმა მიიღო 10.8.0.x იჯარა, 10.8.0.1-მა უპასუხა, ხოლო 10.96.0.10-მა, კლასტერის DNS სერვისმა, დრო ამოწურა. სერვერის ჟურნალში არაფერი ავადმყოფურად არ ჩანდა, და სწორედ ამიტომ იწყებენ ადამიანები iptables-ის წესების გადაწერას, რომლებსაც არასდროს სჭირდებოდათ შეხება.

VPN pod არის როუტერი, და ამის პირდაპირ თქმა ღირს. დაშიფრული პაკეტები მოდის, იხსნება თავად pod-ის ქსელურ namespace-ში, და შემდეგ უნდა გავიდეს სხვა ინტერფეისით. Linux უარყოფს ამ მეორე ნაბიჯს, თუ გადაცემა ჩართული არ არის სწორედ იმ namespace-ის შიგნით.

რას აღწევს კლიენტი და რას — ვერა

პასუხის მიმცემი მისამართი გვირაბის ბოლო წერტილს ეკუთვნის, და VPN პროცესი მას ლოკალურად ფლობს, ამიტომ გადაცემა საერთოდ არ მონაწილეობს. ყველა დანარჩენი, მათ შორის სხვა pod, სერვისის VIP ან ინტერნეტი, მოითხოვს, რომ ბირთვმა პაკეტი tun0-დან eth0-ზე გადაიტანოს. როცა ეს გადატანა უარყოფილია, სიმპტომი ერთგვაროვანი სიჩუმეა და არა უარყოფა, რადგან არაფერი აწარმოებს ICMP შეცდომას უკან გვირაბში. თქვენ იღებთ დროის ამოწურვებს და არა მიუწვდომლობის შეტყობინებებს, და ეს არის მინიშნება, რომ საერთოდ არავინ მარშრუტიზაციას აკეთებს.

ორი წუთი კლასიფიკაცია ავიწროებს შრეს. თუ DNS სახელები ვარდებიან, მაშინ როცა სერვისის IP-ზე ნედლი პინგები წარმატებულია, პრობლემა DNS-ის სანტექნიკაშია და არა გადაცემაში. თუ peer-ის მისამართის მიღმა ყველა დანიშნულება დროში იწურება, შიშველი IP-ის ჩათვლით, დაიწყეთ namespace-იდან.

წაიკითხეთ პარამეტრი namespace-ის შიგნით

ყოველი pod იღებს საკუთარ ქსელურ namespace-ს, და net.ipv4.ip_forward არის sysctl თითოეული namespace-ისთვის. კვანძზე მისი შეცვლა კონტეინერის შესახებ არაფერს გეუბნებათ, და ეს არის საიმედო გზა შუადღის არასწორ მანქანაზე გასატარებლად.

kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0

ნული ადასტურებს დიაგნოზს. მნიშვნელობა ასევე არ მიიღება მემკვიდრეობით კვანძის გაშვების კონფიგურაციიდან: ის იწყება იმიჯის ნაგულისხმევიდან ყოველ ჯერზე, როცა კონტეინერი იქმნება. ამიტომ kubectl exec ... sysctl -w-ით ხელით გამოყენებული შესწორება ქრება შემდეგ გადატვირთვაზე და ბრუნდება როგორც შეფერხებით გამოვლენილი ხარვეზი.

ჩართვა ისე, რომ manifest-მა შეინარჩუნოს

გამძლე ვარიანტია init კონტეინერი, რომელიც მუშაობს იმავე pod sandbox-ში და წერს მნიშვნელობას VPN კონტეინერის დაწყებამდე. pod-ის კონტეინერები იზიარებენ ქსელურ namespace-ს, ამიტომ პარამეტრი გადადის მთავარ კონტეინერში.

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 pod-ს უარყოფს, ამას შექმნის დროს იგებთ, რაც სულ ცოტა გულახდილი და ადვილად წასაკითხია.

უფრო სუფთა ალტერნატივაა pod-ის დონეზე securityContext.sysctls სია, რომელიც kubelet-ს საშუალებას აძლევს გამოიყენოს namespace-ური sysctl-ები ყოველგვარი კონტეინერისთვის პრივილეგიის მიცემის გარეშე. ის მოიცავს მხოლოდ კლასტერის დაშვებული სიის სახელებს. არის თუ არა net.ipv4.ip_forward ამ სიაში, დამოკიდებულია იმაზე, როგორ იყო კონფიგურირებული kubelet, და pod, რომელიც სთხოვს sysctl-ს მის გარეთ, უარყოფილია admission-ზე ან რჩება CreateContainerConfigError-ში, სანამ sandbox ხელახლა სცდება. შეამოწმეთ დაშვებული სია, სანამ ივარაუდებთ, რომ ველი გატეხილია.

სანამ რომელიმე მიდგომას ხელით ააწყობთ, ნახეთ, ხომ არ აჩვენებს chart უკვე გადამრთველს, ხშირად რაღაც ipForwardInitContainer: true-ის მსგავსს. chart-ის მნიშვნელობის გამოყენება პატარად ინახავს თქვენს override ფაილს და გადაურჩება შემდეგ განახლებას, რასაც ხელით დაპატჩული Deployment-ის ცვლილებები ვერ აკეთებს.

მეორე ნახევარი: დაბრუნების გზა და პოლიტიკა

ჩართული გადაცემა აუცილებელია, მაგრამ არა საკმარისი. თუ კლიენტები იყენებენ კერძო აუზს, რომლისკენაც კლასტერის ქსელს მარშრუტი არ აქვს, პასუხები ვერ პოულობენ გზას უკან გვირაბში, და pod-მა ეს ტრაფიკი თავისი დანიშნულებისკენ უნდა შენიღბოს.

პოლიტიკა ამაზე ზის. NetworkPolicy ობიექტები და ღრუბლის firewall-ის წესები ფასდება იმ წყაროს მისამართის მიმართ, რომელსაც პაკეტი ტრანსლაციის შემდეგ ატარებს, ამიტომ კლიენტის აუზისთვის დაწერილი წესი შეიძლება ჩუმად შეწყვიტოს შესაბამისობა, როგორც კი შენიღბვა ჩაირთვება.

როცა კლიენტებს მხოლოდ კლასტერის შიგნით არსებულ სერვისებზე სჭირდებათ წვდომა, VPN-ის სერვისის VIP-ზე დასრულება უფრო მცირე დიზაინია, ვიდრე pod-ების ქსელში მარშრუტიზაცია. ის ასევე სრულად აშორებს კლიენტის აუზს CNI-ის მარშრუტიზაციის ცხრილიდან.

წარუმატებელი ნახტომის იზოლირება კლიენტისგან

იმუშავეთ გარეთკენ და გაჩერდით პირველ წყნარ საფეხურზე. დაიწყეთ VPN peer-ით, შემდეგ სცადეთ რომელიმე pod-ის მისამართი, შემდეგ სერვისის VIP, და მხოლოდ ამის შემდეგ საჯარო დანიშნულება. ყოველი წარმატება საზღვარს ერთი ნახტომით ამოძრავებს, და ყოველი მარცხი ასახელებს შრეს, რომელიც ღირს შემოწმებად. ნებისმიერი გაშვების შემდეგ შედით exec-ით და ისევ წაიკითხეთ sysctl, რადგან ჩანაცვლებული pod იწყება იმიჯის ნაგულისხმევიდან, და შესწორება, რომელიც არასდროს ყოფილა manifest-ში, უკვე წავიდა.

Kubernetes-ის დოკუმენტაცია კლასტერში sysctl-ების გამოყენების შესახებ ჩამოთვლის, რომელი სახელების დაყენება შეიძლება pod-ის უსაფრთხოების კონტექსტით, და ეს არის პირველი ადგილი, სადაც უნდა შეხედოთ, როცა admission უარყოფს ცვლილებას.

დაკავშირებული სტატიები