mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-23 12:05:27 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# QingLong 3.0 Worker Credential Management External OIDC Ceremony
|
||||
|
||||
This operation records one external-identity, two-User management ceremony. It creates and approves a
|
||||
secret-free Worker credential plan, then inspects it without consuming the approval or executing credential
|
||||
delivery.
|
||||
|
||||
It is a short-lived operator command, not a controller. Run it only against an already reviewed Worker
|
||||
management endpoint. A successful local/K3s fixture is not a substitute for this external report.
|
||||
|
||||
## Private inputs
|
||||
|
||||
Prepare five canonical absolute paths:
|
||||
|
||||
- mode 0600 production client config using the exact Worker endpoint path, TLS server name, CA file, client
|
||||
certificate file, matching private-key file and a 1–30 second timeout;
|
||||
- mode 0600 requester assertion;
|
||||
- mode 0600 reviewer assertion for a different User from the same external issuer;
|
||||
- mode 0600 ceremony JSON;
|
||||
- an unused output path in a canonical private directory.
|
||||
|
||||
Both assertions must use:
|
||||
|
||||
```text
|
||||
aud=qinglong3-worker-credential-management
|
||||
typ=ql3-worker-credential-management+jwt
|
||||
ql3_purpose=worker-credential-management
|
||||
```
|
||||
|
||||
The client certificate is a separate transport-possession factor. It must be issued by the manager's reviewed
|
||||
client CA, be absent from the current CRL and must not be reused as an assertion-signing key or Worker execution
|
||||
identity. A valid certificate never substitutes for either external User assertion.
|
||||
|
||||
The ceremony JSON has this exact top-level shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"planRequest": {
|
||||
"actionRef": "worker-credential:REVIEWED_WORKER:REVIEWED_GENERATION",
|
||||
"authorityProjectId": "REVIEWED_AUTHORITY_PROJECT",
|
||||
"action": "rotate",
|
||||
"deliveryId": "REVIEWED_UUID",
|
||||
"workerId": "REVIEWED_WORKER",
|
||||
"credentialId": "REVIEWED_NEW_CREDENTIAL",
|
||||
"previousCredentialId": "REVIEWED_PREVIOUS_CREDENTIAL",
|
||||
"credentialNotBeforeAtMs": 0,
|
||||
"credentialExpiresAtMs": 0,
|
||||
"deploymentTargetDigest": "REVIEWED_64_LOWERCASE_HEX_DIGEST",
|
||||
"deploymentGeneration": "REVIEWED_GENERATION"
|
||||
},
|
||||
"approvalRequestId": "REVIEWED_APPROVAL_ID",
|
||||
"approvalAuditEventId": "REVIEWED_UUID",
|
||||
"requesterDecisionId": "REVIEWED_SELF_DENY_PROBE_ID",
|
||||
"requesterDecisionAuditEventId": "REVIEWED_UUID",
|
||||
"reviewerDecisionId": "REVIEWED_REVIEWER_DECISION_ID",
|
||||
"reviewerDecisionAuditEventId": "REVIEWED_UUID",
|
||||
"decisionReasonCode": "reviewed",
|
||||
"inspectionId": "REVIEWED_INSPECTION_ID"
|
||||
}
|
||||
```
|
||||
|
||||
Replace both timestamps with valid future millisecond values accepted by the Worker management plan contract.
|
||||
Use new identifiers dedicated to evidence; do not reuse a production delivery that an executor may consume.
|
||||
|
||||
## Run and audit
|
||||
|
||||
```bash
|
||||
export QL3_WORKER_CREDENTIAL_MANAGEMENT_LIVE_CEREMONY=1
|
||||
|
||||
pnpm evidence:worker-management-live-ceremony:ql3 -- \
|
||||
--config=/absolute/private/client.json \
|
||||
--requester-assertion=/absolute/private/requester.jwt \
|
||||
--reviewer-assertion=/absolute/private/reviewer.jwt \
|
||||
--ceremony=/absolute/private/ceremony.json \
|
||||
--output=/absolute/private/worker-management-ceremony.json
|
||||
|
||||
unset QL3_WORKER_CREDENTIAL_MANAGEMENT_LIVE_CEREMONY
|
||||
|
||||
pnpm audit:worker-management-live-ceremony:ql3 -- \
|
||||
--report=/absolute/private/worker-management-ceremony.json
|
||||
```
|
||||
|
||||
The runner performs exactly five calls: requester plan, requester propose, requester self-decision rejection,
|
||||
reviewer decision and reviewer inspect. It fails if self-decision is accepted, if the resulting approval is not
|
||||
approved by the reviewer, or if inspect observes a dispatch/consumption.
|
||||
|
||||
The report contains no raw assertion, subject, JTI, request ID, Worker identifier, Project identifier, token,
|
||||
Secret, DSN or private key. Retain it with the IdP/operator change record and the independent durable-audit
|
||||
evidence.
|
||||
|
||||
## Collect independent durable-audit evidence
|
||||
|
||||
Create a short-lived PostgreSQL login role outside the QingLong migration stream. It must not inherit or be
|
||||
granted any QingLong runtime role:
|
||||
|
||||
```sql
|
||||
CREATE ROLE ql3_worker_management_evidence
|
||||
LOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE
|
||||
NOREPLICATION NOBYPASSRLS;
|
||||
|
||||
GRANT CONNECT ON DATABASE qinglong
|
||||
TO ql3_worker_management_evidence;
|
||||
GRANT USAGE ON SCHEMA ql3
|
||||
TO ql3_worker_management_evidence;
|
||||
GRANT SELECT ON
|
||||
ql3.worker_credential_management_plans,
|
||||
ql3.approval_requests,
|
||||
ql3.security_audit_events
|
||||
TO ql3_worker_management_evidence;
|
||||
```
|
||||
|
||||
Set its password through the deployment's private credential mechanism, not a checked-in SQL file. Prepare a
|
||||
mode 0600 libpq service file and an independently protected passfile. The service entry should use
|
||||
`sslmode=verify-full`, the reviewed hostname and an absolute CA path; do not put a DSN on the command line.
|
||||
|
||||
Run the second collector only after the ceremony report has passed its offline audit:
|
||||
|
||||
```bash
|
||||
export QL3_WORKER_CREDENTIAL_MANAGEMENT_DURABLE_AUDIT_EVIDENCE=1
|
||||
|
||||
pnpm evidence:worker-management-durable-audit:ql3 -- \
|
||||
--ceremony-report=/absolute/private/worker-management-ceremony.json \
|
||||
--ceremony=/absolute/private/ceremony.json \
|
||||
--pg-service-file=/absolute/private/pg_service.conf \
|
||||
--pg-service=ql3_worker_management_evidence \
|
||||
--output=/absolute/private/worker-management-durable-audit.json
|
||||
|
||||
unset QL3_WORKER_CREDENTIAL_MANAGEMENT_DURABLE_AUDIT_EVIDENCE
|
||||
|
||||
pnpm audit:worker-management-durable-audit:ql3 -- \
|
||||
--report=/absolute/private/worker-management-durable-audit.json
|
||||
```
|
||||
|
||||
The collector rejects a role that can read any other `ql3` table, mutate any `ql3` table, or become a
|
||||
privileged QingLong role. It observes exactly two durable audit rows: proposal and reviewer decision. The
|
||||
requester's rejected self-decision must have no audit row because separation-of-duty fails before the database
|
||||
update/audit insert transaction can commit. The v1 evidence contract requires PostgreSQL 18.4 or a later
|
||||
security patch in the reviewed 18.x major.
|
||||
|
||||
After retaining the report, revoke the three SELECT grants, schema usage and database connect grant, then drop
|
||||
the short-lived role according to the deployment's credential revocation procedure. Do not retain its passfile
|
||||
with the low-sensitive evidence reports.
|
||||
|
||||
If the runner stops after creating durable facts, inspect them before using any new identifiers. Do not infer
|
||||
rollback from a missing response and do not hand this evidence-only approval to the credential executor.
|
||||
Reference in New Issue
Block a user