Введение

При использовании принципов 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 и созданный ранее сертификат открытого ключа.
Эти шаги включают в себя выполнение нескольких действий:

  1. Извлечение сертификата открытого ключа из контроллера Sealed Secrets, работающего в Kubernetes. Для этого воспользуемся инструментом kubeseal.
  2. Создание файла манифеста секрета Kubernetes, где будут храниться наши секретные данные.
  3. Шифрование секрета Kubernetes с помощью инструмента kubeseal и полученного сертификата открытого ключа. Это позволит сгенерировать файл манифеста Sealed Secret.
  4. Добавление и фиксация файла манифеста 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.

От root

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *