← Kubernetes: конфигурация
7 мин · просто · Урок 3 из 8

Secret и почему base64 это не шифрование

Чем Secret отличается от ConfigMap, какие бывают типы и что на самом деле защищает секреты в кластере.

Что такое Secret

Secret и ConfigMap на уровне Kubernetes почти близнецы. Оба хранят пары «ключ/значение» в etcd. Отличий два: Secret хранит значения в base64, и у него есть type. Всё.

Главная путаница новичков: base64 это не шифрование. Это просто кодировка, чтобы бинарные данные можно было положить в YAML. Любой, кто получит доступ к Secret в etcd или через kubectl get -o yaml, расшифрует за секунду через base64 -d. Secret внутри кластера защищён только RBAC.

kubectl get secret запрос на чтение запрос kube-apiserver RBAC решает, пустить ли чтение etcd encryption at rest
Доступ решает RBAC, хранение закрывает шифрование etcd. base64 не участвует ни там, ни там.

Зачем тогда Secret, если он encoded, а не encrypted? Три причины. Ключи не попадают в kubectl describe pod и логи (там показан факт env, но не значение). Можно включить etcd encryption at rest на уровне кластера и зашифровать все Secret оптом. Внешние инструменты (Vault, Sealed Secrets) знают, куда складывать расшифрованное.

Минимальный YAML

apiVersion: v1
kind: Secret
metadata:
  name: db-creds
type: Opaque
data:
  username: YWRtaW4=
  password: czNjcmV0

YWRtaW4= это admin в base64. Кодируют так:

echo -n admin | base64

-n обязателен, иначе echo добавит перевод строки и значение в Secret будет с лишним \n на конце. Очень типичная ловушка.

Лишний \n в значении не видно ни в kubectl get, ни в describe. Логин падает с «invalid credentials», а Secret при этом выглядит нормальным.

Поле type

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

Подключение к Pod

Один в один как ConfigMap, только secretKeyRef вместо configMapKeyRef:

env:
  - name: DB_USER
    valueFrom:
      secretKeyRef:
        name: db-creds
        key: username

И volume:

volumes:
  - name: creds
    secret:
      secretName: db-creds
      defaultMode: 0400

defaultMode: 0400 ставит read-only для владельца, остальным ничего. Хорошая привычка для секретов.

automountServiceAccountToken

По умолчанию Kubernetes монтирует в каждый Pod токен ServiceAccount - ключ доступа к API кластера. Если приложение к API не ходит, токен это лишний секрет внутри Pod. Его выключают в spec:

spec:
  automountServiceAccountToken: false

Меньше доступов внутри Pod - меньше что украсть при компрометации.

Связанные команды

kubectl create secret generic db-creds \
  --from-literal=username=admin \
  --from-literal=password=s3cret
kubectl create secret tls my-tls --cert=cert.pem --key=key.pem
kubectl get secret db-creds -o yaml
kubectl get secret db-creds -o jsonpath='{.data.password}' | base64 -d
kubectl explain secret.type

Что часто ломается

Домашка

Теорию закрепляет задание на своём кластере: 4 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-secret     # развернуть стартовое состояние
./run.sh verify k8s-secret    # проверить текущий шаг

Коротко

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Что такое ConfigMap и чем он отличается от Secret?

K8S-004
02

Что такое Secret и в чём его проблемы с безопасностью?

K8S-015

Прошли материал до конца? Отметьте урок пройденным.