Kubernetes Operators: розбираємось на прикладі сікретів

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Я Олександр Воробйов, AWS Cloud Architect з більш ніж десятирічним досвідом. В SoftServe ми допомагаємо клієнтам з усього світу в оптимізації їхньої хмарної інфраструктури з погляду ефективності використання cloud-технологій, оптимізації витрат тощо.

Сьогодні я хочу поговорити про Kubernetes-оператори. Майже кожен проєкт, над яким ми працюємо, так чи інакше використовує Kubernetes. Щобільше, на основі нашого досвіду ми в SoftServe розробили платформу, яка дає нам можливість збирати Kubernetes-кластери з різних компонентів, як лего, додаючи необхідні модулі для логінгу та моніторингу, CD та сікретів.

На прикладі сікретів я хочу розглянути, чому взагалі існує така штука як Kubernetes-оператори та як вони допомагають в активностях Day 2.

Що таке Kubernetes-оператори

Дизайн Kubernetes-платформи відповідає двом базовим принципам. По-перше — це простота та гнучкість, а по-друге — можливість автоматизації якомога більше задач. З цього ми маємо як сильні сторони куба, так і його обмеження. Його API достатньо простий, а з іншого боку — API недостатньо для автоматизації багатьох процесів. Для цього і придумали Kubernetes-оператори.

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

Загалом, оператор визначається як програмне розширення, яке дозволяє працювати із застосунком, абстрагуючись від понять кубера як деплоймент, под, конфіг-мапа тощо. Оператори використовують Custom Resource (CR) для опису необхідного конфігурації застосунку та Custom Resource Definition (CRD) для опису його стану.

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

Якщо описати простими словами, то оператор — це застосунок, який працює в Kubernetes та використовує його API, щоб автоматизувати необхідні задачі.

Тепер, коли ми розібрались з тим, що таке Kubernetes-оператор та яка його роль, розгляньмо роботу такого оператора на прикладі.

Практичне застосування

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

Найпростіший випадок — це підключення до бази даних або авторизація в зовнішньому API. Для того, щоб це зробити застосунку, треба, по-перше, знати адресу, де зовнішній ресурс розташований, а по-друге — логін-деталі, тобто ім’я користувача з паролем, токен авторизацій тощо.

Ці дані часто зберігаються в зовнішній системі, у випадку AWS це може бути або Parameter Store, або SecretsManager, або, якщо клієнт хоче використовувати рішення без прив’язки до хмар, — Hashicorp Vault.

Ці паролі, токени, адреси зовнішніх ресурсів треба забрати з місця, де вони зберігаються, а далі передати їх в Kubernetes та створити сікрет. Також було б непогано, якби за зміни значення в хмарному сервісі secret-ресурс в Kubernetes також оновлювався.

Стандартний API Kubernetes нічого не знає про зовнішні системи збереження ресурсів — у нього є API для створення і роботи з сікретами Kubernetes та й все. Тому нам треба мати щось, що буде спілкуватися з зовнішніми системами збереження секретних даних з одного боку, а з іншого — створювати та оновлювати сікрети в Kubernetes. Тут нам і допомагає Kubernetes Operator.

Для роботи з сікретамі Kubernetes спільнота створила External Secrets Operator (ESO). Він розв’язує задачу синхронізації сікрет-ресурсів в Kubernetes з відповідними значеннями в системах зберігання як Hashicorp Vault, AWS SecretsManager та інших.

Розгляньмо на прикладі ESO, як працює Kubernetes-оператор.

Тож, ESO використовує Custom Resource(CR) для того, щоб розширити та доповнити Kubernetes API. Перелік CR, які використовує ESO, можна подивитись тут.

Нижче — список CRD, які були задеплоєні ESO:

#kubectl get crd -o json | jq -r '.items[]|select(.metadata.name | contains("external-secrets.io"))|.metadata.name'
acraccesstokens.generators.external-secrets.io
clusterexternalsecrets.external-secrets.io
clustersecretstores.external-secrets.io
ecrauthorizationtokens.generators.external-secrets.io
externalsecrets.external-secrets.io
fakes.generators.external-secrets.io
gcraccesstokens.generators.external-secrets.io
passwords.generators.external-secrets.io
pushsecrets.external-secrets.io
secretstores.external-secrets.io
vaultdynamicsecrets.generators.external-secrets.io
webhooks.generators.external-secrets.io

Як ми бачимо, ESO створив CRD, які розширюють можливості стандартного Kubernetes API, за допомогою яких відстежує статус та конфігурацію ресурсів. З CRD користувач Kubernetes-кластера може створювати додаткові ресурси, які не доступні за замовчуванням, такі як secretstore та externalsecret.

Нижче наведено приклад ресурсу clustersecretstore, через якого ми описуємо, де розташовується наше сховище паролів або інших параметрів та як авторизуватися, щоб отримати до нього доступ:

❯ k get clustersecretstore ps-cluster-default-secretstore -o yaml
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  creationTimestamp: "2024-03-06T08:46:15Z"
  generation: 4
  labels: 
           argocd.argoproj.io/instance: argo-proj
  name: ps-cluster-default-secretstore
  resourceVersion: "3251005210"
  uid: 4385f262-f8e1-4719-9b51-0d474b678864
