rotate-key
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRotate API Key / Secret
轮换API密钥/密钥
Rotate a secret or API key across all locations in the OMI project.
在OMI项目的所有位置轮换密钥或API密钥。
Usage
使用方法
/rotate-key <KEY_NAME> <NEW_VALUE>Examples:
/rotate-key GEMINI_API_KEY AIzaSyNewKeyHere123/rotate-key OPENAI_API_KEY sk-new-key-here
If no new value is provided, ask the user for it.
/rotate-key <KEY_NAME> <NEW_VALUE>示例:
/rotate-key GEMINI_API_KEY AIzaSyNewKeyHere123/rotate-key OPENAI_API_KEY sk-new-key-here
如果未提供新值,请向用户询问。
Rotation Checklist
轮换检查清单
For every key rotation, work through ALL of the following locations. Skip any that don't apply to the specific key.
每次密钥轮换时,需完成以下所有位置的更新。不适用于当前密钥的位置可跳过。
1. Discovery — Find All Occurrences
1. 查找定位——找到所有出现的位置
bash
undefinedbash
undefinedSearch the entire repo for the key name (env var references)
在整个仓库中搜索密钥名称(环境变量引用)
grep -r "<KEY_NAME>" --include=".env" --include=".yaml" --include=".yml" --include=".py" --include=".swift" --include=".rs" --include=".mjs" --include="*.dart" .
grep -r "<KEY_NAME>" --include=".env" --include=".yaml" --include=".yml" --include=".py" --include=".swift" --include=".rs" --include=".mjs" --include="*.dart" .
Search for the old value if known (hardcoded instances)
如果知道旧值,搜索硬编码的实例
grep -r "<OLD_VALUE>" .
undefinedgrep -r "<OLD_VALUE>" .
undefined2. macOS Keychain
2. macOS Keychain
Check if the key is stored in the macOS Keychain and update it:
bash
undefined检查密钥是否存储在macOS Keychain中并更新:
bash
undefinedCheck for existing entry (try common service name patterns)
检查现有条目(尝试通用服务名称模式)
security find-generic-password -s "<key-name-lowercase>" -w 2>/dev/null
security find-generic-password -s "<key-name-lowercase>" -w 2>/dev/null
Update: delete old, add new
更新:删除旧条目,添加新条目
security delete-generic-password -s "<key-name-lowercase>" 2>/dev/null
security add-generic-password -s "<key-name-lowercase>" -a "<key-name-lowercase>" -w "<NEW_VALUE>"
undefinedsecurity delete-generic-password -s "<key-name-lowercase>" 2>/dev/null
security add-generic-password -s "<key-name-lowercase>" -a "<key-name-lowercase>" -w "<NEW_VALUE>"
undefined3. Local .env Files
3. 本地.env文件
Common locations (check all that contain the key):
| Location | Purpose |
|---|---|
| Desktop app runtime |
| Desktop app bundled env |
| Desktop app dev env |
| Rust backend local |
| Dev build artifact |
| Beta build artifact |
| Python backend local |
| Flutter app |
| Flutter app dev |
bash
undefined常见位置(检查所有包含该密钥的位置):
| 位置 | 用途 |
|---|---|
| 桌面端应用运行时 |
| 桌面端应用打包环境 |
| 桌面端应用开发环境 |
| Rust后端本地环境 |
| 开发构建产物 |
| Beta构建产物 |
| Python后端本地环境 |
| Flutter应用 |
| Flutter应用开发环境 |
bash
undefinedUpdate each file that contains the key
更新每个包含该密钥的文件
sed -i '' "s/<KEY_NAME>=.*/<KEY_NAME>=<NEW_VALUE>/" <file>
undefinedsed -i '' "s/<KEY_NAME>=.*/<KEY_NAME>=<NEW_VALUE>/" <file>
undefined4. GCP Secret Manager
4. GCP Secret Manager
The backend and desktop-backend pull secrets via Kubernetes ExternalSecrets from GCP Secret Manager.
bash
undefined后端和桌面端后端通过Kubernetes ExternalSecrets从GCP Secret Manager拉取密钥。
bash
undefinedProd (based-hardware)
生产环境(based-hardware)
echo -n "<NEW_VALUE>" | gcloud secrets versions add <KEY_NAME> --data-file=- --project=based-hardware
echo -n "<NEW_VALUE>" | gcloud secrets versions add <KEY_NAME> --data-file=- --project=based-hardware
Dev (based-hardware-dev) — may need dev service account
开发环境(based-hardware-dev)——可能需要开发服务账号权限
echo -n "<NEW_VALUE>" | gcloud secrets versions add <KEY_NAME> --data-file=- --project=based-hardware-dev
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
echo -n "<NEW_VALUE>" | gcloud secrets versions add <KEY_NAME> --data-file=- --project=based-hardware-dev
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
Disable old versions to prevent use of leaked key
禁用旧版本以防止泄露的密钥被使用
gcloud secrets versions list <KEY_NAME> --project=based-hardware --format="table(name,state)"
gcloud secrets versions disable <OLD_VERSION> --secret=<KEY_NAME> --project=based-hardware
gcloud secrets versions disable <OLD_VERSION> --secret=<KEY_NAME> --project=based-hardware-dev
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
undefinedgcloud secrets versions list <KEY_NAME> --project=based-hardware --format="table(name,state)"
gcloud secrets versions disable <OLD_VERSION> --secret=<KEY_NAME> --project=based-hardware
gcloud secrets versions disable <OLD_VERSION> --secret=<KEY_NAME> --project=based-hardware-dev
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
--account=local-development-joan@based-hardware-dev.iam.gserviceaccount.com
undefined5. Cloud Run Services (Direct Env Vars)
5. Cloud Run服务(直接设置的环境变量)
Some services run on Cloud Run with env vars set directly (not via K8s secrets). Check and update these:
bash
undefined部分运行在Cloud Run上的服务直接设置了环境变量(不通过K8s密钥)。检查并更新这些变量:
bash
undefinedCheck current value
检查当前值
gcloud run services describe <SERVICE_NAME> --project=based-hardware --region=us-central1 --format=json |
python3 -c "import json,sys; [print(f"{e['name']}: ...{e.get('value','')[-4:]}") for e in json.load(sys.stdin)['spec']['template']['spec']['containers'][0].get('env',[]) if '<KEY_NAME>' in e.get('name','')]"
python3 -c "import json,sys; [print(f"{e['name']}: ...{e.get('value','')[-4:]}") for e in json.load(sys.stdin)['spec']['template']['spec']['containers'][0].get('env',[]) if '<KEY_NAME>' in e.get('name','')]"
gcloud run services describe <SERVICE_NAME> --project=based-hardware --region=us-central1 --format=json |
python3 -c "import json,sys; [print(f"{e['name']}: ...{e.get('value','')[-4:]}") for e in json.load(sys.stdin)['spec']['template']['spec']['containers'][0].get('env',[]) if '<KEY_NAME>' in e.get('name','')]"
python3 -c "import json,sys; [print(f"{e['name']}: ...{e.get('value','')[-4:]}") for e in json.load(sys.stdin)['spec']['template']['spec']['containers'][0].get('env',[]) if '<KEY_NAME>' in e.get('name','')]"
Update — IMPORTANT: must specify --image with a valid tag, check available tags first
更新——重要提示:必须指定带有效标签的--image,先查看可用标签
gcloud container images list-tags gcr.io/based-hardware/<SERVICE_NAME> --limit=5 --sort-by=~timestamp --format="table(tags,timestamp.datetime)"
gcloud run services update <SERVICE_NAME> --region=us-central1 --project=based-hardware
--image=gcr.io/based-hardware/<SERVICE_NAME>:<VALID_TAG>
--update-env-vars "<KEY_NAME>=<NEW_VALUE>"
--image=gcr.io/based-hardware/<SERVICE_NAME>:<VALID_TAG>
--update-env-vars "<KEY_NAME>=<NEW_VALUE>"
**Known Cloud Run services with direct env vars:**
| Service | Region | Key(s) |
|---------|--------|--------|
| `desktop-backend` | us-central1 | `GEMINI_API_KEY`, `AGENT_GEMINI_API_KEY` |gcloud container images list-tags gcr.io/based-hardware/<SERVICE_NAME> --limit=5 --sort-by=~timestamp --format="table(tags,timestamp.datetime)"
gcloud run services update <SERVICE_NAME> --region=us-central1 --project=based-hardware
--image=gcr.io/based-hardware/<SERVICE_NAME>:<VALID_TAG>
--update-env-vars "<KEY_NAME>=<NEW_VALUE>"
--image=gcr.io/based-hardware/<SERVICE_NAME>:<VALID_TAG>
--update-env-vars "<KEY_NAME>=<NEW_VALUE>"
**已知直接设置环境变量的Cloud Run服务:**
| 服务 | 区域 | 密钥 |
|---------|--------|--------|
| `desktop-backend` | us-central1 | `GEMINI_API_KEY`, `AGENT_GEMINI_API_KEY` |6. Restart Kubernetes Deployments
6. 重启Kubernetes部署
After updating GCP secrets, restart deployments so pods pick up the new values:
bash
undefined更新GCP密钥后,重启部署让Pod获取新值:
bash
undefinedCheck which deployments use the key
检查哪些部署使用了该密钥
kubectl get deployments -n prod-omi-backend
kubectl get deployments -n prod-omi-backend
Restart relevant deployments (common ones that use env secrets)
重启相关部署(使用环境密钥的常用部署)
kubectl rollout restart deployment/prod-omi-backend-listen -n prod-omi-backend
kubectl rollout restart deployment/desktop-backend -n prod-omi-backend
kubectl rollout restart deployment/prod-omi-pusher -n prod-omi-backend
kubectl rollout restart deployment/prod-omi-backend-listen -n prod-omi-backend
kubectl rollout restart deployment/desktop-backend -n prod-omi-backend
kubectl rollout restart deployment/prod-omi-pusher -n prod-omi-backend
Add others as needed based on which services use the key
根据使用该密钥的服务按需添加其他部署
undefinedundefined7. Codemagic CI Environment Variables
7. Codemagic CI环境变量
Codemagic stores env vars used during mobile and desktop builds. Update via the dashboard:
App ID:
66c95e6ec76853c447b8bcbbAPI approach (list vars):
bash
export CODEMAGIC_API_TOKEN="$(grep CODEMAGIC_API_TOKEN ~/.zshrc | cut -d'"' -f2)"
curl -s -H "x-auth-token: $CODEMAGIC_API_TOKEN" \
"https://api.codemagic.io/apps/66c95e6ec76853c447b8bcbb" | \
python3 -c "
import json,sys
data = json.load(sys.stdin)['application']
for v in data.get('appEnvironmentVariables',{}).get('variables',[]):
if v.get('key') == '<KEY_NAME>':
print(f'Found: group={v[\"group\"]}, id={v[\"id\"]}, secure={v.get(\"secure\",False)}')
"Dashboard approach (if API update isn't supported):
- Navigate to
https://codemagic.io/app/66c95e6ec76853c447b8bcbb/settings - Click "Environment variables" tab
- Find the variable, click the delete (trash) button, confirm deletion
- Add new variable: enter name, value, select the correct group (usually ), check "Secret", click "Add"
app_env
Codemagic存储了移动端和桌面端构建过程中使用的环境变量。通过控制台更新:
应用ID:
66c95e6ec76853c447b8bcbbAPI方式(列出变量):
bash
export CODEMAGIC_API_TOKEN="$(grep CODEMAGIC_API_TOKEN ~/.zshrc | cut -d'"' -f2)"
curl -s -H "x-auth-token: $CODEMAGIC_API_TOKEN" \
"https://api.codemagic.io/apps/66c95e6ec76853c447b8bcbb" | \
python3 -c "
import json,sys
data = json.load(sys.stdin)['application']
for v in data.get('appEnvironmentVariables',{}).get('variables',[]):
if v.get('key') == '<KEY_NAME>':
print(f'Found: group={v[\"group\"]}, id={v[\"id\"]}, secure={v.get(\"secure\",False)}')
"控制台方式(如果不支持API更新):
- 访问
https://codemagic.io/app/66c95e6ec76853c447b8bcbb/settings - 点击"Environment variables"标签页
- 找到对应变量,点击删除(垃圾桶)按钮,确认删除
- 添加新变量:输入名称、值,选择正确的分组(通常是),勾选"Secret",点击"Add"
app_env
8. Codemagic OMI_DESKTOP_APP_ENV
(Bundled Desktop .env)
OMI_DESKTOP_APP_ENV8. Codemagic OMI_DESKTOP_APP_ENV
(打包的桌面端.env)
OMI_DESKTOP_APP_ENVThe Codemagic secret (group: ) is a base64-encoded copy of that gets decoded into the bundle at build time. If any key inside changes, this secret must also be updated.
OMI_DESKTOP_APP_ENVdesktop_secretsdesktop/.env.app.app.env.appbash
undefinedCodemagic密钥(分组:)是**的base64编码副本**,构建时会解码到包中。如果内的任意密钥发生变更,该密钥也必须更新。
OMI_DESKTOP_APP_ENVdesktop_secretsdesktop/.env.app.app.env.appbash
undefined1. Verify desktop/.env.app has the new key value
1. 确认desktop/.env.app已经更新为新的密钥值
grep "<KEY_NAME>" desktop/.env.app
grep "<KEY_NAME>" desktop/.env.app
2. Re-encode
2. 重新编码
base64 -i desktop/.env.app | tr -d '\n' > /tmp/omi_desktop_app_env_b64.txt
base64 -i desktop/.env.app | tr -d '\n' > /tmp/omi_desktop_app_env_b64.txt
3. Update in Codemagic dashboard:
3. 在Codemagic控制台更新:
- Environment variables tab
- 环境变量标签页
- Delete old OMI_DESKTOP_APP_ENV (desktop_secrets group)
- 删除旧的OMI_DESKTOP_APP_ENV(desktop_secrets分组)
- Add new: name=OMI_DESKTOP_APP_ENV, value=<contents of /tmp/omi_desktop_app_env_b64.txt>,
- 添加新变量:名称=OMI_DESKTOP_APP_ENV,值=</tmp/omi_desktop_app_env_b64.txt的内容>
group=desktop_secrets, Secret=checked
分组=desktop_secrets,勾选Secret
**Keys bundled in `desktop/.env.app`:** `OMI_API_URL`, `DEEPGRAM_API_KEY`, `GEMINI_API_KEY`, `MIXPANEL_PROJECT_TOKEN`, `ANTHROPIC_API_KEY`
**`desktop/.env.app`中打包的密钥:** `OMI_API_URL`, `DEEPGRAM_API_KEY`, `GEMINI_API_KEY`, `MIXPANEL_PROJECT_TOKEN`, `ANTHROPIC_API_KEY`9. Verification
9. 验证
After rotation, verify:
bash
undefined轮换完成后,验证更新结果:
bash
undefinedKeychain
Keychain验证
security find-generic-password -s "<key-name-lowercase>" -w
security find-generic-password -s "<key-name-lowercase>" -w
All .env files
所有.env文件验证
grep "<KEY_NAME>" desktop/.env desktop/.env.app desktop/.env.app.dev desktop/Backend-Rust/.env backend/.env 2>/dev/null
grep "<KEY_NAME>" desktop/.env desktop/.env.app desktop/.env.app.dev desktop/Backend-Rust/.env backend/.env 2>/dev/null
GCP Secret Manager
GCP Secret Manager验证
gcloud secrets versions list <KEY_NAME> --project=based-hardware --format="table(name,state)"
gcloud secrets versions list <KEY_NAME> --project=based-hardware --format="table(name,state)"
Kubernetes rollout status
Kubernetes滚动发布状态验证
kubectl rollout status deployment/prod-omi-backend-listen -n prod-omi-backend --timeout=120s
undefinedkubectl rollout status deployment/prod-omi-backend-listen -n prod-omi-backend --timeout=120s
undefined9. Remind User
9. 提醒用户
After completing rotation, remind the user to:
- Revoke the old key in the provider's console (Google Cloud API Credentials, OpenAI dashboard, etc.)
- Check for unauthorized usage in the provider's usage/billing dashboard during the leak window
完成轮换后,提醒用户:
- 在服务商控制台吊销旧密钥(Google Cloud API凭证、OpenAI控制台等)
- 在泄露窗口期内检查服务商使用/账单控制台,确认是否存在未授权使用
Key-Specific Notes
特定密钥说明
GEMINI_API_KEY
GEMINI_API_KEY
- Used by: backend (Python), desktop app (Swift via env), desktop Rust backend, Codemagic (mobile builds + desktop deploy)
- Codemagic groups: (direct var) AND
app_env(insidedesktop_secretsbase64 bundle)OMI_DESKTOP_APP_ENV - Keychain service:
gemini-api-key - GCP projects: (prod),
based-hardware(dev)based-hardware-dev - Cloud Run: (us-central1, direct env var — NOT via K8s secrets)
desktop-backend - K8s deployments: (via ExternalSecrets)
prod-omi-backend-listen - Helm values reference it via (no hardcoded values in helm charts)
secretKeyRef - IMPORTANT: Also update in Codemagic (step 8) — it contains this key inside the base64-encoded
OMI_DESKTOP_APP_ENV.env.app - WARNING: Never hardcode this key in any tracked file. It has been leaked twice via committed helm values.
- 使用方:后端(Python)、桌面端应用(Swift通过环境变量调用)、桌面端Rust后端、Codemagic(移动端构建+桌面端部署)
- Codemagic分组:(直接变量)和
app_env(在desktop_secretsbase64包内部)OMI_DESKTOP_APP_ENV - Keychain服务名:
gemini-api-key - GCP项目:(生产)、
based-hardware(开发)based-hardware-dev - Cloud Run:(us-central1,直接环境变量——不通过K8s密钥)
desktop-backend - K8s部署:(通过ExternalSecrets)
prod-omi-backend-listen - Helm values通过引用(Helm chart中无硬编码值)
secretKeyRef - 重要提示: 还需要更新Codemagic中的(第8步)——base64编码的
OMI_DESKTOP_APP_ENV中包含该密钥.env.app - 警告: 永远不要在任何被跟踪的文件中硬编码该密钥,之前已经因为提交Helm values泄露过两次。
OPENAI_API_KEY
OPENAI_API_KEY
- Used by: backend (Python), Codemagic (mobile builds)
- Codemagic group:
app_env
- 使用方:后端(Python)、Codemagic(移动端构建)
- Codemagic分组:
app_env
GOOGLE_CLIENT_SECRET
GOOGLE_CLIENT_SECRET
- Used by: backend OAuth, Codemagic
- Codemagic group:
app_env
- 使用方:后端OAuth、Codemagic
- Codemagic分组:
app_env