Как эффективно и безопасно делиться множеством секретов в кластере Kubernetes? И, возможно, попутно изучите внутреннюю работу Kubernetes.

Рассмотрим следующую ситуацию: вы установили новый ElasticSearch в своем кластере Kubernetes, возможно, используя Elastic Cloud on Kubernetes (ECK).

Поскольку вы глубоко заботитесь о защите своей инфраструктуры, вы выпускаете сертификат для включения связи TLS между серверной частью приложения и API-интерфейсом ElasticSearch. Это то, что ECK делает для вас действительно хорошо, так что будем благодарны!

$ kubectl -n es get secrets -o name
secret/default-token-pbvfd
secret/es-remote-ca
secret/http-ca-internal
secret/es-http-certs-internal
secret/es-http-certs-public
secret/es-transport-ca-internal
secret/es-transport-certs-public
secret/es-elastic-user
secret/es-internal-users
secret/es-xpack-file-realm
secret/es-transport-certificates
secret/es-default-es-config

Этот es-http-certs-public выглядит особенно многообещающим, и быстрый осмотр показывает, что он содержит CA и публичный сертификат нового экземпляра ES. Как только мы нашли то, что нам нужно, мы хотим использовать этот секрет в наших приложениях, развернутых в нескольких пространствах имен. Конечно, эти пространства имен отличаются от пространства имен es выше, в котором живет ES.

Но нет! 😩 Секреты - это ресурсы с пространством имен, и поэтому на них можно ссылаться только из того же пространства имен. Так как же сделать этот секрет доступным в других пространствах имен?

Начиная с ленивого решения

Одна вещь, которую разделяет каждый технически подкованный человек, - это способность эффективно копировать / вставлять. Превратим это умение в прибыль. Мы назовем пространство имен, в котором находится наше приложение, app, потому что у меня нет никакого вдохновения.

$ kubectl -n es get secrets es-http-certs-public -o yaml | kubectl apply -n app -f -
error: the namespace from the provided object "es" does not match the namespace "app". You must pass '--namespace=es' to perform this operation.

Давай попробуем:

$ kubectl -n es get secrets es-http-certs-public -o yaml | sed '/namespace.*/d' | kubectl apply -n app -f -
secret/es-http-certs-public created
$ kubectl -n app get secret -o name
secret/default-token-4vlrv
secret/es-http-certs-public

Прохладный! Работает. Затем вы можете смонтировать этот секрет в своем модуле приложения для безопасного обсуждения с ES API. Тяжелая работа! Давай назовем это днем, но все же ...

Вы просыпаетесь на следующий день, и ваше приложение сообщает о сбое связи с ES API. Но до сих пор все работало нормально, верно? Вы быстро понимаете, что скопированный секрет исчез! 😱

$ kubectl -n app get secret -o name
secret/default-token-4vlrv
<It should be here! Please come back>

Kubernetes подводит меня!

Кто удалил этот секрет? Наверняка это новый шумный стажер, которого вы наняли на прошлой неделе 🤔 Вы просматриваете журналы аудита Kubernetes и, наконец, находите виновника: system:serviceaccount:kube-system:generic-garbage-collector. Твоя тяжелая 5-минутная работа вчера ушла, она уничтожена жестоким сборщиком мусора!

Возможно, вам стоило внимательно прочитать документацию Kubernetes о концепции владения. Особенно в этой части:

Зависимые в пространстве имен могут указывать владельцев в области кластера или в пространстве имен. Владелец с пространством имен должен существовать в том же пространстве имен, что и зависимый. В противном случае ссылка на владельца рассматривается как отсутствующая, а зависимый подлежит удалению после проверки отсутствия всех владельцев.

Если бы мы взглянули на удаленный секрет, мы бы увидели, что у нашего скопированного секрета есть владелец, которым является ресурс ElasticSearch:

metadata:
  namespace: app
  ownerReferences:
  - apiVersion: elasticsearch.k8s.elastic.co/v1
    blockOwnerDeletion: true
    controller: true
    kind: Elasticsearch
    name: es
    uid: c7c85fe4-ef48-4933-84aa-4c7dd0d86d79

Согласно документации, владелец ресурса должен существовать в том же пространстве имен или в области кластера, что здесь не так: владелец ElasticSearch все еще живет, но в пространстве имен es! Так что сборщик мусора по праву посчитал секрет бесхозным и удалил его.

Но почему его не удалили раньше? Или почему мне вообще разрешили творить такую ​​мерзость? На самом деле это не должно было быть разрешено, и секрет был удален после перезапуска диспетчера контроллеров. Проблема исправлена ​​в Kubernetes 1.20 через два года. Но немногие из нас используют передовую версию Kubernetes, особенно у провайдера общедоступного облака 👀

Вооружившись этими новыми знаниями, вы больше никогда не будете копировать собственный ресурс Kubernetes! Хорошо, но, может быть, мы все же сможем повторить попытку в последний раз и удалить блок ownerReference? .. Конечно, это сработает, но должно быть лучшее решение.

Входит в отражатель

Reflector от Emberstack - небольшой, но удобный проект. Он написан на C #, но я перейду к нему из-за того, насколько хорошо он работает.

Reflector - это надстройка Kubernetes, предназначенная для отслеживания изменений ресурсов (секретов и конфигурационных карт) и отражения изменений зеркальных ресурсов в том же или другом пространстве имен.

Развертывание очень простое, одна простая команда Kubectl, и все готово. Теперь мы просто аннотируем наш секрет в пространстве имен es:

$ kubectl -n es annotate secret es-http-certs-public reflector.v1.k8s.emberstack.com/reflection-auto-enabled=true 
  
secret/es-http-certs-public annotated
$ kubectl -n es annotate secret es-http-certs-public reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces=app
secret/es-http-certs-public annotated

И вот, наш секрет снова в пространстве имен app, ура! 🎉

$ kubectl -n app get secret -o name
secret/default-token-4vlrv
secret/quickstart-es-http-certs-public

Но на этот раз ownerReference больше нет, поскольку Reflector знает, как правильно копировать. Более того, решение не ограничивается секретами, и вы также можете таким образом распространять карты конфигурации или сертификаты диспетчера сертификатов.

Заключение

Я твердо уверен, что чем проще решение, тем лучше, но эта поучительная история показывает, что это не всегда так.

Однако такого рода проблемы неожиданно заставляют вас многое узнать о внутренней работе Kubernetes и открыть для себя новые полезные инструменты для элегантного решения проблем. Оглядываясь назад, я благодарен за то, что мне пришлось решить столько проблем! 🤗

👋 Присоединяйтесь к FAUN сегодня и получайте похожие истории каждую неделю на свой почтовый ящик! Получите еженедельную дозу обязательных к прочтению технических статей, новостей и руководств.

Подписывайтесь на нас в Twitter 🐦 и Facebook 👥 и Instagram 📷 и присоединяйтесь к нашим Facebook и Linkedin Группы 💬

Если этот пост был полезен, пожалуйста, несколько раз нажмите кнопку хлопка 👏 ниже, чтобы выразить поддержку автору! ⬇