Потому что ваши ключи и секреты должны быть именно такими - секретными
Здравствуйте и добро пожаловать! Мы продолжаем путешествие Kubernetes в двух словах. В одном из предыдущих блогов мы видели, как настраивать приложения Kubernetes с помощью ConfigMap
object. В этом посте мы рассмотрим Kubernetes Secrets
и то, как их можно использовать для хранения конфиденциальных данных конфигурации, которые необходимо безопасно обрабатывать (например, учетные данные базы данных, ключи API и т. Д.).
Как обычно, это будет основано на примерах, и вы узнаете:
- как создать
Secrets
(CLI,yaml
и т. д.) и - различные способы их использования в ваших приложениях (переменные env, объемы и т. д.)
Код (и YAML
) доступен на GitHub.
Эта часть разделена на два логических раздела: способы создания Secrets
и методы использования Secrets
в ваших приложениях.
Предпосылки
Чтобы просмотреть примеры в этом посте, все, что вам нужно, это кластер Minikube и инструмент командной строки kubectl для доступа к кластеру.
Установите Minikube как одноузловой кластер Kubernetes на виртуальной машине на вашем компьютере. На Mac вы можете просто:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 \ && chmod +x minikube
sudo mv minikube /usr/local/bin
Установите kubectl для взаимодействия с кластером Minikube. На Mac вы можете:
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
Создание секретов
Давайте посмотрим на методы, с помощью которых вы можете создать Secret
.
Используйте раздел data
Можно создать Secret
вместе с данными конфигурации, хранящимися в виде пар "ключ-значение" в разделе data
определения.
apiVersion: v1
kind: Secret
metadata:
name: service-apikey
data:
apikey: Zm9vYmFy
Secret
содержит данные "ключ-значение", представляющие конфиденциальную информацию, где apikey
является ключом, а значение представляет собой строку в кодировке base64
.
Чтобы создать этот Secret
в Kubernetes:
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/secret-data.yaml
Чтобы упростить задачу, на файл YAML ссылаются непосредственно из репозитория GitHub, но вы также можете загрузить файл на свой локальный компьютер и использовать его таким же образом.
Чтобы подтвердить, что Secret
был создан:
kubectl get secret/service-apikey -o yaml
Вы получите ответ YAML, подобный следующему:
apiVersion: v1
data:
apikey: Zm9vYmFy
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"apikey":"Zm9vYmFy"},"kind":"Secret","metadata":{"annotations":{},"name":"service-apikey","namespace":"default"}}
creationTimestamp: "2019-12-17T11:11:27Z"
name: service-apikey
namespace: default
resourceVersion: "113009"
selfLink: /api/v1/namespaces/default/secrets/service-apikey
uid: 671b547c-3316-4916-b6dc-be2b551b974e
type: Opaque
Получение Secret
сведений с помощью kubectl get не раскрывает их содержимое.
Обратите внимание, что apikey: Zm9vYmFy
был тем, что мы предоставили в манифесте YAML. Вы можете проверить текстовую форму, расшифровав ее:
echo 'Zm9vYmFy' | base64 --decode
//foobar
Используйте раздел stringData
Атрибут data
, используемый в приведенном выше примере, используется для сохранения информации в кодировке base64
. Если вы хотите безопасно хранить текстовые данные, вы можете использовать stringData
section. Вот пример:
apiVersion: v1
kind: Secret
metadata:
name: plaintext-secret
stringData:
foo: bar
mac: cheese
Значения foo
и mac
передаются как обычный текст. Создайте этот Secret
и подтвердите:
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/secret-plaintext.yaml
kubectl get secret/plaintext-secret -o yaml
Вот часть data
ответа YAML. Фактические данные хранятся в кодированном формате base64
.
data:
foo: YmFy
Если вы декодируете данные, вы можете подтвердить, что они соответствуют исходному текстовому вводу (bar
), который мы предоставили.
echo 'YmFy' | base64 --decode
//bar
Обратите внимание, что секция thedata
не принимает атрибут обычного текста. Попытка сделать это приведет к ошибке, подобной этой: illegal base64 data at input byte 8
Содержимое файла
Вы также можете предоставить содержимое всего файла в качестве входных данных для раздела stringData
. Вот как это может выглядеть:
apiVersion: v1
kind: Secret
metadata:
name: secret-in-a-file
stringData:
app-config.yaml: |-
hello: world
john: doe
Создать это Secret
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/secret-file.yaml
Этот результирующий Secret
будет содержать ключ с именем app-config.yaml
, а его содержимое (значение) будет base64
кодировкой предоставленных данных.
Как обычно, вы подтверждаете это в Kubernetes, а также декодируете содержимое.
kubectl get secret/secret-in-a-file -o yaml
echo '<"data" content in yaml response> | base64 --decode
Примечание. Когда вы используете этот метод, ваше приложение отвечает за анализ данных, представляющих конфигурацию Secret
. В данном случае это пары ключ-значение, разделенные новой строкой, но это может быть что угодно .
Использование kubectl
Вы можете использовать команду kubectl create secret
для создания Secret
объектов
Использование --from-literal
Вы можете использовать текстовые данные для создания Secret
с помощью интерфейса командной строки (в Kubernetes они будут храниться в кодированном формате base64
):
kubectl create secret generic redis-credentials --from-literal=user=poweruser --from-literal=password='f0ob@r'
Использование --from-file
kubectl create secret generic topsecret --from-file=api_keys.txt
Это создаст секрет (topsecret
) с
- ключ с тем же именем файла, то есть
api_keys.txt
в данном случае - и значение как содержимое файла
Из файлов в каталоге
Вы можете просто указать на каталог, и все файлы в нем будут использоваться для создания Secret
.
kubectl create secret generic topsecrets --from-file=/home/credentials/
Вы получите
- несколько ключей, которые будут такими же, как имя отдельного файла
- значением будет содержимое соответствующего файла
Использование секретов
Чтобы секреты были полезными, мы должны убедиться, что они доступны для наших приложений (то есть для модулей). Давайте посмотрим, как мы можем это сделать.
Переменные среды
Вы можете использовать данные Secret
как переменные среды в Pod
(как и ConfigMap
). Вот пример:
apiVersion: v1
kind: Pod
metadata:
name: pod1
spec:
containers:
- name: nginx
image: nginx
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: service-apikey
key: apikey
Мы используем ключ apikey
из Secret
service-apikey
и убеждаемся, что его значение доступно как переменная среды API_KEY
внутри Pod
.
Создайте Pod
(при условии, что у вас есть Secret
, созданный из предыдущего примера) и подтвердите.
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/pod-secret-env.yaml
kubectl get pods -w
Подождите, пока Pod
перейдет в состояние Running
. Затем убедитесь, что переменная среды была введена в Pod
.
kubectl exec pod1 -- env | grep API_KEY
Вы должны получить такой ответ - API_KEY=foobar
.
Вместо ссылки на отдельные записи в Secret
, вы можете использовать envFrom
для удобного использования всех записей в качестве переменных среды в Pod
. Вот как вы можете это использовать:
apiVersion: v1
kind: Pod
metadata:
name: pod2
spec:
containers:
- name: nginx
image: nginx
envFrom:
- secretRef:
name: plaintext-secret
Мы имеем в виду plaintext-secret
Secret
using envFrom.secretRef
. Чтобы создать этот Pod
:
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/pod-secret-envFrom.yaml
kubectl get pods -w
Подождите, пока Pod
перейдет в состояние Running
, а затем подтвердите наличие переменных среды.
kubectl exec pod2 -- env | grep foo //foo=bar
kubectl exec pod2 -- env | grep mac //mac=cheese
Это подтверждает, что и foo
, и mac
были добавлены как переменные среды в the
Pod вместе с их декодированными значениями, то есть bar
и cheese
соответственно.
Объемы
Вы можете смонтировать Secrets
как Volume
в Pod
. Например:
apiVersion: v1
kind: Pod
metadata:
name: pod3
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: apikey-config-volume
mountPath: /secret
readOnly: true
volumes:
- name: apikey-config-volume
secret:
secretName: service-apikey
Том apikey-config-volume
относится к service-apikey
Secret
. Чтобы создать это Pod
:
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/pod-secret-volume.yaml
kubectl get pods -w
Подождите, пока Pod
перейдет в состояние Running
. Затем выполните следующую команду:
kubectl exec pod3 -- cat /secret/apikey
//foobar
Это подтверждает, что ключ apikey
в секрете service-apikey
был смонтирован как файл (с именем apikey
) в каталоге /secret
(как указано в Pod). Содержимое файла - это не что иное, как секретное значение, в данном случае foobar
.
Использование imagePullSecrets
Существует способ использовать Secrets
, чтобы ваш модуль приложения мог использовать его для аутентификации и извлечения образов Docker из частных реестров Docker.
На самом деле есть три типа Secrets
:
generic
- используется для хранения пар ключ-значение, как мы уже видели в примерах.tls
- хранить информацию о паре общедоступных и закрытых ключей какSecrets
docker-registry
- учетные данные для аутентификации в реестре Docker.
Способ использования этой техники очень прост:
- Используйте тип
docker-registry
Secret
для хранения личных учетных данных реестра Docker в Kubernetes. - А затем
imagePullSecrets
(в модуле) для ссылки наSecret
, содержащий учетные данные реестра Docker.
Всегда помогает пример:
apiVersion: v1
kind: Pod
metadata:
name: pod4
spec:
containers:
- name: privateapp
image: abhirockzz/test-private-repo:latest
command: ["/bin/sh"]
args: ["-c", "while true; do date; sleep 5;done"]
imagePullSecrets:
- name: docker-repo-secret
Посмотрите, как imagePullSecrets.name
относится к Secret
под названием docker-repo-secret
. Создадим это.
Но перед этим убедитесь, что у вас есть частный реестр Docker. Я использовал DockerHub
, но вы можете выбрать любой другой.
Начните с создания Secret
(с именем docker-repo-secret
), содержащего ваши учетные данные Docker, с помощью kubectl create secret docker-registry
command.
kubectl create secret docker-registry docker-repo-secret --docker-server=DOCKER_REG_SERVER --docker-username=DOCKER_REG_USERNAME --docker-password=DOCKER_REG_PASSWORD --docker-email=DOCKER_REG_EMAIL
Для Docker Hub:
kubectl create secret docker-registry docker-repo-secret --docker-server=https://index.docker.io/v1/ --docker-username=foobarbaz --docker-password=t0ps3cr3t [email protected]
kubectl get secret/docker-repo-secret -o yaml
https://index.docker.io/v1/
- сервер реестра Docker Hub
Для проверки мы будем использовать изображение busybox
и tag
it
docker pull busybox docker tag busybox [DOCKER_REG]/[DOCKER_PRIVATE_REPO]:[IMAGE_TAG]
e.g. docker tag busybox abhirockzz/test-private-repo:latest
… И push
это
docker push [DOCKER_REG]/[DOCKER_PRIVATE_REPO]:[IMAGE_TAG]
e.g. docker push abhirockzz/test-private-repo:latest
Когда частное репо будет готово, вы можете создать Pod
, который будет извлекать образ из частного репо, используя учетные данные реестра, предоставленные ему через Secret
kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/secrets/pod-secret-docker.yaml
kubectl get pods -w
Подождите, пока Pod
перейдет в состояние Running
.
Если вы видите ошибку ErrImagePull
, это означает, что может возникнуть проблема с аутентификацией в реестре Docker. Чтобы получить подробную информацию, используйте: kubectl describe pod/pod4
Чтобы убедиться, что модуль работает нормально: kubectl logs -f pod4
Поскольку образ busybox
сам по себе ничего не делает, мы выполняем: while true; do date; sleep 5;done
(как предусмотрено в спецификации Pod
). В результате вы должны увидеть журналы (печатаемые каждые 5 секунд).
Tue Dec 17 14:17:34 UTC 2019
Tue Dec 17 14:17:39 UTC 2019
Tue Dec 17 14:17:44 UTC 2019
Tue Dec 17 14:18:49 UTC 2019
Все хорошо! Это означает, что Pod смог извлечь ваше изображение из частного репозитория Docker, используя учетные данные Docker, которые были введены в Pod
с помощью imagePullSecrets
, который сам ссылался на Secret
Хорошо знать
Вот (не исчерпывающий) список вещей, которые вы должны помнить при использовании Secrets
:
Secret
должен быть создан перед любымPod
, который захочет его использовать.Secrets
применимы вnamespace
, т.е. они могут использоваться толькоPods
в том жеnamespace
Pod
не запустится, если есть ссылка на несуществующий ключ вSecret
(с использованиемsecretKeyRef
)- 1 МБ - это максимальный размер для физических лиц
Secrets
.
Вот и все, что касается этого выпуска серии статей о Kubernetes в двух словах. Следите за новостями!
Если вы заинтересованы в изучении Kubernetes и контейнеров с помощью Azure, просто создайте бесплатную учетную запись и приступайте. Хорошей отправной точкой является использование кратких руководств, руководств и примеров кода в документации, чтобы ознакомиться с сервисом. Я также настоятельно рекомендую пройти 50-дневный курс обучения Kubernetes. Опытные пользователи могут захотеть сослаться на Лучшие практики Kubernetes или посмотреть некоторые из видео для демонстраций, основных функций и технических сессий.
Я очень надеюсь, что вам понравилась эта статья и вы ее чему-то научились. 🙌