feat: initialize ansible-vault secret repository
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*.log
|
||||
*.retry
|
||||
.env
|
||||
.env.*
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.DS_Store
|
||||
.vault_pass.txt
|
||||
secrets/plaintext/
|
||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Agent Secret Vault
|
||||
|
||||
這個 repo 專門存放本地 AI agent 開發會用到的機密管理機制。
|
||||
|
||||
核心設計:
|
||||
- 使用 `ansible-vault` 作為加密格式
|
||||
- 加密檔可進 git
|
||||
- vault password file 只放在本機
|
||||
- 多個 agent 透過統一腳本存取 secrets
|
||||
|
||||
## 內容
|
||||
- `scripts/vault.sh`:初始化、檢視、編輯、加密、解密、rekey
|
||||
- `docs/secret-vault.md`:使用說明與設計原則
|
||||
- `secrets/vault.yml`:加密後 secrets 檔
|
||||
|
||||
## 目標
|
||||
- 讓 Hermes / OpenClaw / cron worker / 其他本地 agent 共用同一套 secret storage contract
|
||||
- 不把明文 secret 留在 repo
|
||||
- 不讓每個 agent 各自發明一套 credential 管理方式
|
||||
55
docs/secret-vault.md
Normal file
55
docs/secret-vault.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Secret Vault
|
||||
|
||||
這個 repo 使用 `ansible-vault` 來保存開發過程中需要的機密資訊。
|
||||
|
||||
## 設計
|
||||
- 加密檔:`secrets/vault.yml`
|
||||
- 本機 vault password file:`~/.config/continuous-ai-workflow-spec/vault-pass.txt`
|
||||
- 管理腳本:`scripts/vault.sh`
|
||||
|
||||
## 原則
|
||||
- 加密後的 `secrets/vault.yml` 可以進 git
|
||||
- `vault-pass.txt` 只放在本機,不進 git
|
||||
- 解密後的暫存 plaintext 檔不要提交
|
||||
|
||||
## 常用指令
|
||||
初始化:
|
||||
```bash
|
||||
./scripts/vault.sh init
|
||||
```
|
||||
|
||||
檢視:
|
||||
```bash
|
||||
./scripts/vault.sh view
|
||||
```
|
||||
|
||||
編輯:
|
||||
```bash
|
||||
./scripts/vault.sh edit
|
||||
```
|
||||
|
||||
把一份 plaintext YAML 加密成 vault:
|
||||
```bash
|
||||
./scripts/vault.sh encrypt /tmp/my-secrets.yml
|
||||
```
|
||||
|
||||
解密到暫存檔:
|
||||
```bash
|
||||
./scripts/vault.sh decrypt /tmp/vault.yml
|
||||
```
|
||||
|
||||
重置 vault key:
|
||||
```bash
|
||||
./scripts/vault.sh rekey
|
||||
```
|
||||
|
||||
## 建議格式
|
||||
```yaml
|
||||
gitea:
|
||||
base_url: https://gitea.cowbay.org
|
||||
ssh_url_template: ssh://git@gitea.cowbay.org:2203/{owner}/{repo}.git
|
||||
account: hermes
|
||||
email: hermes@ntu.edu.rs
|
||||
password: ...
|
||||
api_token: ...
|
||||
```
|
||||
79
scripts/vault.sh
Executable file
79
scripts/vault.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
VAULT_FILE="${VAULT_FILE:-$REPO_DIR/secrets/vault.yml}"
|
||||
VAULT_PASS_FILE="${VAULT_PASS_FILE:-$HOME/.config/continuous-ai-workflow-spec/vault-pass.txt}"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
用法:
|
||||
scripts/vault.sh init 初始化 vault password file(若不存在)
|
||||
scripts/vault.sh view 檢視加密檔內容
|
||||
scripts/vault.sh edit 編輯加密檔內容
|
||||
scripts/vault.sh encrypt FILE 將檔案加密成 ansible-vault 格式
|
||||
scripts/vault.sh decrypt OUT 解密到指定輸出檔
|
||||
scripts/vault.sh rekey 重新加密並更新 key
|
||||
EOF
|
||||
}
|
||||
|
||||
ensure_pass() {
|
||||
mkdir -p "$(dirname "$VAULT_PASS_FILE")"
|
||||
chmod 700 "$(dirname "$VAULT_PASS_FILE")" || true
|
||||
if [ ! -f "$VAULT_PASS_FILE" ]; then
|
||||
umask 177
|
||||
python3 - <<'PY' > "$VAULT_PASS_FILE"
|
||||
import secrets
|
||||
print(secrets.token_urlsafe(48))
|
||||
PY
|
||||
chmod 600 "$VAULT_PASS_FILE"
|
||||
echo "已建立 vault password file: $VAULT_PASS_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd="${1:-}"
|
||||
case "$cmd" in
|
||||
init)
|
||||
ensure_pass
|
||||
;;
|
||||
view)
|
||||
ensure_pass
|
||||
ansible-vault view "$VAULT_FILE" --vault-password-file "$VAULT_PASS_FILE"
|
||||
;;
|
||||
edit)
|
||||
ensure_pass
|
||||
[ -f "$VAULT_FILE" ] || { echo "找不到 $VAULT_FILE"; exit 1; }
|
||||
ansible-vault edit "$VAULT_FILE" --vault-password-file "$VAULT_PASS_FILE"
|
||||
;;
|
||||
encrypt)
|
||||
ensure_pass
|
||||
src="${2:-}"
|
||||
[ -n "$src" ] || { usage; exit 1; }
|
||||
cp "$src" "$VAULT_FILE"
|
||||
ansible-vault encrypt "$VAULT_FILE" --vault-password-file "$VAULT_PASS_FILE"
|
||||
;;
|
||||
decrypt)
|
||||
ensure_pass
|
||||
out="${2:-}"
|
||||
[ -n "$out" ] || { usage; exit 1; }
|
||||
ansible-vault decrypt "$VAULT_FILE" --output "$out" --vault-password-file "$VAULT_PASS_FILE"
|
||||
chmod 600 "$out" || true
|
||||
;;
|
||||
rekey)
|
||||
ensure_pass
|
||||
tmp_new="$(mktemp)"
|
||||
chmod 600 "$tmp_new"
|
||||
python3 - <<'PY' > "$tmp_new"
|
||||
import secrets
|
||||
print(secrets.token_urlsafe(48))
|
||||
PY
|
||||
ansible-vault rekey "$VAULT_FILE" --vault-password-file "$VAULT_PASS_FILE" --new-vault-password-file "$tmp_new"
|
||||
mv "$tmp_new" "$VAULT_PASS_FILE"
|
||||
chmod 600 "$VAULT_PASS_FILE"
|
||||
echo "已更新 vault key: $VAULT_PASS_FILE"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
30
secrets/vault.yml
Normal file
30
secrets/vault.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
$ANSIBLE_VAULT;1.1;AES256
|
||||
35373933393361653231623331383037626334666462366635386261346662316463366264363535
|
||||
3263613961616637633466646661396438383231353334360a363330343736613232626333316337
|
||||
62376637633062333866343039363862613361353266326532663337663137306130633465383063
|
||||
6437316262346635340a653337363536613363613762613362323636316564323433653533343963
|
||||
32633532666465613930353636333533336432333261653362633738316333313532366637346265
|
||||
35363138306634323462393665336330393731323132356266323037303838306233303832383337
|
||||
36613264376538343030353361343638393835613465303665383135326539653434346233663036
|
||||
63383536613331346631323835333933636365346465313239363536613532633837383639663832
|
||||
32663730626266356364383564386634613463313833363963353832333335393339386164633138
|
||||
36343065363965326237633066306137643432333836303561343530356564313465353332353634
|
||||
63383338383631343239653563656632393833323033383738373236356563636361373133343065
|
||||
66653239353930663633626163653830626434313132396637663635663538326166383335323365
|
||||
31333833333261303433393563363266376465303431363031346234313433663737306133613836
|
||||
31646134333333303864303836656235623834356131663764666330326538646265636435326266
|
||||
36313839393335373231363330343664633364663536376566343964633039663037646133666464
|
||||
61623837656633323332646236346362373861653237636461363366333139663531373761373464
|
||||
66633536303332633464396333636164613064633462376166666463353138376231376433396361
|
||||
61316665386363393163306530633966636638616261653034313430623933363135343236663137
|
||||
32363634303063646264663630376532313833393665386433666533613635333432323936616533
|
||||
66313031313933303032303435656436343233653966663964333635353832663631363337386539
|
||||
63313339313031383964653637373566336134613338346465323235316131396131353535343332
|
||||
34643936633864323130353561303933633937626234353233373033333137666565383930626535
|
||||
39626561653836633661333736623934393437303934346361313265663736663037626332663534
|
||||
37313139623364373235333164313662333933616630626561333061653739613665613865366537
|
||||
64643132373130666233383335343361623239363232363133356233633764663435396161363038
|
||||
37363962323563343836653965633935316236666434326236623362663536633136346637343637
|
||||
66663237333537333738353730306539313533363635343836656262373336646262333733636564
|
||||
63633934343264396331363265343166383565373630633432343337306130396464336463643435
|
||||
33386332396336653336313438336563663537303364323765633062333163363735
|
||||
Reference in New Issue
Block a user