diff --git a/infrastructure/openbao/terraform/auth-spire.tf b/infrastructure/openbao/terraform/auth-spire.tf new file mode 100644 index 0000000..976d8f2 --- /dev/null +++ b/infrastructure/openbao/terraform/auth-spire.tf @@ -0,0 +1,27 @@ +# Workload authentication via SPIFFE JWT-SVIDs. The discovery document and +# JWKS contain public verification material, so this backend carries no secret. +resource "vault_jwt_auth_backend" "spire" { + path = "jwt-spire" + description = "SPIFFE JWT-SVID workload authentication" + oidc_discovery_url = "https://spire-oidc.ad.ddupan.top" + bound_issuer = "https://spire-oidc.ad.ddupan.top" +} + +# First end-to-end identity. Keep the subject exact: this role is deliberately +# not a wildcard escape hatch for every workload in the trust domain. +resource "vault_jwt_auth_backend_role" "spire_poc" { + backend = vault_jwt_auth_backend.spire.path + role_name = "spire-poc" + role_type = "jwt" + + user_claim = "sub" + bound_audiences = ["openbao"] + bound_claims = { + sub = "spiffe://ddupan.top/ns/spire-poc/sa/spire-jwt-poc" + } + + token_policies = [vault_policy.spire_poc.name] + token_no_default_policy = true + token_ttl = 300 + token_max_ttl = 900 +} diff --git a/infrastructure/openbao/terraform/policies.tf b/infrastructure/openbao/terraform/policies.tf index 21d910e..e057d47 100644 --- a/infrastructure/openbao/terraform/policies.tf +++ b/infrastructure/openbao/terraform/policies.tf @@ -14,6 +14,11 @@ resource "vault_policy" "ai_agent_ssh" { policy = file("${path.module}/policies/ai-agent-ssh.hcl") } +resource "vault_policy" "spire_poc" { + name = "spire-poc" + policy = file("${path.module}/policies/spire-poc.hcl") +} + resource "vault_policy" "snapshot" { name = "snapshot" policy = file("${path.module}/policies/snapshot.hcl") diff --git a/infrastructure/openbao/terraform/policies/spire-poc.hcl b/infrastructure/openbao/terraform/policies/spire-poc.hcl new file mode 100644 index 0000000..8d81867 --- /dev/null +++ b/infrastructure/openbao/terraform/policies/spire-poc.hcl @@ -0,0 +1,10 @@ +# Intentionally grants no secret access. This policy proves that an exact +# SPIFFE ID can exchange a JWT-SVID for a bounded OpenBao token and inspect or +# revoke only that token. +path "auth/token/lookup-self" { + capabilities = ["read"] +} + +path "auth/token/revoke-self" { + capabilities = ["update"] +} diff --git a/platform/spire/README.md b/platform/spire/README.md index 226c374..3b5cc46 100644 --- a/platform/spire/README.md +++ b/platform/spire/README.md @@ -76,6 +76,11 @@ Agent 应通过 PSAT attestation 注册,CSI Driver 应在节点 Ready。 首个业务验收另行增加一个专用测试 Pod 与 `ClusterSPIFFEID`,验证取得 `aud=openbao` 的 JWT-SVID 后登录 OpenBao。PoC 完成前不修改生产认证方式。 +OpenBao 中对应的 Terraform 资源位于 +`../../infrastructure/openbao/terraform/auth-spire.tf`。PoC role 只接受精确 subject +`spiffe://ddupan.top/ns/spire-poc/sa/spire-jwt-poc`,token 不包含 default policy, +且 `spire-poc` policy 不允许读取任何业务 secret。 + ## 恢复边界 - 恢复顺序:共享 PostgreSQL、SPIRE Server signing-key PVC、SPIRE Server、Agent;