部署 SPIRE workload identity 基础设施 #51
@@ -50,4 +50,6 @@ sudo k3s kubectl -n flux-system get gitrepositories,kustomizations
|
|||||||
- VictoriaMetrics Operator 已固定现有 chart `0.66.2` 并完成分阶段 Flux HelmRelease
|
- VictoriaMetrics Operator 已固定现有 chart `0.66.2` 并完成分阶段 Flux HelmRelease
|
||||||
接管;Metrics、Logs、Traces 与 Grafana 也已统一完成 Flux 接管;
|
接管;Metrics、Logs、Traces 与 Grafana 也已统一完成 Flux 接管;
|
||||||
- External Secrets Operator 已固定 chart `2.8.0` 并完成分阶段接管;
|
- 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`。
|
- root Kustomization 与所有 brownfield 子 Kustomization 继续保持 `prune: false`。
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -10,4 +10,5 @@ resources:
|
|||||||
- apps/gitea-actions.yaml
|
- apps/gitea-actions.yaml
|
||||||
- apps/http-echo.yaml
|
- apps/http-echo.yaml
|
||||||
- apps/openebs.yaml
|
- apps/openebs.yaml
|
||||||
|
- apps/spire.yaml
|
||||||
- apps/observability.yaml
|
- apps/observability.yaml
|
||||||
|
|||||||
@@ -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`,删除资源需单独审计。
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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/
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user