Linux GitOps Docker K8S Kubernetes Infrastructure as Code Configuration management Management
05/21/2021
Моє знайомство з GitOps почалося не так давно. До цього, працюючи з Kubernetes кластером та Kubernetes в цілому, ми використовували CI для доставки коду. Користувалися різними інструментами, на кшталт helm чи kubectl, і постійно стикалися з певними проблемами, які виникали через невідповідність стейту на самому кластері. З часом ми перейшли на GitOps і вже успішно використали цей підхід на кількох проєктах. У цій статті розглянемо суть та принципи GitOps, поговоримо про безпеку Pipelines та їхню реалізацію.
У роботі з GitOps можна виділити чотири головні принципи:
1. Декларативність
2. Версіонування
3. Автоматизоване розгортання
4. Системні агенти
GitOps підхід має певні переваги, які включають в себе продуктивність, ефективність та стабільність. Розгляньмо кожну з цих переваг більш детально:
1. Продуктивність
Система завжди надає нам зворотний зв’язок. Цей процес відбувається безперервно. Тобто кожного разу, коли ми робимо якусь зміну, система каже нам “все ок”, або “в процесі”, або “щось пішло не так”. Таким чином ми розуміємо, що відбувається після того, як ми зробили зміну, та зменшуємо час на деплоймент.
2. Краща якість роботи
Нові інженери та розробники не мають прямого доступу до системи. Натомість вони керують тільки маніфестами, які зберігаються в репозиторії. GitOps допомагає їм працювати з кластером, не маючи до нього прямого доступу.
3. Стабільність
Ми завжди маємо аудит того, що відбувається в системі. Ми бачимо кожну зміну та її історію — хто що робив, хто що накоїв. Маючи GitOps, ми також можемо отримати SOC 2 сертифікацію. Тобто за допомогою GitOps інфраструктура відповідає певним Security Compliance.
Використання GitOps у роботі може принести вашому проєкту наступні переваги:
1. Надійність
Крім того, що GitOps надає можливість робити rollback, він також дозволяє вам бачити, з якою швидкістю йде деплоймент. Кожна ваша зміна одразу попадає в кластер. Якщо вам знадобиться відновити кластер, це займе лічені хвилини.
2. Послідовність
Ви завжди маєте одне місце, в якому робите зміни, один репозиторій, який застосовує зміни до всіх концептів. Це і моніторинг, і логування, і сервери застосунків, і безпека — все знаходиться в одному репозиторії.
PS. Так можна розділяти застосунки розробників, щоб покращити досвід співпраці між командами та щоб розділити повноваження до кластера.
3. Безпека та аудит
Git гарантує постійний контроль змін. Він також дає можливість підписувати зміни, тобто їх затверджувати за допомогою різних воркфловів, перевірок, аудитів безпеки та pull/merge запитів, які повинні перевірятися іншими людьми.
В основі GitOps знаходяться три головні складові — Pipelines, Control та Observability. Вони гарантують безперервне знаходження вашого застосунку у певному стані. Ми можемо об’єднати Control та Observability, оскільки ці речі можна контролювати за допомогою Pipeline. А Pipeline, зі свого боку, — це основа автоматизації нашого деплойменту. Вона базується на основі Git репозиторію, який і є відображенням нашої інфраструктури та наших напрацювань. Git надає нам безпеку, що гарантується набором перевірок, про які ми поговоримо далі.
Безпека ваших пайплайнів починається з обмеження доступу до кластера. Доступ до нього має бути тільки у DevOps або infrastructure інженерів. Інші члени команди чи користувачі інфраструктури, яким потрібно буде розміщувати застосунки чи додаткові системні ресурси, повинні отримати доступ тільки до репозиторію, в межах якого вони повинні працювати.
Те саме стосується і сторонніх сервісів. Наприклад, час від часу нам може знадобитися надати доступ таким програмам, як terraform cloud або platform9 чи spotlight. Якщо на їхньому боці станеться якийсь інцидент чи виникне проблема з безпекою, зловмисники зможуть отримати доступ і до вашого акаунту. Тому потрібно переглянути практику надання повного доступу таким системам. Натомість надавайте їм тільки read-only доступ.
Крім того, при розробці застосунків, скажімо Node.js, ми часто використовуємо сторонні бібліотеки, які не завжди походять від офіційного виробника. Тобто, це може бути якийсь розробник, якому захотілось щось зробити. Він опублікував свій модуль, і ви його собі встановили. А цей модуль мав в собі зловмисне програмне забезпечення, і ваш код було доставлено разом з ним і це призвело до втрати чи шифруванню даних. Це може бути дуже небезпечно і може призвести до великих фінансових втрат.
Ще одну проблему з безпекою становить застаріла CI система. Простим прикладом може бути Jenkins server, в якому ви маєте безліч плагінів. Їх ніхто не оновлює, бо раптом щось не те зробиш і все зламається. А старі плагіни мають чимало слабких місць, які можуть бути використані зловмисниками і про які всі насправді знають. Тим не менш, не оновлені вчасно плагіни досі складають серйозну безпекову проблему на багатьох проєктах. Тому краще обмежити публічний доступ до СІ системи та лімітувати внутрішній трафік.
Також є ще поширена практика використовувати один СІ сервер на кілька команд. Припустимо, що є аутсорс компанія, яка має 10 проєктів. Для того, щоб не створювати 10 серверів і 10 СІ систем під кожен проєкт, компанія використовує один сервер на всіх. Таким чином ми даємо доступ багатьом розробникам до СІ системи, щоб вони могли самі створювати собі джоби, тощо. Таке трапляється часто, але робити це небажано.
Отже, проаналізувавши згадані небезпеки, можна сказати, що найчастіше проблеми виникають через так званий людський фактор. Хтось зробив щось не так, щось виконав не там де треба, чи поставив Cron джоби і все виконалось на продакшені замість стейджа. Наприклад, кілька років тому був інцидент з Amazon S3, коли працівник виконав не той Ansible скрипт не там де треба. І через нього перестав працювати цілий S3 сервіс в одному з регіонів.
Кілька рекомендацій, як ми можемо убезпечити себе від подібних ситуацій:
В інтернеті є чимало прикладів, коли Лінус Торвальд комітає щось у відкритий репозиторій, чим викликає подив і захоплення всіх, хто це бачить. Адже це сам Лінус Торвальд! Насправді, у більшості випадків це ніякий не Торвальд, а звичайна атака, коли зловмисники користується незахищеним доступом до репозиторію і вдають із себе когось іншого. Щоб вберегтися від цього ми можемо увімкнути обов'язковий підпис кожної зміни і мати GPG сертифікат, яким ми підписуємо кожен свій “git push”. Таким чином, якщо ми побачимо, що підпис відрізнявся від попереднього, ми можемо його або скасувати, або принаймні відстежити спробу шахрайства.
Ще одна потенційна загроза виникає тоді, коли розробники переписують історію і виконують форс пуш. Через це можуть з’явитися проблеми з порівнянням версій, можуть не співпадати git log чи просто виникнути великі merge конфлікти, які не завжди буде легко вирішити. Щоб не допускати такого, ми можемо заборонити форс пуш у мейн бенчу чи мастер. Також, про всяк випадок, варто робити бекап репозиторіїв.
І третій пункт — ми можемо розгортати наші Git репозиторії за допомогою GitOps. Terraform підтримує Git провайдера, і ми можемо описати в ньому те, яку структуру та налаштування повинен мати репозиторій. Часто користувачі не задумуються над безпекою в репозиторію і просто її ігнорують. А ми натомість форсуємо кожен репозиторій. Тобто навіть, якщо хтось з адмін правами піде і вимкне якісь галочки чи поміняє якісь параметри репозиторію, при наступному виконанні Terraform коду всі зміни будуть відновлені.
Більшість із нас стикалася з ситуацією, коли потрібно зберегти пароль в СІ системі. Що ми робимо в таких випадках? Додаємо пароль в environment variable нашої Pipeline чи в Jenkins секрети, чи навіть Amazon секрети. І в кожному разі створюємо потенційно небезпечну ситуацію. Адже варто вам добавити print, або echo в гілку чи зробити пост реквест на endpoint — все, ваші секрети перестають бути лише вашими. Надаючи доступ розробникам до репозиторію, ви в той самий момент надаєте їм можливість побачити ваші секрети.
То як варто зберігати секрети?
Написати на папірці або ж записати пароль на флешку та замкнути у сейфі. Це — найбезпечніше.
Інший варіант — Vault (HashiCorp Vault). Це крута штука, якою ми користувалися неодноразово, але вона несе з собою досить великий багаж налаштувань. Amazon Secret Manager — це теж непогана опція. Ми можемо її використовувати багато де, але в любому випадку нам прийдеться цей секрет спочатку отримати, ми ж все одно авторизовуємо CI Pipeline на те, щоб витягнути цей секрет. В результаті він буде розшифрований і CI система буде мати його у відкритому вигляді. Звісно, це спрацьовує не у всіх системах. Якщо вона бачить цей секрет, вона його сховає, але, на жаль, у випадку з post на endpoint вона цього не зробить. Тобто Secret Manager — це зручно, але його краще інтегрувати в Kubernetes і уникнути того, щоб використовувати плейн секрети безпосередньо в репозиторій.
Моїм улюбленим інструментом є Sealed Secret. Це, по суті, також шифрований файл, який ви зберігаєте в Git-і, але, щоб його застосувати, вам потрібно створити агент Kubernetes кластерів, який буде вичитувати ваші секрети з репозиторія. Після цього він вже на стороні кластера їх розшифрує. Це такий односторонній спосіб того, щоб доставляти секрети на кластері. Як все відбувається?
За допомогою kubeseаl ви шифруєте ваш секрет і додаєте його в Git репозиторій. Відповідно, ви навіть можете його опублікувати, адже його дуже важко розшифрувати. Ви налаштовуєте агент на те, щоб він контролював ваші секрети з певного репозиторію. І, як тільки він бачить, що з'явився чи змінився ресурс з назвою SealedSecret, він автоматично створює чи оновлює аналогічний дешифрований Secret в Kubernetes кластері. Таким чином Kubernetes кластер може отримувати доступ до секретів, не беручи участь у СІ процесі. Він буде просто поза ним.
Ще одним корисним інструментом є Git Crypt. Його можна застосовувати поверх Sealed Secret. Ви просто вказуєте, які файли повинні бути шифровані, й ці файли можуть бути розшифровані тільки в тому місці чи на тій машині, в якої є decryption key. Це, по суті, приватний ключ. Якщо ви просто завантажите (git clone) репозиторій, то ті файли, які були позначені Git Crypt-ом будуть зашифровані й будуть доступні тільки тим, хто має ключ шифрування.
Наразі існує два головних підходи до налаштування CD — Push-based і Pull-based. Давайте розглянемо їх трохи детальніше.
Push-based підхід є більш стандартним майже в усіх організаціях. Це найпростіший підхід, який найлегше організувати. У Push-based підході у вас є репозиторій, система автоматизації — СІ система чи Jenkins — чи будь-який інший СІ сервер. Ви також маєте певний інструмент — Kubectl, Helm, Terraform тощо. І, звісно, у вас є Kubernetes та image репозиторій. Вам потрібно створити застосунок і після цього дати Kubernetes кластеру команду: “візьми цей image за допомогою деплойменту тощо”. Це є прямий Push-based підхід. Чому Push-based? Бо ви напряму кажете: “СІ система, візьми і додай собі ці зміни”.
Тепер давайте розглянемо Рull-based підхід. Push-based базується на децентралізований системі доступів, тобто СІ система має доступ тільки до репозиторіїв та до AWS ECR чи будь-якого іншого Docker репозиторію, чи до репозиторію артефактів. Кожний етап розділений, і ніхто не заходить за його межі. У випадку, якщо хтось втрутиться, він зможе отримати доступ чи тільки до Image Repo, чи до якогось іншого кроку. До кластера доступ є тільки у DevOps/Infrastructure інженерів, а основні зміни можуть попадати тільки після проходження всіх етапів перевірок та попадання в основну гілку і відповідно з репозиторіїв, які дозволені в кластер агенті.
Можна розглянути Pull-based систему на основі Agro-CD. Це агент, який допомагає нам застосовувати зміни в Kubernetes кластері. За допомогою Agro-CD ми можемо отримати Multicluster архітектуру. Скажімо, ми маємо якийсь мастер кластер, в якого є централізований моніторинг, логування чи деплоймент. Ви додаєте інші агенти в інші кластери і вказуєте, що ваш мастер знаходиться там. Це все налаштовується елементарним встановленням агента. Для того, щоб налаштовувати кілька кластерів одночасно, використовується Apps pattern. Це, по суті, така тавтологія. Це набір застосунків, який має в собі інші застосунки. Звісно, що Agro-CD повинен мати доступ до тих чи інших кластерів, але сертифікат і key повинен бути збережений в ньому.
В Agro-CD ми налаштовуємо елементарні речі, наприклад, назву застосунку, namespace завжди має бути agrocd. Тобто ми вказуємо Git репозиторій і, відповідно, вказуємо шлях, де лежить наш Helm чарт чи наші yaml файли.
Ми також маємо finalizer в кожного ресурсу, який створений Agro CD. Що він нам дає? Коли ми видаляємо застосунок, ми можемо отримати orphan ресурси. Тобто застосунок створив за собою деплоймент, Horizontal Pod Autoscaler, купу сервісів, секретів і різних ресурсів. Якщо ми просто видалимо застосунок, то вони так і лишаться неконтрольовані. Тобто, додаючи finalizer, Agro-CD отримує сповіщення про те, що цей застосунок повинен бути видалений. Тоді він спочатку видаляє всі ресурси, які були створені цим застосунком, а після того вже видаляє цей застосунок із кластера.
Сам же AppProject — це, по суті, логічна одиниця, в якій ми описуємо структуру застосунка. Ми вказуємо, куди вона має розгортатися, точніше на який кластер. Також namespace, який буде дозволений і в який відбудеться розгортання. Ми також зазначаємо репозиторії, з яких можливі зміни. І основне — права, які ми даємо тому чи іншому проєкту. Припустимо, в нас є кілька проєктів, які мають свої репозиторії і над якими працюють різні девелопери. Але нам треба якось їх обмежити. За допомогою APP Project ми створюємо їм певні обмеження, наприклад, дозволяємо їм деплоїти тільки в одному namespace. В останньому пункті ClusterResourceWhitelist ми додаємо те, що можна робити в межах цього проєкту. Ми там вказуємо, до прикладу, що тільки для певного namespace цей проєкт зможе працювати. Якщо ми захочемо створити якусь кластер роль, ми просто цього зробити не зможемо. Таким чином ми захищаємо себе від несанкціонованого доступу з боку розробників. Якщо вони захочуть розширити свої права в межах кластеру, вони просто цього зробити не зможуть.
GitOps - це хороший спосіб покращити процес доставки змін та застосунків в Kubernetes кластер. Але варто врахувати, що він підійде не всім. Його потрібно впроваджувати комплексно. Тобто вам потрібно підготувати зміни до Git Workflow, до інфраструктури, до CI системи, чи навіть зовсім від неї відмовитися (!). Також потрібно буде провести тренінг розробникам, а то й розробити додаткову документацію. І звісно, пояснити клієнту для чого ви це робите. Вставновити ArgoCD чи FluxCD агента це 5 хвилин, а стабільна і налагоджена робота на всіх етапах виконання автоматизації може тривати й кілька місяців!
Все ж я рекомендую кожному, хто працює, чи планує працювати з Kubernetes, спробувати реалізувати POC GitOps, хоча б на Minikube. За цим майбутнє!
Дякую всім хто дочитав до цього моменту і пам’ятайте “With great power comes great responsibility!”.