Введение
При использовании принципов GitOps в разработке приложений возникает необходимость безопасного хранения конфиденциальных данных. Мы понимаем, что размещение секретов непосредственно в репозиторий Git недопустимо. Для решения этой задачи существует множество подходов, включая сложные инструменты вроде AWS Secrets Manager или HashiCorp Vault. Однако для небольших проектов и команд Sealed Secrets от Bitnami предоставляет более простое решение.
Sealed Secrets работает следующим образом: вы создаете зашифрованный манифест Sealed Secret, используя открытый ключ от контроллера Sealed Secrets, запущенного в Kubernetes. Только этот контроллер способен расшифровать секретные данные при применении Sealed Secret в кластере. Таким образом, вместо самих секретов в репозитории хранятся зашифрованные версии, что обеспечивает безопасность. После развертывания в Kubernetes контроллер создает обычный секрет Kubernetes, который становится доступным вашим рабочим нагрузкам.
Способы предоставления секретов приложению
Существуют разные методы передачи секретов вашему приложению:
- Переменные окружения: секреты могут быть переданы в виде переменных окружения.
- Монтирование томов: секреты можно смонтировать как файлы внутри контейнера, делая их доступными через файловую систему.
- Kubernetes Downward API: секреты могут предоставляться приложениям через Downward API, позволяя контейнерам получать доступ к ним как к части метаданных модуля.
В данном руководстве мы рассмотрим внедрение секретов через переменные окружения.
Требования
Чтобы следовать этому руководству, у вас должны быть следующие ресурсы:
- Кластер Kubernetes
- Реестр контейнерных образов
- Контроллер Sealed Secrets от Bitnami, установленный в вашем кластере
- Инструмент
kubeseal
для работы с Sealed Secrets - ArgoCD (хотя это необязательно, приложение можно развертывать и без него)
Установка kubeseal
Инструмент командной строки kubeseal
используется для создания и управления зашифрованными секретами в Kubernetes. Он позволяет шифровать ваши секреты в формате SealedSecret, который впоследствии может быть расшифрован только контроллером Sealed Secrets в вашем кластере.
Рекомендуется установить kubeseal
, следуя официальной инструкции по установке, доступной по ссылке:
https://github.com/bitnami-labs/sealed-secrets?tab=readme-ov-file#kubeseal
Архитектура рабочего процесса Sealed Secrets
Ниже представлена схема, иллюстрирующая, как происходит процесс использования Sealed Secrets:
Получение публичного ключа сертификата:Разработчик получает сертификат открытого ключа от контроллера Sealed Secrets. Этот сертификат необходим для шифрования секретов таким образом, чтобы только контроллер Sealed Secrets смог их расшифровать.
Создание файла манифеста Kubernetes Secret:Разработчик создает файл манифеста Kubernetes Secret, включающий конфиденциальные данные, которые требуется зашифровать. Используя CLI-инструмент kubeseal
и полученный сертификат открытого ключа, он шифрует эти данные.
Шифрование секрета:Результатом этого шага является зашифрованный манифест Sealed Secret, готовый к сохранению в системе контроля версий.
Применение зашифрованного манифеста:Зашифрованный манифест Sealed Secret применяется к кластеру Kubernetes.
Развертывание зашифрованного секрета:Теперь зашифрованный секрет применен к контроллеру Kubernetes/Sealed Secrets.
Создание секрета Kubernetes:Контроллер Sealed Secrets расшифровывает зашифрованный объект и создает обычный секрет Kubernetes.
Использование секрета приложениями:Приложения, работающие в кластере Kubernetes, получают доступ к созданному секрету и используют его.
Проект
Мы будем разворачивать тестовое веб-приложение, использующее секретные данные. Весь код проекта доступен в следующем репозитории:
https://github.com/devoriales/sealed-secrets-example
Вы также можете создать свой собственный репозиторий со следующей структурой папок и файлов:
.
├── README.md
├── app
│ ├── Dockerfile
│ ├── app.py
│ └── requirements.txt
├── k8s-manifests
│ ├── deployment.yaml
│ ├── ingress.yaml
│ └── service.yaml
Веб-приложение
Наше веб-приложение будет считывать секретные данные из переменных окружения и отображать их на странице. У нас есть два ключевых параметра:
- Имя пользователя
- Пароль
Кроме того, в проекте предусмотрен Ingress для доступа к данным через браузер. Хотя такой подход не имеет большого практического смысла для реальных приложений, он полезен для демонстрации возможностей Sealed Secrets.
Приложение написано на Flask, и основной код выглядит следующим образом:
from flask import Flask
import os
app = Flask(__name__)
@app.route('/')
@app.route('/home')
def home():
html = f'''
<h1>Web App</h1>
<p>Welcome to the home page</p>
<p>Username: {os.environ.get('USERNAME')}</p>
<p>Password: {os.environ.get('PASSWORD')}</p>
'''
return html
if __name__ == '__main__':
app.run(debug=False, host='0.0.0.0', port=5050)
Как видно, приложение просто читает значения из переменных окружения, которые будут переданы ему в процессе запуска.
Создание и отправка образа в реестр
Для сборки образа контейнера перейдем в директорию приложения и выполним следующую команду:
docker build -t <your_registry>/web-app-sealed-secret:0.1.0 .
Не забудьте заменить <your_registry>
на имя вашего реестра изображений. Название и версия образа могут быть изменены по вашему желанию.
Создание файлов манифестов
В папке k8s-manifests
уже подготовлены необходимые файлы манифестов для развертывания приложения.
Файлы манифестов:
.
├── README.md
├── k8s-manifests
│ ├── deployment.yaml
│ ├── ingress.yaml
│ └── service.yaml
Манифест развертывания
Обратите внимание, что в файле развертывания (deployment.yaml
) важно указать правильный путь к образу контейнера:
spec:
containers:
- name: web-app
image: <ваш_реестр>/web-app-sealed-secret:0.1.0
Манифест Ingress
В файле ingress.yaml
убедитесь, что указали корректное имя хоста:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-app-ingress
namespace: gitops-sealed-secret-demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: <укажите_имя_хоста>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-service
port:
number: 80
Если у вас отсутствует контроллер Ingress, вы можете настроить перенаправление запросов прямо на сервис.
Создание манифеста Sealed Secret
Теперь пришло время создать манифест Sealed Secret. Для этого используем kubeseal
и созданный ранее сертификат открытого ключа.
Эти шаги включают в себя выполнение нескольких действий:
- Извлечение сертификата открытого ключа из контроллера Sealed Secrets, работающего в Kubernetes. Для этого воспользуемся инструментом
kubeseal
. - Создание файла манифеста секрета Kubernetes, где будут храниться наши секретные данные.
- Шифрование секрета Kubernetes с помощью инструмента
kubeseal
и полученного сертификата открытого ключа. Это позволит сгенерировать файл манифеста Sealed Secret. - Добавление и фиксация файла манифеста Sealed Secret вместе с другими нашими файлами манифеста.
Получение сертификата открытого ключа
Инструмент kubeseal
работает в контексте kubectl
. Если у вас есть разрешение на доступ к кластеру Kubernetes, то он сможет функционировать правильно.
Чтобы извлечь сертификат, выполните следующую команду:
kubeseal --fetch-cert --controller-name=sealed-secrets --controller-namespace=sealed-secrets > public-key-cert.pem
Параметр --controller-name=sealed-secrets
указывает имя контроллера Sealed Secrets. Обычно по умолчанию контроллер называется sealed-secrets
.
После выполнения команды у вас появится файл с именем public-key-cert.pem
в текущей директории. Этот файл содержит публичный сертификат, который будет использован для шифрования ваших секретов.
Проверить наличие действующего открытого сертификата можно, открыв файл public-key-cert.pem
. В нём должен содержаться открытый ключ:
-----BEGIN CERTIFICATE-----
JkIIEzDCCArSgAwIBAgIQb+VoA+cz7YJfXvk+NlRgvzANBgkqhkiG9w0BAQsFADAA
MB4XDTI0MDYyMTIwMzY1OVoXDTM0MDYxOTIwMzY1OVowADCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAJ1vfKdoj+OLVcB4voW6V/Z/eHZIg4toZuJw9ORg
...
-----END CERTIFICATE-----
Создание секрета Kubernetes
Следующим шагом будет создание секрета Kubernetes. Важно отметить, что этот секрет не следует коммитить в репозиторий Git. Вместо этого мы создадим ещё один файл манифеста под названием Sealed Secret.
Создаём секрет Kubernetes:
kubectl create secret generic mysecret --dry-run=client --from-literal=username=admin --from-literal=password='supersecretpassword' -o yaml > mysecret.yaml
Убедимся, что у нас действительно создан секрет Kubernetes:
cat mysecret.yaml
Пример вывода:
apiVersion: v1
data:
password: c3VwZXJzZWNyZXRwYXNzd29yZA==
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: null
name: mysecret
Шифрование секрета
Теперь, когда у нас есть файл манифеста секрета, мы можем зашифровать его с помощью kubeseal
и сертификата открытого ключа:
spec:
containers:
- name: web-app
image: 192.168.64.54:30500/web-app-sealed-secret:0.1.0
env:
- name: USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
ports:
- containerPort: 5000
Шифрование секрета Kubernetes с помощью kubeseal
На этом этапе мы зашифруем секрет, который был создан ранее, с использованием инструмента kubeseal
. Это приведет к генерации файла манифеста Sealed Secret.
Выполните следующую команду:
kubeseal -n sealed-secret-demo --cert public-key-cert.pem --format yaml < mysecret.yaml > sealedsecret.yaml
⚠️ Обратите внимание, что если вы не укажете пространство имен с помощью опции -n
в команде kubeseal
, файл манифеста будет содержать пространство имен, установленное в вашем контексте kubectl
. Поэтому либо измените контекст, либо добавьте флаг пространства имен.
Эта команда выполняет следующие действия:
- Читает содержимое файла
mysecret.yaml
, который был создан на предыдущем шаге. - Использует сертификат открытого ключа
public-key-cert.pem
для шифрования секрета. - Сохраняет результат в файл
sealedsecret.yaml
.
Проверка зашифрованного секрета
Убедитесь, что у вас получился правильный зашифрованный секрет, распечатав файл sealedsecret.yaml
:
---
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
creationTimestamp: null
name: mysecret
namespace: gitops-sealed-secret-demo
spec:
encryptedData:
password: AgB0rhJWYqojdSVcn+49XQGnKkN+j79cza08goDBJrMd3dX7qTbgJJ+Klko929f7VUBv0LOP1gQBz/XJEMmLze4iqIHhz/w9ZDmxEOOjufTSYQy1/lztSMKb6qVt54Hj038iKbq43zIL3YgUZiF5aqqpj+F9CIoQKhsPACtM/VTN3sYHy1JwWyH6M/89uPjj/jPE9Khblm9iKIsx2BfqipR0K8fMOo9XtX+fUA4L8ORJBYKjN4yaGihnyTZV/3HKZd3gOsuL70GL7oPrBWLOh1ERVhh+dnoIv2RMPMJ94le53Fi8QWdBGI3zznPrf9fWDSwJa/76Zx3leqSTcBTwSftdcFTDpFEKd30qllav8lTMvr/jWsHKKrIZLFLZZ+tyBopHyCx3DrWoI39v9w1TilrVtL6+W4Uc/UAxdyHRLio9glWxANH+GjvLHHRrxsnGHtRqSEHNP2PeZ+EEhAKYSdOXURMWAbpIVbTiwd4NT6mD14plYx0Gxn+KLJkwhLFKhVUZPCjv+0SJhzHseW+xgNyoMHdq4bvYaICmSmmZLbMaqaPVeSWCElpiSzVCFLpYQleP6CDnnoQMRliNd84WAv9SjKRFQcuqM3NOp8gREBG05ucNKPk26UUF1+3+Xef2i9LEAkHtVDBumYjx07SUiCZ6usU2xxLaDttpOlp9xQdA/Mm9LXvCGS/N6a9pxE0Hwllo+geU/nJWgHU0LKV+9w==
username: AgBaNDSRzBL/FqZUZXoGuttfOdecsB5Jqfiau7dJJFvqW4PLwV513Bhv9NLe59zavxg+dZe27HGszSZfbt0mDtiw4Usjk5icWnF9ZrZNAlim4cPJNslnYUxU8A5bTPsuQ9ZBJ88z2CEa7O6I08i5CpIyp6L6A2r2Y/S5Tz4YKyKbXzTAW8kBoOCsCqJ/5XsfKpgNBedP+xDYi+U3UxvET95RS/1HFPE8mTERdrqzTflNmduccgyJ34yuANFbi7YXO8UPE+4Ogcpw6LEPRKHNi4sajPbxCnAXZtiw9X30/DGF64V4RtB413U5m+3N9OrkQmK/Uq/YBsz7pr66C0JUyMAOeEdITfWEy8qtT5N4eG1PESr75zKz/n45kSXkkqbbv6WXCtFhKFd0Lrn9YHIfImgny93ZhyCjEnKRpGmno82Ut1PuykiPBCxnECORGn7+GxlWScdkRYt4Tv2c4ZctZUsSzP3Hrh1IIACMDw7smB879cXgXebKkEyZltPyyBMLN4gxcRw59Vk495LEvUAp4cteVwywPlx6mhPUX1gLMpqiXk5SXHT296C8m5sjNtGmzgx9ddDnmIzL4uL2ComtnxkENDupPyHk/FX4XFahN+FvaGZ+5hQh9eg91zN37reXY2uS8Ss019YIoFUjUBcPDA9FPpF9RoN/KzcQaZRV1PPl886ZJT6FnnjHFqdbMmSwXE5wsdu4uA==
template:
metadata:
creationTimestamp: null
name: mysecret
namespace: gitops-sealed-secret-demo
Добавление зашифрованного манифеста в репозиторий
Теперь вы можете спокойно добавить файл sealedsecret.yaml
в ваш репозиторий. Этот файл может быть расшифрован только контроллером Sealed Secrets, так как он хранит соответствующий закрытый ключ.
Обновление манифеста развертывания
Убедитесь, что ваш файл манифеста развертывания ссылается на правильное имя секрета, которое в нашем примере — mysecret
:
spec:
containers:
- name: web-app
image: 192.168.64.54:30500/web-app-sealed-secret:0.1.0
env:
- name: USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
ports:
- containerPort: 5000
Теперь ваше приложение готово к использованию зашифрованных секретов!
Фиксация и развертывание
После создания зашифрованного манифеста Sealed Secret, его можно зафиксировать в репозитории Git:
git add k8s-manifests/sealed_secret.yaml
git commit -m "Добавляем SealedSecret для учетных данных приложения"
git push origin <название-ветки>
Теперь остается решить, каким способом вы будете выполнять развертывание.
Развертывание с помощью ArgoCD
Если вы используете ArgoCD, вам потребуется создать файл манифеста приложения для вашего веб-приложения.
Пример манифеста приложения ArgoCD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitops-secret-example
namespace: argocd
spec:
project: default
source:
repoURL: 'git@github.com:devoriales/gitops-secret-example.git'
path: k8s-manifests
targetRevision: main
destination:
server: 'https://kubernetes.default.svc'
namespace: gitops-sealed-secret-demo
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Прямое применение с помощью kubectl
Если у вас нет ArgoCD, вы можете применить файлы манифестов напрямую с помощью kubectl
:
kubectl apply -f k8s-manifests/
Вы увидите следующий вывод:
deployment.apps/web-app configured
ingress.networking.k8s.io/web-app-ingress configured
sealedsecret.bitnami.com/mysecret configured
service/web-app-service configured
Проверка работоспособности веб-приложения
Теперь проверьте, что ваше веб-приложение работает корректно. Если вы использовали ArgoCD, вы сможете увидеть статус развернутых ресурсов в интерфейсе ArgoCD.
Откройте веб-браузер и перейдите по URL вашего приложения, чтобы убедиться, что секретные данные были успешно раскрыты для вашего приложения.
Если все прошло успешно, вы увидите, что ваше приложение запущено и работает, а секретные данные стали доступны, как и планировалось.
Можно ли раскрыть запечатанный секрет?
Да, но для этого потребуется проделать определенную работу.
Допустим, вы установили оператор Sealed Secrets в пространстве имен sealed-secrets
.
Первым делом вам нужно получить закрытый ключ из этого пространства имен.
Извлеките закрытый ключ (обратите внимание, что нужно указать правильное имя секрета):
kubectl get secret sealed-secrets-keyv7jc7 -n sealed-secrets -o jsonpath="{.data.tls\.key}" | base64 --decode > sealed-secrets.key
Пример содержимого файла sealed-secrets.key
:
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAnW98p2iP44tVwHi+hbpX9n94dkiDi2hm4nD05GA1wnSkPKYT
Qk+w6ob8MNecnm2VG8zw784IvBeEHP6jwmtbgDThY8OcpJ+zJJTi9fS/SQ3kQ4f5
...
-----END RSA PRIVATE KEY-----
Теперь вам нужно клонировать репозиторий Sealed Secrets и собрать инструмент kubeseal
с возможностью расшифровки:
git clone https://github.com/bitnami-labs/sealed-secrets.git
cd sealed-secrets
go build -tags decrypt ./cmd/kubeseal
Используйте собранный инструмент kubeseal
с закрытым ключом для расшифровки запечатанного секрета:
./kubeseal --recovery-unseal --recovery-private-key sealed-secrets.key < sealedsecret.yaml > decrypted-secret.yaml
Откройте файл decrypted-secret.yaml
, чтобы увидеть расшифрованный секрет Kubernetes:
{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
"name": "mysecret",
"namespace": "sealed-secret-demo",
"creationTimestamp": null,
"ownerReferences": [
{
"apiVersion": "bitnami.com/v1alpha1",
"kind": "SealedSecret",
"name": "mysecret",
"uid": "",
"controller": true
}
]
},
"data": {
"password": "c3VwZXJzZWNyZXRwYXNzd29yZA==",
"username": "YWRtaW4="
}
}
Расшифровка значения пароля с помощью base64
покажет, что оно соответствует ожидаемому значению:
echo "c3VwZXJzZWNyZXRwYXNzd29yZA==" | base64 --decode
В результате вы получите:
supersecretpassword
Заключение
Sealed Secrets представляет собой эффективное решение для управления конфиденциальной информацией в среде Kubernetes, особенно полезное для реализации подхода GitOps. Благодаря использованию контроллера Sealed Secrets, вы можете безопасно хранить файлы манифеста Sealed Secret в вашем репозитории Git, избегая раскрытия фактических секретных данных.
В этом блоге описаны пошаговые инструкции по всем этапам работы с Sealed Secrets, начиная с установки необходимых инструментов и заканчивая развертыванием простого веб-приложения с использованием ArgoCD.
Основные моменты, рассмотренные в статье:
- Принципы работы Sealed Secrets и архитектура на высоком уровне.
- Извлечение сертификата открытого ключа из контроллера Sealed Secrets.
- Создание и шифрование секретов Kubernetes.
- Фиксация манифестов Sealed Secret в репозиторий Git.
- Процесс развертывания приложения с использованием ArgoCD.
При внедрении этих методов в свою инфраструктуру помните о необходимости обеспечения безопасности сертификатов открытых ключей и проверки манифестов развертывания, чтобы убедиться, что они ссылаются на правильные SealedSecrets. Удачи в защите вашей инфраструктуры!
Если у вас возникнут вопросы или сложности, не стесняйтесь обращаться за помощью к документации или сообществу разработчиков Sealed Secrets.