Skip to content

Commit e104427

Browse files
committed
chore: add create-rpc-api-key skill
1 parent 9e217b2 commit e104427

1 file changed

Lines changed: 140 additions & 0 deletions

File tree

  • spartan/.claude/skills/create-rpc-api-key
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
---
2+
name: create-rpc-api-key
3+
description: Add a new public RPC API key consumer to an Aztec RPC environment (mainnet or testnet) — mint the GCP Secret Manager secret with the helper script, wire it into Kong via Terraform, apply, verify it is live, and open the PR. Use when asked to add/create an RPC API key, onboard a new RPC client/consumer, or "give <someone> a mainnet/testnet rpc key".
4+
---
5+
6+
# Create a public RPC API key
7+
8+
Adds one API key for the public RPC gateway. A key is a value stored in GCP Secret Manager; Terraform turns it into a Kong consumer that can call every keyed route in the environment. Externally the consumer is just `clientN`; the real recipient is recorded only as a private annotation on the secret.
9+
10+
The two RPC environments live in `spartan/terraform/deploy-rpc/environments/`:
11+
12+
| Environment | dir | secret prefix | namespace / release prefix |
13+
|---|---|---|---|
14+
| mainnet | `environments/mainnet` | `mainnet-rpc-consumer` | `mainnet-rpc` / `mainnet` |
15+
| testnet | `environments/testnet` | (check that env's `CONSUMERS` entries) | `testnet-rpc` / `testnet` |
16+
17+
The examples below use **mainnet**. For testnet, swap the dir, prefix, namespace, and context. Always read the target env's existing `CONSUMERS` entries and copy their exact prefix rather than assuming.
18+
19+
## Before you start — access and tooling
20+
21+
- **Working directory**: agents in this repo often run with `yarn-project` as the shell CWD, but the script and Terraform live under the git root's `spartan/`. Use absolute paths (or the correct git-root-relative path). Do **not** `cd` — the Bash working directory persists across calls and a stray `cd` will break later relative paths.
22+
- **gcloud**: authenticated, project `testnet-440309` (`gcloud config get-value project`). Terraform's GCS backend and google provider need Application Default Credentials — if you hit auth errors, `gcloud auth application-default login`.
23+
- **kubectl**: the GKE context `gke_testnet-440309_us-west1-a_aztec-gke-public` must exist (`kubectl config get-contexts`).
24+
- **Terraform version**: the remote state may have been written by a newer Terraform than your local binary, and Terraform refuses to operate on newer state. Check and match:
25+
```bash
26+
# state version (mainnet)
27+
gcloud storage cat gs://aztec-terraform/aztec-gke-public/mainnet-rpc/deploy-rpc/terraform.tfstate/default.tfstate | jq -r .terraform_version
28+
terraform version
29+
```
30+
If local `< state`, install a matching-or-newer Terraform before continuing.
31+
32+
## Step 1 — mint the secret
33+
34+
`spartan/scripts/create_api_key.sh <prefix> <internal-owner-name>`
35+
36+
- `<prefix>` = the environment's consumer prefix, e.g. `mainnet-rpc-consumer`.
37+
- `<internal-owner-name>` = a private annotation naming the real recipient (e.g. `vitalik`, `fairies`). Kept for our records only — **do not put it in the public PR.** Match the lowercase style of existing annotations.
38+
- The script lists existing `<prefix>-client*` secrets, takes the most recently created, and creates the next index (`clientN+1`). If none exist it starts at `client1`.
39+
40+
```bash
41+
/abs/path/to/spartan/scripts/create_api_key.sh mainnet-rpc-consumer fairies
42+
# -> Created version [1] of the secret [mainnet-rpc-consumer-client9].
43+
```
44+
45+
Verify (note the index and annotation):
46+
```bash
47+
gcloud secrets describe mainnet-rpc-consumer-client9 --format="value(name.basename(), annotations)"
48+
```
49+
50+
Caveat: the "next index" is derived from the most-recently-*created* secret, not the max number. This is only a problem if secrets were created out of order — normally fine.
51+
52+
## Step 2 — add the consumer to Terraform
53+
54+
Edit `spartan/terraform/deploy-rpc/environments/<env>/main.tf` and append a `clientN` entry to the `CONSUMERS` map, matching the existing entries exactly:
55+
56+
```hcl
57+
client9 = {
58+
username = "mainnet-rpc-consumer-client9"
59+
gcp_secret_manager_secret_name = "mainnet-rpc-consumer-client9"
60+
rate_limit_minute = 0
61+
}
62+
```
63+
64+
`rate_limit_minute = 0` means unlimited (no rate-limit plugin is generated). Use a positive value only if a cap is intended.
65+
66+
## Step 3 — plan and verify (the guardrail)
67+
68+
```bash
69+
TF=/abs/path/to/spartan/terraform/deploy-rpc/environments/mainnet
70+
terraform -chdir="$TF" init -reconfigure -input=false
71+
terraform -chdir="$TF" plan -input=false -out=tfplan
72+
```
73+
74+
The plan **must** be exactly:
75+
76+
```
77+
Plan: 2 to add, 0 to change, 0 to destroy.
78+
```
79+
80+
The two additions are the new consumer's resources:
81+
- `module.environment.module.rpc_gateway.kubernetes_manifest.consumer["clientN"]` — the KongConsumer
82+
- `module.environment.module.rpc_gateway.kubernetes_manifest.consumer_key_external_secret["clientN"]` — the ExternalSecret that pulls the key from Secret Manager into Kong
83+
84+
If the plan shows **anything else** — a change/replace/destroy on an RPC node, helm release, domain, or another consumer — STOP and find out why. Common cause: a deployment change (e.g. a version promotion) has been merged to the branch but not yet applied to live, so applying now would also push that change. You do **not** need to pass image `-var`s if the env's image defaults match the live pods (`kubectl -n <ns> get pods -o jsonpath=... <node>`). If you must add a key without triggering such a pending deployment, temporarily revert that change in your working tree so the plan is clean — but do not commit the revert (see Step 6).
85+
86+
## Step 4 — apply
87+
88+
```bash
89+
terraform -chdir="$TF" apply -input=false tfplan
90+
```
91+
92+
The ExternalSecret has a `wait { Ready }` block, so the GCP secret from Step 1 must already exist or the apply will block waiting for it to sync.
93+
94+
## Step 5 — verify it is live
95+
96+
```bash
97+
CTX=gke_testnet-440309_us-west1-a_aztec-gke-public
98+
kubectl --context "$CTX" -n mainnet-rpc get kongconsumer mainnet-client9 # PROGRAMMED=True
99+
kubectl --context "$CTX" -n mainnet-rpc get externalsecret mainnet-client9-rpc-key-auth # Ready/SecretSynced=True
100+
```
101+
102+
(Resource names are `<release-prefix>-clientN` and `<release-prefix>-clientN-rpc-key-auth`.)
103+
104+
## Step 6 — open the PR
105+
106+
The committed Terraform is a record of what is already applied. Keep the PR to a single-purpose, one-line addition.
107+
108+
- **Commit only the `clientN` addition.** If you made a temporary revert in Step 3 to get a clean plan, undo it so it is not committed — the diff must be the `clientN` block and nothing else. Verify with `git diff <base>...HEAD -- <main.tf path>`.
109+
- Commit message: `chore: add new client` (the established convention). Author is the git author — no Claude attribution.
110+
- **Base branch: `merge-train/spartan`** for these `spartan/` deploy changes (not `next`). Branch off it, and if the base has moved, rebase the single commit onto it so the PR diff stays client-only.
111+
112+
```bash
113+
git checkout -b stack/chore-add-new-client-N origin/merge-train/spartan
114+
# edit main.tf to add clientN
115+
git add /abs/path/.../environments/mainnet/main.tf
116+
git commit -m "chore: add new client"
117+
git push -u origin stack/chore-add-new-client-N
118+
gh pr create --base merge-train/spartan --head stack/chore-add-new-client-N \
119+
--title "chore: add new client" \
120+
--body "Adds \`clientN\` to the mainnet RPC consumers. Secret created and already \`terraform apply\`-ed; the plan was the two expected resources (KongConsumer + ExternalSecret). Rate limit 0 = unlimited."
121+
```
122+
123+
**Print the PR URL back to the user.** Do not name the private owner in the PR title or body.
124+
125+
If the previous client-add PR merged while you were working (and its branch was deleted), target `merge-train/spartan` directly and rebase your commit onto it so the diff is only the new client.
126+
127+
## Handing the key to the recipient
128+
129+
The key value was never printed (the script piped it straight into Secret Manager). Retrieve it with:
130+
131+
```bash
132+
gcloud secrets versions access latest --secret=mainnet-rpc-consumer-client9
133+
```
134+
135+
It is a bearer credential — share it over a secure channel, not plain chat/email. The recipient uses it either way:
136+
137+
- Path form: `https://canonical.mainnet.rpc.aztec-labs.com/<KEY>`
138+
- Header form: `x-aztec-api-key: <KEY>` against `https://canonical.mainnet.rpc.aztec-labs.com/`
139+
140+
The consumer is defined at the environment level, so the key authenticates on **every** keyed route in that environment (e.g. mainnet `v4`, `canonical`, and `v5` hosts) — one key, all routes.

0 commit comments

Comments
 (0)