feat(ql3): validate cluster credential key rotation

This commit is contained in:
whyour
2026-08-26 03:31:13 +08:00
parent b45a5e04b7
commit ac0992081e
23 changed files with 1119 additions and 167 deletions
+12 -9
View File
@@ -958,22 +958,25 @@ stringData:
-----BEGIN CERTIFICATE-----
REPLACE_WITH_OPERATOR_CA_BUNDLE
-----END CERTIFICATE-----
api-credential-pepper: REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL
api-credential-pepper-keyring.json: |
{"schemaVersion":1,"activePepperKeyId":"legacy-v1","keys":[{"pepperKeyId":"legacy-v1","pepper":"REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL"}]}
```
The URL must not contain `ssl*` query parameters. TLS is configured separately
and is fixed to `verify-full` in the committed deployment. The servername is
mandatory, must be an explicit DNS name rather than an IP literal, and must
match the endpoint certificate SAN. Only
`postgres-ca.crt` is projected from this Secret into the runtime trust mount;
the URL, servername and pepper remain environment-only values. The CA loader
requires an absolute path to a regular file that is not group/world writable,
1256 KiB, and contains 116 unique PEM X.509 CA certificates with no trailing
data.
`postgres-ca.crt` and `api-credential-pepper-keyring.json` are projected from
this Secret into the runtime private mount; only the URL and servername remain
environment values. The keyring is a canonical, bounded 12 generation file;
the singleton above is the bootstrap form. The CA loader requires an absolute
path to a regular file that is not group/world writable, 1256 KiB, and
contains 116 unique PEM X.509 CA certificates with no trailing data.
The trust bundle is loaded once for each new application activation. Rotate the
Secret and perform a controlled Deployment rollout; an active Pool never
silently changes trust roots in place. Use the
The trust bundle and API credential keyring are loaded once for each new
application activation. Rotate the Secret and perform a controlled Deployment
rollout; an active process never silently changes either authority in place.
Use the
[old → overlap → new runbook](operations/postgres-ca-rotation.md) and its
`audit:postgres-ca-overlap:ql3` preflight rather than replacing a trust root in
one step.
@@ -113,11 +113,8 @@ spec:
secretKeyRef:
name: ql3-cluster-control-runtime
key: postgres-tls-servername
- name: QL3_API_CREDENTIAL_PEPPER
valueFrom:
secretKeyRef:
name: ql3-cluster-control-runtime
key: api-credential-pepper
- name: QL3_API_CREDENTIAL_PEPPER_KEYRING_FILE
value: /var/run/secrets/qinglong3/postgres-runtime/api-credential-pepper-keyring.json
- name: QL3_POSTGRES_WORKER_INGRESS_URL
valueFrom:
secretKeyRef:
@@ -250,6 +247,8 @@ spec:
items:
- key: postgres-ca.crt
path: ca.crt
- key: api-credential-pepper-keyring.json
path: api-credential-pepper-keyring.json
- name: postgres-worker-ingress-ca
secret:
secretName: ql3-cluster-worker-ingress
@@ -72,7 +72,7 @@ spec:
- --command=/var/run/qinglong3/security-administration-private/input/command.json
- --assertion=/var/run/qinglong3/security-administration-private/input/assertion.jwt
- --keyset=/var/run/qinglong3/security-administration-private/input/keyset.json
- --pepper=/var/run/qinglong3/security-administration-private/input/pepper
- --pepper-keyring=/var/run/qinglong3/security-administration-private/input/pepper-keyring.json
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
@@ -120,8 +120,8 @@ spec:
path: assertion.jwt
- key: keyset.json
path: keyset.json
- key: pepper
path: pepper
- key: pepper-keyring.json
path: pepper-keyring.json
- name: private-input
emptyDir:
medium: Memory
@@ -11,4 +11,5 @@ stringData:
{"schemaVersion":1,"operation":"audit.list","request":{"limit":25,"filter":{"outcome":"allowed"}}}
assertion.jwt: REPLACE_WITH_SHORT_LIVED_MULTI_FACTOR_ASSERTION
keyset.json: REPLACE_WITH_PINNED_SECURITY_ADMINISTRATION_KEYSET
pepper: REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL_API_CREDENTIAL_PEPPER
pepper-keyring.json: |
{"schemaVersion":1,"activePepperKeyId":"REPLACE_WITH_ACTIVE_KEY_ID","keys":[{"pepperKeyId":"REPLACE_WITH_ACTIVE_KEY_ID","pepper":"REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL_API_CREDENTIAL_PEPPER"}]}
@@ -175,7 +175,8 @@ metadata:
namespace: qinglong3-system
type: Opaque
stringData:
api-credential-pepper: REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL
api-credential-pepper-keyring.json: |
{"schemaVersion":1,"activePepperKeyId":"REPLACE_WITH_ACTIVE_KEY_ID","keys":[{"pepperKeyId":"REPLACE_WITH_ACTIVE_KEY_ID","pepper":"REPLACE_WITH_CANONICAL_32_BYTE_BASE64URL"}]}
---
apiVersion: v1
kind: Secret