Rotate gitea SECRET_KEY into its own claim, drop gitea-random
Completes the post-breach (CVE-2026-59774) secret split. SECRET_KEY moves from the shared gitea-random claim to a dedicated gitea-secret-key claim with a fresh value, and the now-unused gitea-random claim is removed (ArgoCD prunes it). The earlier concern that rotating SECRET_KEY breaks the 2 push mirrors was wrong: their gitlab.com credentials live in each repo's on-disk git config, not in SECRET_KEY-encrypted storage. Blast radius here is negligible: 0 TOTP 2FA, 0 Actions secrets, 0 runner tokens, pull mirrors are public. SECRET_KEY has no length constraint (Gitea hashes it to derive the AES key), so unlike JWT_SECRET size 32 is fine and is not regenerated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e17b0e0b41
commit
910f2c56d0
+9
-15
@@ -16,28 +16,22 @@ spec:
|
|||||||
|
|
||||||
# Gitea DOES NOT go through Traefik. It has its own IP because ssh :22 would conflict with kube worker ssh. On its own IP, at the moment it doesn't flirt with Traefik — also has its own certificate.
|
# Gitea DOES NOT go through Traefik. It has its own IP because ssh :22 would conflict with kube worker ssh. On its own IP, at the moment it doesn't flirt with Traefik — also has its own certificate.
|
||||||
---
|
---
|
||||||
# After the 2026-09 breach (CVE-2026-59774) all three secrets below leaked
|
# After the 2026-09 breach (CVE-2026-59774) all three security secrets leaked
|
||||||
# because they shared one generated value. INTERNAL_TOKEN and JWT_SECRET were
|
# because they shared one generated value from a single "gitea-random" claim.
|
||||||
# moved to their own claims (gitea-internal-token, gitea-oauth2-jwt) and rotated;
|
# Each now has its own claim and a fresh value: gitea-secret-key,
|
||||||
# the StatefulSet now reads those two from the new claims, so the copies here are
|
# gitea-internal-token and gitea-oauth2-jwt. The old shared gitea-random claim
|
||||||
# unused. SECRET_KEY is intentionally still sourced from this claim and NOT
|
# was removed. SECRET_KEY has no length constraint (Gitea hashes it to derive the
|
||||||
# rotated: a new value would make data-at-rest (push-mirror creds, 2FA)
|
# AES key), so size 32 is fine; the earlier worry about push mirrors was wrong:
|
||||||
# undecryptable and break the 2 push mirrors, whose credentials must be re-entered
|
# their credentials live in each repo's on-disk git config, not SECRET_KEY.
|
||||||
# by hand. Do not shrink this mapping: the operator would regenerate the plaintext
|
|
||||||
# and change SECRET_KEY. Rotate SECRET_KEY in a maintenance window instead.
|
|
||||||
apiVersion: codemowers.cloud/v1beta1
|
apiVersion: codemowers.cloud/v1beta1
|
||||||
kind: SecretClaim
|
kind: SecretClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: gitea-random
|
name: gitea-secret-key
|
||||||
spec:
|
spec:
|
||||||
size: 32
|
size: 32
|
||||||
mapping:
|
mapping:
|
||||||
- key: GITEA__SECURITY__SECRET_KEY
|
- key: GITEA__SECURITY__SECRET_KEY
|
||||||
value: "%(plaintext)s"
|
value: "%(plaintext)s"
|
||||||
- key: GITEA__SECURITY__INTERNAL_TOKEN
|
|
||||||
value: "%(plaintext)s"
|
|
||||||
- key: GITEA__OAUTH2__JWT_SECRET
|
|
||||||
value: "%(plaintext)s"
|
|
||||||
---
|
---
|
||||||
apiVersion: codemowers.cloud/v1beta1
|
apiVersion: codemowers.cloud/v1beta1
|
||||||
kind: SecretClaim
|
kind: SecretClaim
|
||||||
@@ -264,7 +258,7 @@ spec:
|
|||||||
- name: GITEA__SECURITY__SECRET_KEY
|
- name: GITEA__SECURITY__SECRET_KEY
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: gitea-random
|
name: gitea-secret-key
|
||||||
key: GITEA__SECURITY__SECRET_KEY
|
key: GITEA__SECURITY__SECRET_KEY
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
|
|||||||
Reference in New Issue
Block a user