Vault-ის გადაყვანა Shamir-დან transit auto-unseal-ზე და ოთხი ხაფანგი გზაზე
Vault-ის პოდის ყოველი გადატვირთვა დალუქული საცავით და გაყინული საიდუმლოებების სინქრონიზაციით სრულდებოდა. როგორ დავამატეთ transit პროვაიდერი, გადავიყვანეთ სამნოდიანი raft კლასტერი და სად წავიბორძიკეთ.
Optimacros-ში ჩვენი Vault Kubernetes-ში მუშაობდა სამნოდიან HA raft კლასტერად — Shamir-ზე, auto-unseal-ის გარეშე. ეს ნიშნავდა, რომ პოდის ნებისმიერი გადატვირთვა მას დალუქულს აბრუნებდა და გასაღების სამი წილის ხელით შეყვანა იყო საჭირო. ორ კვირაში ეს ხუთჯერ მოხდა ზედამხედველობის გარეშე და კიდევ ოთხჯერ ნოდების პაჩინგისას. ყოველი seal Vault Secrets Operator-ს ყინავდა: სინქრონიზებული 55 საიდუმლოებიდან 53-მდე დღეობით ეკიდა, ერთხელ — 32 საათი შეუმჩნევლად.
ეს სხვა სამუშაოსაც ბლოკავდა. ნოდების პაჩინგი ყოველ ჯერზე სამ-ოთხ ხელით unseal-ს მოითხოვდა, ზედამხედველობის გარეშე გადატვირთვაზე ლაპარაკიც არ შეიძლებოდა, ხოლო Vault-ის ერთი პოდის ძველი რევიზიიდან გადაყვანაც კი შეუძლებელი იყო გასაღების წილებით მზად მდგომი ადამიანის გარეშე. ბაგი არ იყო: ინფრასტრუქტურაში უბრალოდ არ არსებობდა KMS ან transit პროვაიდერი, რომლის მეშვეობითაც შესაძლებელი იქნებოდა გახსნა.
მოწყობა
პატარა გამოყოფილი VM ახლა Docker-ში მეორე Vault-ს მართავს raft-ზე, transit პროვაიდერის როლში. მასში აპლიკაციების საიდუმლოებები არ არის — მხოლოდ transit გასაღები, რომელიც კლასტერის მასტერ-გასაღებს ხსნის.
- TLS თვითხელმოწერილ CA-ზე, რომელიც Vault-ის პოდებში არის მიმაგრებული და
tls_ca_cert-ით დაფიქსირებული. არანაირიtls_skip_verify: გახსნის გზა MITM-ისთვის მისაწვდომი არ უნდა იყოს. - ავთენტიფიკაცია — პერიოდული orphan ტოკენი, რომლის პოლიტიკა ზუსტად ორ გზას უშვებს: encrypt და decrypt ერთ transit გასაღებზე. პოდებში ის Git-ის გარეთ შექმნილი Kubernetes Secret-ით ხვდება. Vault მას თავად აგრძელებს.
- Transit VM ჩატვირთვისას თავად იხსნება ლოკალური გასაღებების ფაილიდან — წინააღმდეგ შემთხვევაში ამ ერთი ჰოსტის გადატვირთვა კლასტერის ავარიად იქცეოდა.
კლასტერის მხარე GitOps-ით შევიდა, შემდეგ — seal-ის ერთჯერადი მიგრაცია. მიგრაციამდე გადავიღეთ raft-ის სნეპშოტი და შევინახეთ Shamir-ის თავდაპირველი წილები.
ხაფანგი 1: -config ორჯერ
ოფიციალური იმიჯის entrypoint თავად ამატებს -config=/vault/config-ს, თუ პირველი არგუმენტი server-ია. მე ჩემი -config=<file> დავამატე, Vault-მა კონფიგი ორჯერ ჩატვირთა და bind: address already in use-ით დაეცა აშკარად თავისუფალ პორტზე. გამოსავალი უბრალოდ command: server-ია.
ხაფანგი 2: ტოკენის ცვლადი
ტოკენი სტანდარტული VAULT_TOKEN-ით გადაეცემა. არსებობს VAULT_TRANSIT_SEAL_* ცვლადების ოჯახი გასაღების სახელისა და მონტირების გზისთვის, ამიტომ VAULT_TRANSIT_SEAL_TOKEN დამაჯერებლად გამოიყურება. მაგრამ Vault მას არ კითხულობს.
ხაფანგი 3: app-of-apps-მა ცვლილება დამალა
Argo CD Vault-ის აპლიკაციას ახალ რევიზიაზე Synced-ად აჩვენებდა, ცოცხალ კონფიგში კი seal-ის სექცია არ იყო. თავად Application ობიექტს მშობელი აპლიკაცია არენდერებს, მშობელი კი ჯერ კიდევ ძველ რევიზიაზე იდგა. ჯერ მშობელს ვარეფრეშებთ, შემდეგ შვილს.
ხაფანგი 4: -migrate ყველა პირზე
ეს იყო მთავარი. ახალი seal სექციით პოდების გადატვირთვის შემდეგ Vault ლოგში წერს, რომ seal-ის მიგრაციის რეჟიმში შევიდა და ავტომატურად არ გაიხსნება, მაშინაც კი, თუ autoseal კონფიგურირებულია. მიგრაცია მხოლოდ მაშინ სრულდება, როცა ყოველი პირი -migrate-ით და Shamir-ის წილებით გაიხსნება. ერთი გადაყვანილი ნოდი raft-ს კვორუმის გარეშე ტოვებს, კლასტერს კი — ლიდერის გარეშე. წილები სამივეს უნდა მიეწოდოს, თითოეულს — ზღვრული რაოდენობით.
მიღების ტესტი
მთელი აზრი ერთ შემოწმებაში იყო: Vault-ის პოდის წაშლა და არანაირი unseal ბრძანების გაცემა. ახალმა პოდმა დაწერა unsealed with stored key და თავად შევიდა კლასტერში. ეს იყო ზედამხედველობის გარეშე პირველი გადატვირთვა, რომელსაც ადამიანი არ დასჭირდა.
რას ვიხდით
- Transit VM ახლა Vault-ის გაშვების მკაცრი დამოკიდებულებაა. მომუშავე პოდები მომსახურებას აგრძელებენ, თუ ის გათიშულია, მაგრამ ნებისმიერი გადატვირთული პოდი დალუქული დარჩება. მისი თვითგახსნა, სნეპშოტები და მონიტორინგი ისევე მნიშვნელოვანია, როგორც თავად Vault-ის.
- საიდუმლოებების სინქრონიზაცია მიგრაციისას ნულამდე დაეცა და თავად არ აღდგა. ის სინქრონიზებულ ობიექტებზე
refreshAfter-ის შეცვლამ გააღვიძა. - Shamir-ის წილები შეინახეთ. ისინი უკან მიგრაციისთვის რჩება ძალაში.
რა წავიღოთ
- Shamir auto-unseal-ის გარეშე ყოველ გადატვირთვას ხელით ინციდენტად აქცევს. თუ ნოდებს აპაჩებთ — auto-unseal გჭირდებათ.
- Transit პროვაიდერს მინიმალური უფლებები სჭირდება: ერთი გასაღები, ორი გზა, დაფიქსირებული TLS.
- Seal-ის მიგრაცია მთელ კლასტერს ეხება. გაუშვით
-migrateყველა პირზე, თორემ ლიდერი არ აირჩევა. - App-of-apps-ში შვილის Synced არაფერს ნიშნავს, სანამ მშობელი ძველ რევიზიაზეა.
- ცვლილება მიიღეთ მხოლოდ მას შემდეგ, რაც ზედამხედველობის გარეშე გადატვირთული პოდი თავად გაიხსნება.