diff --git a/kubernetes/apps/security/external-secrets/app/clustersecretstore.yaml b/kubernetes/apps/security/external-secrets/app/clustersecretstore.yaml new file mode 100644 index 0000000..51d8951 --- /dev/null +++ b/kubernetes/apps/security/external-secrets/app/clustersecretstore.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: vault +spec: + provider: + vault: + # Внутрикластерный адрес, а не https://vault.<домен>: Vault слушает без TLS + # (tls_disable), а поход через шлюз потребовал бы ещё и доверия к internal-ca + # внутри ESO. Снаружи UI остаётся на https через envoy. + server: http://vault.security.svc:8200 + path: kv + version: v2 + auth: + kubernetes: + mountPath: kubernetes + role: eso + # Service account оператора: имя и namespace должны совпадать с + # bound_service_account_names/namespaces роли eso в Vault. + serviceAccountRef: + name: external-secrets + namespace: security + # Vault 1.21+ требует audience в роли, ESO по умолчанию просит "vault". + audiences: + - vault diff --git a/kubernetes/apps/security/external-secrets/app/externalsecret.yaml b/kubernetes/apps/security/external-secrets/app/externalsecret.yaml new file mode 100644 index 0000000..b706acf --- /dev/null +++ b/kubernetes/apps/security/external-secrets/app/externalsecret.yaml @@ -0,0 +1,30 @@ +--- +# Проверочный ExternalSecret: доказывает всю цепочку ESO -> kubernetes-auth -> +# Vault -> Secret в кластере. Значение кладётся в Vault командой +# vault kv put kv/demo username=demo password=s3cr3t +# (key в ExternalSecret указывается без префикса path: demo -> kv/data/demo). +# Когда появятся настоящие потребители (токен вебхука Flux и приложения), +# этот объект можно удалить. +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vault-smoke + namespace: security +spec: + refreshInterval: 1h + secretStoreRef: + name: vault + kind: ClusterSecretStore + target: + name: vault-smoke + creationPolicy: Owner + deletionPolicy: Retain + data: + - secretKey: username + remoteRef: + key: demo + property: username + - secretKey: password + remoteRef: + key: demo + property: password diff --git a/kubernetes/apps/security/external-secrets/app/helmrelease.yaml b/kubernetes/apps/security/external-secrets/app/helmrelease.yaml new file mode 100644 index 0000000..d3be0f5 --- /dev/null +++ b/kubernetes/apps/security/external-secrets/app/helmrelease.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: external-secrets +spec: + interval: 1h + chartRef: + kind: OCIRepository + name: external-secrets + install: + crds: CreateReplace + upgrade: + crds: CreateReplace + cleanupOnFail: true + remediation: + retries: 3 + # Оператор без состояния: переустановка с нуля безопасна, поэтому при + # падении апгрейда релиз снимается и ставится заново, а не залипает. + strategy: uninstall + values: + replicaCount: 1 + # CRD ставит и обновляет сам чарт. + installCRDs: true + # Валидирующий вебхук и его certController включены: сертификаты чарт + # выпускает и продлевает сам, cert-manager для этого не нужен. + webhook: + create: true + certController: + create: true + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + memory: 256Mi diff --git a/kubernetes/apps/security/external-secrets/app/kustomization.yaml b/kubernetes/apps/security/external-secrets/app/kustomization.yaml new file mode 100644 index 0000000..f47595c --- /dev/null +++ b/kubernetes/apps/security/external-secrets/app/kustomization.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ./ocirepository.yaml + - ./helmrelease.yaml + - ./clustersecretstore.yaml + - ./externalsecret.yaml diff --git a/kubernetes/apps/security/external-secrets/app/ocirepository.yaml b/kubernetes/apps/security/external-secrets/app/ocirepository.yaml new file mode 100644 index 0000000..2e08612 --- /dev/null +++ b/kubernetes/apps/security/external-secrets/app/ocirepository.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: external-secrets +spec: + interval: 15m + layerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy + ref: + # Версия чарта external-secrets (равна appVersion). Релизы чарта тегируются + # как helm-chart-, в ghcr публикуется тег без префикса. + tag: 2.10.0 + url: oci://ghcr.io/external-secrets/charts/external-secrets diff --git a/kubernetes/apps/security/external-secrets/ks.yaml b/kubernetes/apps/security/external-secrets/ks.yaml new file mode 100644 index 0000000..85309e9 --- /dev/null +++ b/kubernetes/apps/security/external-secrets/ks.yaml @@ -0,0 +1,25 @@ +--- +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: external-secrets +spec: + interval: 1h + path: ./kubernetes/apps/security/external-secrets/app + prune: true + sourceRef: + kind: GitRepository + name: flux-system + namespace: flux-system + targetNamespace: security + wait: true + healthChecks: + - apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + name: external-secrets + namespace: security + # Оператор ходит в Vault через kubernetes-auth, поэтому ждём готовности Vault. + # Обе Kustomization живут в ns security — dependsOn работает только внутри + # своего namespace, и здесь это выполняется. + dependsOn: + - name: vault diff --git a/kubernetes/apps/security/kustomization.yaml b/kubernetes/apps/security/kustomization.yaml index 0942720..4e1672b 100644 --- a/kubernetes/apps/security/kustomization.yaml +++ b/kubernetes/apps/security/kustomization.yaml @@ -8,4 +8,5 @@ components: resources: - ./namespace.yaml + - ./external-secrets/ks.yaml - ./vault/ks.yaml