spec:
  provider:
aws:
   auth:
     jwt:
       serviceAccountRef:
         name: external-secret-default-secretstore
         namespace: external-secrets
   region: us-east-1
   service: ParameterStore
status:
  capabilities: ReadWrite
  conditions:
  - lastTransitionTime: "2024-03-06T08:46:31Z"
message: store validated
reason: Valid
status: "True"
type: Ready

В цьому прикладі ми створюємо secretstore, який буде надавати нам доступ до даних, які зберігаються в AWS Systems Manager Parameter Store. Та для того, щоб мати доступ до цього сервісу, ESO-оператор цього secretstore буде використовувати сервіс-акаунт з іменем external-default-secretstore.

Але для створення кінцевого сікрет-ресурсу, який буде використовуватись застосунками, встановленими в Kubernetes-кластер, нам необхідно мати опис того, що саме ми хочемо забирати зі сховища та який саме сікрет нам треба створювати. Для цього оператор ESO має інший CR externalsecret:

kubectl get externalsecret -n secret my-external-secret -o yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  creationTimestamp: "2024-03-30T18:49:32Z"
  generation: 1
  labels:
argocd.argoproj.io/instance: argo-proj
  name: my-eso-resource
  namespace: secret
  resourceVersion: "3264145932"
  uid: 0493c90d-a709-47d9-b492-88ab0ebe8118
spec:
  data:
  - remoteRef:
   conversionStrategy: Default
   decodingStrategy: None
   key: /apps/cloud-runtime/security/my-secret/secret-token
   metadataPolicy: None
secretKey: SECRET_TUNNEL_TOKEN
  refreshInterval: 1h
  secretStoreRef:
kind: ClusterSecretStore
name: ps-cluster-default-secretstore
  target:
creationPolicy: Owner
deletionPolicy: Retain
template:
   engineVersion: v2
   mergePolicy: Replace
status:
  binding:
name: my-secret-tunnel-token
  conditions:
  - lastTransitionTime: "2024-04-10T15:19:31Z"
message: Secret was synced
reason: SecretSynced
status: "True"
type: Ready
  refreshTime: "2024-04-12T11:19:48Z"

Ну і нарешті, коли ми створили externalsecret-ресурс та все правильно вказали, ESO за допомогою цих CRD створить сікрет-ресурс, який ми зможемо використати в нашому застосунку:

#k get secrets -n secret my-secret-tunnel-token -o yaml
apiVersion: v1
data:
  SECRET_TUNNEL_TOKEN: 1234567890
immutable: false
kind: Secret
metadata:
  annotations:
  creationTimestamp: "2024-03-30T18:49:32Z"
  labels:
reconcile.external-secrets.io/created-by: b4b359b6d2e71b206b53004058721c29
  name: orca-tunnel-token
  namespace: orca
  ownerReferences:
  - apiVersion: external-secrets.io/v1beta1
blockOwnerDeletion: true
controller: true
kind: ExternalSecret
name: my-secret-tunnel-token
uid: 0493c90d-a709-47d9-b492-88ab0ebe8118
  resourceVersion: "3193039237"
  uid: f10ebe7b-4885-4ad9-9809-4842191ad72b
type: Opaque

Тобто за допомогою двох ресурсів, secretstore та externalsecret, ми описали, де в нас зберігаються значення необхідних параметрів, як ці значення забрати з зовнішнього ресурсу та як створити сікрет об’єкт в Kubernetes, який буде містити ці дані.

Також за допомогою параметру refreshInterval ресурсу externalsecret ми налаштували період оновлення значення сікрет-ресурсу, якщо це значення зміниться в зовнішній системі.

Тобто ми розширили стандартний API Kubernetes та додали можливість автоматичного створення сікрет-ресурсів та також автоматичного завантаження даних з зовнішніх систем зберігання параметрів або сікретів.

З погляду кінцевого застосунку, який працює в Kubernetes, він споживає сікрет-ресурс, який для нього створив ESO, та взагалі не в курсі, як той ресурс створено та звідки взялись дані. Таким чином, в адміністратора Kubernetes-кластера є можливість зміни зовнішнього провайдера параметрів та сікретів.

Якщо ми хочемо переїхати з AWS SystemsManager ParameterStore на, наприклад, Hashicorp Vault, все, що нам треба зробити, — це оновити secretstore-ресурс, щоб він забирав дані з іншого ендпоінту та перевірити, що externalsecrets-ресурс посилається на коректний шлях в зовнішньому провайдері.

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

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному4
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

трохи ріже глаз сікрет. Секрет же.

І не забути про безпеку кредів від сервіс аккаунту external-default-secretstore

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

Тільки я не бачу сенсу у такій безпеці. Якщо, припустимо, у результаті всіх цих солжностей самі секрети лежать у файлах/энвах, то хакер ламане аппку, прочитає креди і їх зіллє інфу.

... ок, а ще секрети можуть лежати в env’i, й якщо хакер ламане аппку — прочитає через getenv syscall :D

... та й взагалі вийде з Container Runtime’у й захопить AWS через діру в KVM’і

Замість того щоб заморачуватись з кредами — їх треба ролити й робити одноразовими, для всього.

Підписатись на коментарі