From 22192a3c6836ecea4ecccaa7c89df2eb5d60af24 Mon Sep 17 00:00:00 2001 From: panxiao81 Date: Sun, 13 Sep 2026 15:32:59 +0000 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E7=BD=B2=20SPIRE=20workload=20identit?= =?UTF-8?q?y=20=E5=9F=BA=E7=A1=80=E8=AE=BE=E6=96=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clusters/homelab/README.md | 2 + clusters/homelab/apps/spire.yaml | 14 ++++ clusters/homelab/kustomization.yaml | 1 + platform/spire/README.md | 80 +++++++++++++++++++++ platform/spire/helmrelease-crds.yaml | 30 ++++++++ platform/spire/helmrelease.yaml | 34 +++++++++ platform/spire/helmrepository.yaml | 8 +++ platform/spire/kustomization.yaml | 16 +++++ platform/spire/namespaces.yaml | 14 ++++ platform/spire/values.yaml | 103 +++++++++++++++++++++++++++ 10 files changed, 302 insertions(+) create mode 100644 clusters/homelab/apps/spire.yaml create mode 100644 platform/spire/README.md create mode 100644 platform/spire/helmrelease-crds.yaml create mode 100644 platform/spire/helmrelease.yaml create mode 100644 platform/spire/helmrepository.yaml create mode 100644 platform/spire/kustomization.yaml create mode 100644 platform/spire/namespaces.yaml create mode 100644 platform/spire/values.yaml diff --git a/clusters/homelab/README.md b/clusters/homelab/README.md index 4daa2ec..7a3694e 100644 --- a/clusters/homelab/README.md +++ b/clusters/homelab/README.md @@ -50,4 +50,6 @@ sudo k3s kubectl -n flux-system get gitrepositories,kustomizations - VictoriaMetrics Operator 已固定现有 chart `0.66.2` 并完成分阶段 Flux HelmRelease 接管;Metrics、Logs、Traces 与 Grafana 也已统一完成 Flux 接管; - External Secrets Operator 已固定 chart `2.8.0` 并完成分阶段接管; +- SPIRE 已按官方 hardened chart `0.30.2`(SPIRE `1.15.3`)声明,使用共享 + PostgreSQL 与独立 signing-key PVC;首次上线和 OpenBao JWT-SVID PoC 尚待合并后验证; - root Kustomization 与所有 brownfield 子 Kustomization 继续保持 `prune: false`。 diff --git a/clusters/homelab/apps/spire.yaml b/clusters/homelab/apps/spire.yaml new file mode 100644 index 0000000..3177750 --- /dev/null +++ b/clusters/homelab/apps/spire.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: spire + namespace: flux-system +spec: + interval: 10m + path: ./platform/spire + prune: false + sourceRef: + kind: GitRepository + name: flux-system + timeout: 15m + wait: false diff --git a/clusters/homelab/kustomization.yaml b/clusters/homelab/kustomization.yaml index 66e79ca..f6268f5 100644 --- a/clusters/homelab/kustomization.yaml +++ b/clusters/homelab/kustomization.yaml @@ -10,4 +10,5 @@ resources: - apps/gitea-actions.yaml - apps/http-echo.yaml - apps/openebs.yaml + - apps/spire.yaml - apps/observability.yaml diff --git a/platform/spire/README.md b/platform/spire/README.md new file mode 100644 index 0000000..e13e6b1 --- /dev/null +++ b/platform/spire/README.md @@ -0,0 +1,80 @@ +# SPIFFE/SPIRE workload identity + +SPIRE 是 homelab 的机器与 workload identity 根。人类身份继续由 Samba AD 与 +Authelia 提供;SPIRE 不替代人类 OIDC,也不承担目标服务的资源授权。 + +## 部署范围 + +Flux 安装 SPIFFE hardened charts: + +- `spire-crds` `0.6.1`; +- `spire` `0.30.2`(SPIRE `1.15.3`); +- SPIRE Server、Agent、Controller Manager、SPIFFE CSI Driver; +- OIDC Discovery Provider。 + +未启用 Tornjak、SPIRE Identity Exchange、SPIKE、federation、Delegated Identity +API 或 Broker API。Trust domain 是 `ddupan.top`,Kubernetes cluster name 是 +`homelab`。 + +## PostgreSQL bootstrap + +SPIRE registration datastore 使用共享 CloudNativePG: + +```text +host: shared-postgresql-rw.shared-db.svc.cluster.local:5432 +database: spire +role: spire +``` + +数据库与 role 当前是手工创建的临时 bootstrap。密码只存在于 +`spire-server/spire-postgresql` Secret 的 `password` key 中,不提交到 Git。 +在 PostgreSQL tenant operator/DBaaS 接管前,不得删除该 Secret 或重置数据库 +role 密码。 + +后续声明式管理必须保持这一 Secret 接口,或者在同一个变更中更新 +`spire-server.dataStore.sql.externalSecret`,避免数据库凭据出现两个写入方。 + +PostgreSQL保存 registration state;SPIRE Server 的 disk KeyManager 仍使用一个 +`1Gi`、`localpv-zfs-ceph` PVC 保存 trust-domain signing keys。数据库备份不能替代 +该 PVC/密钥的备份。 + +## 身份签发策略 + +默认的全 Pod fallback `ClusterSPIFFEID` 已关闭。新增 workload 必须显式创建 +`ClusterSPIFFEID`,并以 namespace、ServiceAccount、Pod label 等 selector 收窄。 +不得仅因 Pod 能挂载 CSI socket 就给它签发身份。 + +稳定的 JWT issuer 预留为: + +```text +https://spire-oidc.ad.ddupan.top +``` + +首次部署时 OIDC Discovery Provider 仅为 ClusterIP,内部为明文 HTTP;尚未创建 +外部 DNS 或 Gateway route。接入 OpenBao 前,在现有 Envoy Gateway 上终止 TLS、 +增加内网 DNS,并验证 discovery document 的 `issuer` 与上述 URL 完全一致。 + +## 首次部署与验证 + +合并后观察: + +```bash +sudo k3s kubectl -n flux-system get kustomization spire +sudo k3s kubectl -n spire-mgmt get helmrelease +sudo k3s kubectl -n spire-server get pods,pvc +sudo k3s kubectl -n spire-system get daemonset,pods +``` + +必须先确认 `spire-crds` Ready,随后 `spire` Ready。SPIRE Server 应连接 PostgreSQL, +Agent 应通过 PSAT attestation 注册,CSI Driver 应在节点 Ready。 + +首个业务验收另行增加一个专用测试 Pod 与 `ClusterSPIFFEID`,验证取得 +`aud=openbao` 的 JWT-SVID 后登录 OpenBao。PoC 完成前不修改生产认证方式。 + +## 恢复边界 + +- 恢复顺序:共享 PostgreSQL、SPIRE Server signing-key PVC、SPIRE Server、Agent; +- issuer URL 与 trust domain 初始化后不得随意修改; +- 丢失 signing keys 会使既有 SVID 和下游 JWKS 信任失效; +- PostgreSQL或 SPIRE 不可用时,不得用新的空数据库覆盖现有状态; +- 当前 Flux root 与本 Kustomization 均保持 `prune: false`,删除资源需单独审计。 diff --git a/platform/spire/helmrelease-crds.yaml b/platform/spire/helmrelease-crds.yaml new file mode 100644 index 0000000..c93e31e --- /dev/null +++ b/platform/spire/helmrelease-crds.yaml @@ -0,0 +1,30 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: spire-crds + namespace: spire-mgmt +spec: + chart: + spec: + chart: spire-crds + interval: 1h + sourceRef: + kind: HelmRepository + name: spiffe-hardened + version: 0.6.1 + driftDetection: + mode: enabled + install: + crds: CreateReplace + strategy: + name: RetryOnFailure + retryInterval: 5m + interval: 30m + releaseName: spire-crds + targetNamespace: spire-mgmt + timeout: 10m + upgrade: + crds: CreateReplace + strategy: + name: RetryOnFailure + retryInterval: 5m diff --git a/platform/spire/helmrelease.yaml b/platform/spire/helmrelease.yaml new file mode 100644 index 0000000..dd21292 --- /dev/null +++ b/platform/spire/helmrelease.yaml @@ -0,0 +1,34 @@ +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: spire + namespace: spire-mgmt +spec: + chart: + spec: + chart: spire + interval: 1h + sourceRef: + kind: HelmRepository + name: spiffe-hardened + version: 0.30.2 + dependsOn: + - name: spire-crds + namespace: spire-mgmt + driftDetection: + mode: enabled + install: + strategy: + name: RetryOnFailure + retryInterval: 5m + interval: 30m + releaseName: spire + targetNamespace: spire-mgmt + timeout: 15m + upgrade: + strategy: + name: RetryOnFailure + retryInterval: 5m + valuesFrom: + - kind: ConfigMap + name: spire-values diff --git a/platform/spire/helmrepository.yaml b/platform/spire/helmrepository.yaml new file mode 100644 index 0000000..207203a --- /dev/null +++ b/platform/spire/helmrepository.yaml @@ -0,0 +1,8 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: spiffe-hardened + namespace: spire-mgmt +spec: + interval: 1h + url: https://spiffe.github.io/helm-charts-hardened/ diff --git a/platform/spire/kustomization.yaml b/platform/spire/kustomization.yaml new file mode 100644 index 0000000..69075cb --- /dev/null +++ b/platform/spire/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +generatorOptions: + disableNameSuffixHash: true + labels: + reconcile.fluxcd.io/watch: Enabled +configMapGenerator: + - name: spire-values + namespace: spire-mgmt + files: + - values.yaml=values.yaml +resources: + - namespaces.yaml + - helmrepository.yaml + - helmrelease-crds.yaml + - helmrelease.yaml diff --git a/platform/spire/namespaces.yaml b/platform/spire/namespaces.yaml new file mode 100644 index 0000000..f4e1f42 --- /dev/null +++ b/platform/spire/namespaces.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: spire-mgmt +--- +apiVersion: v1 +kind: Namespace +metadata: + name: spire-server +--- +apiVersion: v1 +kind: Namespace +metadata: + name: spire-system diff --git a/platform/spire/values.yaml b/platform/spire/values.yaml new file mode 100644 index 0000000..770da6c --- /dev/null +++ b/platform/spire/values.yaml @@ -0,0 +1,103 @@ +global: + k8s: + clusterDomain: cluster.local + spire: + clusterName: homelab + trustDomain: ddupan.top + # This is a stable external identity even before its Gateway route is added. + # Changing the issuer after consumers trust it would invalidate their config. + jwtIssuer: https://spire-oidc.ad.ddupan.top + caSubject: + country: CN + organization: ddupan homelab + commonName: ddupan.top + namespaces: + create: false + system: + name: spire-system + server: + name: spire-server + recommendations: + enabled: true + namespaceLayout: true + namespacePSS: true + priorityClassName: true + strictMode: true + securityContexts: true + prometheus: false + +spire-server: + kind: statefulset + replicaCount: 1 + auditLogEnabled: true + persistence: + # PostgreSQL stores registrations, but the disk KeyManager still needs durable + # storage for the trust-domain signing keys. + type: pvc + size: 1Gi + accessMode: ReadWriteOnce + storageClass: localpv-zfs-ceph + dataStore: + sql: + databaseType: postgres + databaseName: spire + host: shared-postgresql-rw.shared-db.svc.cluster.local + port: 5432 + username: spire + options: + - sslmode: require + externalSecret: + enabled: true + name: spire-postgresql + key: password + maxOpenConns: 20 + maxIdleConns: 2 + connMaxLifetime: 30m + controllerManager: + enabled: true + # Identities are opt-in. Do not issue a fallback SVID to every pod in the + # cluster merely because it can mount the Workload API socket. + identities: + clusterSPIFFEIDs: + default: + enabled: false + test-keys: + enabled: false + +spire-agent: + nodeAttestor: + k8sPSAT: + enabled: true + workloadAttestors: + k8s: + enabled: true + unix: + enabled: false + +spiffe-csi-driver: + enabled: true + +spiffe-oidc-discovery-provider: + enabled: true + # TLS will terminate at the existing Envoy Gateway when the stable issuer is + # exposed. The service remains ClusterIP-only during the first deployment. + tls: + spire: + enabled: false + externalSecret: + enabled: false + certManager: + enabled: false + +upstream: + enabled: false +tornjak-frontend: + enabled: false +spire-identity-exchange: + enabled: false +spike-keeper: + enabled: false +spike-nexus: + enabled: false +spike-pilot: + enabled: false