GitOps Approach and Best Practices

Моє знайомство з GitOps почалося не так давно. До цього, працюючи з Kubernetes кластером та Kubernetes в цілому, ми використовували CI для доставки коду. Користувалися різними інструментами, на кшталт helm чи kubectl, і постійно стикалися з певними проблемами, які виникали через невідповідність стейту на самому кластері. З часом ми перейшли на GitOps і вже успішно використали цей підхід на кількох проєктах. У цій статті розглянемо суть та принципи GitOps, поговоримо про безпеку Pipelines та їхню реалізацію.

Що таке GitOps і як з ним працювати?

Отже, GitOps — це еволюція infrastructure as code підходу. Він допомагає суттєво покращити ефективність роботи розробників, в тому числі DevOps інженерів. GitOps — це також операційна модель, яка базується на багаторічному досвіді інженерів та містить набір принципів та методів, які пришвидшують усі процеси, розгортання та роботи. Працюючи з GitOps, варто пам’ятати, що всі зміни, конфіги та системи мають бути версіоновані. Крім того, код також повинен мати версію, до прикладу теги чи бренчі. Це допоможе вам зберігати стейт кожного середовища, і відповідно легче робити оновлення чи ролбеки.

Принципи GitOps

У роботі з GitOps можна виділити чотири головні принципи:

1. Декларативність

Ваша система має бути описана декларативно. Ви маєте описувати всі зміни, які робите, щоб в подальшому ви змогли їх легко прочитати та порівняти.

2. Версіонування

Їх ми зберігаємо в коді, тобто в git-і. Таким чином, в будь-який час можна переглянути, що в нас є в мастер гілці, і це буде відображенням того, що в нас є в системі.

3. Автоматизоване розгортання

Кожна затверджена зміна повинна автоматично розгортатися в певній системі. Це може бути Kubernetes кластер, конфігураційні файли, застосунок, чи налаштування якогось елементарного сертифікат-менеджера.

4. Системні агенти

Останній принцип — це агенти, які встановлені у вашій системі і які відповідають за розгортання змін. Вони перевіряють версії, порівнюють стани з попереднім і поточним, і сповіщають вас про певні проблеми, конфлікти чи помилки в синтаксисі. Таким чином ви завжди отримуєте зворотний зв’язок.

Переваги GitOps

GitOps підхід має певні переваги, які включають в себе продуктивність, ефективність та стабільність. Розгляньмо кожну з цих переваг більш детально:

1. Продуктивність

Система завжди надає нам зворотний зв’язок. Цей процес відбувається безперервно. Тобто кожного разу, коли ми робимо якусь зміну, система каже нам “все ок”, або “в процесі”, або “щось пішло не так”. Таким чином ми розуміємо, що відбувається після того, як ми зробили зміну, та зменшуємо час на деплоймент. 

2. Краща якість роботи

Нові інженери та розробники не мають прямого доступу до системи. Натомість вони керують тільки маніфестами, які зберігаються в репозиторії. GitOps допомагає їм працювати з кластером, не маючи до нього прямого доступу.

3. Стабільність

Ми завжди маємо аудит того, що відбувається в системі. Ми бачимо кожну зміну та її історію — хто що робив, хто що накоїв.  Маючи GitOps, ми також можемо отримати SOC 2 сертифікацію. Тобто за допомогою GitOps інфраструктура відповідає певним Security Compliance.

Як GitOps покращує роботу

Використання GitOps у роботі може принести вашому проєкту наступні переваги:

1. Надійність

Крім того, що GitOps надає можливість робити rollback, він також дозволяє вам бачити, з якою швидкістю йде деплоймент. Кожна ваша зміна одразу попадає в кластер. Якщо вам знадобиться відновити кластер, це займе лічені хвилини.

2. Послідовність

Ви завжди маєте одне місце, в якому робите зміни, один репозиторій, який застосовує зміни до всіх концептів. Це і моніторинг, і логування, і сервери застосунків, і безпека — все знаходиться в одному репозиторії. 
PS. Так можна розділяти застосунки розробників, щоб покращити досвід співпраці між командами та щоб розділити повноваження до кластера.

3. Безпека та аудит

Git гарантує постійний контроль змін. Він також дає можливість підписувати зміни, тобто їх затверджувати за допомогою різних воркфловів, перевірок, аудитів безпеки та pull/merge запитів, які повинні перевірятися іншими людьми. 

Три складові GitOps

В основі 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 сервіс в одному з регіонів.
Кілька рекомендацій, як ми можемо убезпечити себе від подібних ситуацій:

  1. Не надавайте доступ до продакшену. Дайте своїй команді можливість робити зміни у власних гілках, а в основну гілку тільки через Pull requests. Якщо зміни для продакшн середовища, то обов'язково з ревю процесом від іншого інженера, тощо. Розділяйте відповідальність, щоб додати більше пунктів контролю. 
  2. Кожен коміт завжди повинен перевірятися на статичний аналіз будь-якими лінтерами чи іншими перевірками. В Python я нерідко використовую елементарні перевірки на довжину стрічки, на правильність використання методів, на складність методів тощо.
  3. Додавайте етапи перевірки. Включайте не тільки лінтери, але також розгортайте ваш код на sandbox-і. Ви можете запустити Docker контейнер, перевірити чи все відбулося і видалити його.
  4. Використовуйте сторонні системи, які допоможуть вам перевіряти ваш код на відповідність вимогам. Наприклад, такі системи можуть перевірити ваші плагіни на наявність слабких місць і надати вам зворотний зв’язок. 

Загрози в Git

В інтернеті є чимало прикладів, коли Лінус Торвальд комітає щось у відкритий репозиторій, чим викликає подив і захоплення всіх, хто це бачить. Адже це сам Лінус Торвальд! Насправді, у більшості випадків це ніякий не Торвальд, а звичайна атака, коли зловмисники користується незахищеним доступом до репозиторію і вдають із себе когось іншого. Щоб вберегтися від цього ми можемо увімкнути обов'язковий підпис кожної зміни і мати 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-ом будуть зашифровані й будуть доступні тільки тим, хто має ключ шифрування. 

Push та pull підходи для налаштування CD

Наразі існує два головних підходи до налаштування 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!”.

Read also

Terraform for Beginners How and Why?

Terraform is an IAC tool, used primarily by DevOps teams to automate various infrastructure tasks.

When does IT Outsourcing work? And when doesn’t it?

IT outsourcing, especially nearshore IT outsourcing, is a big, quickly growing industry. If you are reading this, the chances are you are а stakeholder of one kind or another in the industry, and know that why is not rocket science. Internationally, there’s a skills gap between demand for and supply of IT specialists. And the gap is biggest in the most developed economies, pushing up rates to levels that can be difficult to commercially reconcile with business cases. If the specialists can be hired at all, retention becomes an issue.