a certificate for a name Let's Encrypt cannot visit
the whole reason the credential store exists. a tailnet-only hostname cannot be reached on port 80, so HTTP-01 is impossible and a DNS record is the only proof Let's Encrypt accepts — which needs the provider's API key. POST /domains/certificate is the one route here that is deliberately not a pass-through, and it has to be: the request needs dns_provider_credentials, and officer never returns a stored key to any caller. so the platform resolves which provider owns the name from the Domains list, decrypts, builds the request and returns NPM's own answer unchanged. same arrangement as the NPM token one level up — the thing that wants the work done is not the thing holding the password. NOT under /_config. reading and writing a DNS key stays owner-only; USING it on the owner's behalf is the feature, and gating this to the owner would defeat it. a read-level account still cannot reach it, because it is a POST. three refusals, all before anything is placed at the registrar: a name whose apex is not in the domain list, a provider with no key stored, and a certificate spanning two providers — NPM takes one credential per certificate, and discovering that halfway through leaves a challenge record behind. tested, because each one otherwise fails deep inside certbot with an error about something else. ten minute timeout, 120s default propagation. both err long on purpose: NPM waits for the record to spread before asking Let's Encrypt to look, and abandoning the request does not stop it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -111,10 +111,34 @@ it, and the only proof it accepts is a DNS record:
|
||||
}
|
||||
```
|
||||
|
||||
**You cannot fill in `dns_provider_credentials` yourself, and should not try.** Officer stores DNS
|
||||
provider keys encrypted and never returns them — not to you, not to the owner. Reaching for one is the
|
||||
refusal-shaped mistake this skill warns about below. The route that injects it server-side is not built
|
||||
yet; until it is, a private hostname's certificate is something the owner does in NPM's own UI.
|
||||
**You cannot fill in `dns_provider_credentials` yourself, and must not try.** Officer stores DNS provider
|
||||
keys encrypted and never returns them — not to you, not to the owner. Reaching for one is the
|
||||
refusal-shaped mistake this skill warns about.
|
||||
|
||||
**So there is a different route for this, and it is the only one that works:**
|
||||
|
||||
```bash
|
||||
curl -s -X POST -H "Authorization: Bearer $OFFICER_AGENT_KEY" -H "Host: $OFFICER_API_HOST" \
|
||||
-H 'content-type: application/json' \
|
||||
-d '{"domain_names":["private.example.com"]}' \
|
||||
"$OFFICER_API_URL/api/proxy-manager/domains/certificate"
|
||||
```
|
||||
|
||||
Note the path: `/domains/certificate`, **not** `/npm/…`. It is not a pass-through. The platform works out
|
||||
which DNS provider owns that name from the Domains list, decrypts the stored key, builds the request above
|
||||
and hands back NPM's own answer. You ask for a certificate and never see the key that got it.
|
||||
|
||||
`propagation_seconds` may be passed and defaults to 120 — long, because a challenge record that has not
|
||||
spread yet fails in a way that reads as a bad credential. **Expect this to take minutes**, not seconds, and
|
||||
do not retry a request that has not come back.
|
||||
|
||||
What it refuses, and what each refusal means:
|
||||
|
||||
- **400 "Not in the domain list"** — the apex is not in Domains. Officer does not know whose DNS it is.
|
||||
The owner adds it in the Domains section; you cannot.
|
||||
- **409 "No API key stored"** — the domain is known, its provider is known, and no key has been entered.
|
||||
Again the owner's to do, from the same section.
|
||||
- **400 "cannot span two DNS providers"** — one certificate carries one credential. Split the request.
|
||||
|
||||
## Certificates, read the way Let's Encrypt behaves
|
||||
|
||||
|
||||
Reference in New Issue
Block a user