- 将 terraform init -backend-config 中的 endpoints={s3="..."} HCL map
语法改为 endpoints.s3=... 点号语法(前者在 -backend-config flag 中无效,
导致 R2 endpoint 未被传递,Terraform 回退 AWS 默认 endpoint 签名失败)
- 补全 workflow 顶部 TLDR 前置条件注释(6 项)
- 新增 docs/operations/iac-prerequisites.md(前置条件完整指南含 R2 搭建)
- vault-github-actions.md 补充 §7 交叉引用
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
102 lines
4.7 KiB
Markdown
102 lines
4.7 KiB
Markdown
# Vault + GitHub Actions 配置(xworkspace-console)
|
||
|
||
`xworkspace-console` 的 GitHub Actions 经 HashiCorp Vault (https://vault.svc.plus)
|
||
OIDC 登录、从**共享 CICD KV** 读取密钥。只记录流程、路径、字段名与原则,
|
||
**不含任何敏感值**。延续既有统一模式(见 `vault-github-actions-2026-06-06.md`
|
||
与 `vault-github-actions-ssh-deploy-runbook.md`)。
|
||
|
||
## 1. 全局前提(已存在)
|
||
|
||
- `jwt` auth mount:Type `jwt`、Path `jwt/`、Accessor 如 `auth_jwt_6fd8b418`
|
||
- `oidc_discovery_url = https://token.actions.githubusercontent.com`
|
||
- `bound_issuer = https://token.actions.githubusercontent.com`
|
||
- 共享机密 KV(KV v2):UI `secrets/kv/kv/CICD`,API 读路径 `kv/data/CICD`
|
||
|
||
## 2. role + policy
|
||
|
||
role/policy 命名 `github-actions-xworkspace-console`,读**共享** `kv/data/CICD`。
|
||
|
||
```bash
|
||
# 2.1 policy:允许读共享 CICD KV 路径
|
||
vault policy write github-actions-xworkspace-console - <<'EOF'
|
||
path "kv/data/CICD" {
|
||
capabilities = ["read"]
|
||
}
|
||
path "kv/metadata/CICD" {
|
||
capabilities = ["read", "list"]
|
||
}
|
||
# LLM provider keys 在 openclaw 路径
|
||
path "kv/data/openclaw" {
|
||
capabilities = ["read"]
|
||
}
|
||
path "kv/metadata/openclaw" {
|
||
capabilities = ["read", "list"]
|
||
}
|
||
EOF
|
||
|
||
# 2.2 role:仅绑定本仓库的 GitHub OIDC 身份
|
||
vault write auth/jwt/role/github-actions-xworkspace-console \
|
||
role_type="jwt" \
|
||
user_claim="repository" \
|
||
bound_audiences="vault" \
|
||
bound_claims_type="glob" \
|
||
bound_claims='{"repository":"ai-workspace-lab/xworkspace-console","sub":"repo:ai-workspace-lab/xworkspace-console:*"}' \
|
||
token_policies="github-actions-xworkspace-console" \
|
||
token_ttl="20m" token_max_ttl="30m"
|
||
```
|
||
|
||
> 权限模型一致:`repository = ai-workspace-lab/xworkspace-console`、
|
||
> `sub = repo:ai-workspace-lab/xworkspace-console:*`、`bound_audiences=["vault"]`。
|
||
> 共享 KV 仅授予 read。如需仅限分支,把 `sub` 收窄为
|
||
> `repo:ai-workspace-lab/xworkspace-console:ref:refs/heads/main`。
|
||
|
||
## 3. KV 字段(复用既有共享键,跨两条路径)
|
||
|
||
| Vault 路径 | 键 | 映射到输出 | 用途 |
|
||
| --- | --- | --- | --- |
|
||
| `kv/data/CICD` | `VULTR_API_KEY` | `VULTR_API_KEY` | provision:`TF_VAR_vultr_api_key` |
|
||
| `kv/data/CICD` | `CLOUDFLARE_DNS_API_TOKEN` | `CLOUDFLARE_DNS_API_TOKEN` | dns:Cloudflare DNS 编辑 |
|
||
| `kv/data/CICD` | `SSH_PRIVATE_DEPLOY_KEY_B64` | `ANSIBLE_SSH_KEY_B64` | 连主机 SSH 私钥(**优先**,单行 base64) |
|
||
| `kv/data/CICD` | `SSH_PRIVATE_DEPLOY_KEY` | `ANSIBLE_SSH_KEY` | 同上原始多行(回退) |
|
||
| `kv/data/openclaw` | `DEEPSEEK_API_KEY` / `NVIDIA_API_KEY` / `OLLAMA_API_KEY` | 同名 | deploy:注入主机的 LLM provider keys |
|
||
| `kv/data/CICD` | `TF_STATE_ENDPOINT/BUCKET/ACCESS_KEY/SECRET_KEY/REGION` | 同名 | 可选远端 TF state(不配则本地 state) |
|
||
|
||
> 所有键均已存在(LLM key 在 `kv/openclaw`,其余共享键在 `kv/CICD`)。
|
||
> vault-action 一个步骤可跨多路径读,每行自带路径。
|
||
|
||
> 主机登录用 `SSH_PRIVATE_DEPLOY_KEY`,其公钥 `SSH_PUBLIC_DEPLOY_KEY` 须写入
|
||
> `ai-workspace-infra` 的 `vultr-vps/config/resources/ai-workspace-hosts.yaml`
|
||
> 的 `ssh_keys[].public`,否则 runner 连不上新建主机。
|
||
|
||
## 4. workflow 接入(已落地)
|
||
|
||
`.github/workflows/deploy-ai-workspace-iac.yaml`:
|
||
|
||
1. `permissions.id-token: write`(+ `contents: read`)
|
||
2. 每 job 用 `hashicorp/vault-action@v2`:`method: jwt`、`role:
|
||
github-actions-xworkspace-console`、`jwtGithubAudience: vault`,从
|
||
`kv/data/CICD` 读所需键(用 `KV键 | 输出名` 映射;可选键配 `ignoreNotFound`)
|
||
3. 步骤用 `steps.vault.outputs.<输出名>`,不再用 GitHub Actions Secrets
|
||
4. SSH 落盘优先解码 `ANSIBLE_SSH_KEY_B64`(=`SSH_PRIVATE_DEPLOY_KEY_B64`)、回退原始,
|
||
写 `~/.ssh/id_deploy` 并 `ssh-keygen -y -f` 自检
|
||
5. 远端 TF state 开关由 `steps.vault.outputs.TF_STATE_BUCKET` 是否非空决定
|
||
|
||
## 5. 验收
|
||
|
||
1. 触发 `Deploy AI Workspace (IaC + Ansible + Cloudflare)`。
|
||
2. 每个 job 的 `Load Vault secrets (OIDC)` 成功(读到共享 CICD KV)。
|
||
3. provision:`Terraform apply` 成功、产出 `cmdb.json` 矩阵。
|
||
4. deploy:`Configure SSH`(B64 优先)+ `Run on-host bootstrap` 成功。
|
||
5. dns:`Reconcile Cloudflare DNS` 成功。
|
||
|
||
## 6. 故障处理
|
||
|
||
- `vault-action` 报 `valid path and key`:`secrets` 每行 `;` 分隔、路径含 `data/`。
|
||
- role 不匹配 / `permission denied`:核对 OIDC `repository/sub` 与 role `bound_claims`,及 policy 是否含 `kv/data/CICD`。
|
||
- `Load key ... error in libcrypto`:确认优先解码了 `SSH_PRIVATE_DEPLOY_KEY_B64`。
|
||
- `Permission denied (publickey)`:确认 `SSH_PUBLIC_DEPLOY_KEY` 已进 hosts.yaml 并与私钥配对。
|
||
|
||
## 7. 参考
|
||
|
||
- 完整前置条件清单(含 TF state 后端搭建):[iac-prerequisites.md](iac-prerequisites.md)
|