Kubernetes
August 23, 2023

ExternalSecret Operator + Certificate Manager

ExternalSecret позволяет использовать внешнюю, по отношению к кластеру Kubernetes, секретницу. В данном примере используется интеграция с CM.

Предполагаю, что SA есть и IAM ключ для него уже сгенерирован. Если нет, то можно воспользоваться инструкцией: https://teletype.in/@cameda/w93lPMPQWS4

На всякий случай. Генерацию IAM ключа для SA можно выполнить так:

yc iam key create --service-account-id $SA --output key.json

Создаётся файл key.json, который можно использовать в дальнейшем.

Создаём самоподписанный сертификат и добавляем его в CM.

openssl req -x509 -newkey rsa:4096 -nodes \
  -keyout key.pem \
  -out cert.pem \
  -days 365 \
  -subj '/CN=example.com'
yc cm certificate create \
  --name camedakey \
  --chain cert.pem \
  --key key.pem
yc cm certificate get camedakey
id: fpqtr8jd2jd07a8u60vp
folder_id:
created_at: "2023-08-21T13:31:28.078Z"
name: camedakey
type: IMPORTED
domains:
  - example.com
status: ISSUED
issuer: CN=example.com
subject: CN=example.com
serial: 7d358e9654ba7771df479b778093800eebc9600e
updated_at: "2023-08-21T13:31:28.078Z"
issued_at: "2023-08-21T13:31:28.078Z"
not_after: "2024-08-20T13:29:48Z"
not_before: "2023-08-21T13:29:48Z"
yc cm certificate add-access-binding \
  --id fpqtr8jd2jd07a8u60vp \
  --service-account-name cameda-service \
  --role certificate-manager.certificates.downloader

Посмотрим содержимое сертификата.

yc certificate-manager certificate content \
  --id fpqtr8jd2jd07a8u60vp \
  --chain cert.pem \
  --key key.pem

Создаём секрет на основе файла key.json.

kubectl create secret generic yc-auth --from-file=authorized-key=key.json
# Проверяем, что содержимое соответствует файлу.
kubectl get secret yc-auth --output=json | jq --raw-output ".data[]" | base64 -d

Создаём SecretStore на основе секрета.

kubectl apply -f - <<< '
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: secret-store
spec:
  provider:
    yandexcertificatemanager:
      auth:
        authorizedKeySecretRef:
          name: yc-auth
          key: authorized-key'
kubectl get ss
NAME           AGE    STATUS   CAPABILITIES   READY
cm-store       143m   Valid    ReadOnly       True

Если SecretStore ранее создавался, то повторно его создавать не надо.

Создаём ExternalSecret, использующий SecretStore.

kubectl apply -f - <<< '
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: cm-secret
spec:
  refreshInterval: 30m
  secretStoreRef:
    name: cm-store
    kind: SecretStore
  target:
    name: cm-secret # the target k8s secret name
    template:
      type: kubernetes.io/tls
  data:
    - secretKey: tls.crt # the target k8s secret key
      remoteRef:
        key: fpqtr8jd2jd07a8u60vp # the certificate ID
        property: chain
    - secretKey: tls.key # the target k8s secret key
      remoteRef:
        key: fpqtr8jd2jd07a8u60vp # the certificate ID
        property: privateKey'

В secretKey указываем именно tls.crt и tls.key, а не cert.pem и key.pem.
Иначе будет ошибка.

kubectl get es
NAME              STORE          REFRESH INTERVAL   STATUS         READY
cm-secret         cm-store       30m                SecretSynced   True

В случае возникновения проблем можно посмотреть логи пода external-secrets-<gen>-<gen>

#Пример.
kubectl logs external-secrets-644849d5c9-j9984 -n external-secrets