feat(iam): define a KeyRotation for every consumer except poimen-memory
Eight objects cover grafana, argocd, comfyui, minio, paperless, immich, forgejo and api-gw. Each names its ZITADEL app, the Secret it writes, the consumer to roll and whether the consumer reloads hot or needs a restart. All are suspended: the controller image does not exist yet, and an unsuspended object would claim an intent that no process acts on. The README records the retirement target for the 34 .enc.yaml files: six root-of-trust secrets that cannot rotate themselves survive, everything else becomes a KeyRotation and leaves git.
This commit was merged in pull request #84.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
# KeyRotation declares one credential and how to rotate it.
|
||||
#
|
||||
# The resource never holds a secret value. It names where the value goes and how
|
||||
# to prove the new value works. The controller writes the Secret.
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: keyrotations.iam.homelab.riotpiao.com
|
||||
spec:
|
||||
group: iam.homelab.riotpiao.com
|
||||
scope: Namespaced
|
||||
names:
|
||||
kind: KeyRotation
|
||||
plural: keyrotations
|
||||
singular: keyrotation
|
||||
shortNames: [kr]
|
||||
versions:
|
||||
- name: v1
|
||||
served: true
|
||||
storage: true
|
||||
additionalPrinterColumns:
|
||||
- {name: Provider, type: string, jsonPath: .spec.provider}
|
||||
- {name: Strategy, type: string, jsonPath: .spec.strategy}
|
||||
- {name: Phase, type: string, jsonPath: .status.phase}
|
||||
- {name: Last, type: date, jsonPath: .status.lastRotation}
|
||||
- {name: Next, type: date, jsonPath: .status.nextRotation}
|
||||
subresources:
|
||||
status: {}
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
required: [spec]
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
required: [provider, strategy, intervalHours, target]
|
||||
properties:
|
||||
provider:
|
||||
type: string
|
||||
enum: [zitadel-machine-key, zitadel-oidc-client]
|
||||
description: >-
|
||||
Which external API creates the credential.
|
||||
strategy:
|
||||
type: string
|
||||
enum: [overlap, atomic]
|
||||
description: >-
|
||||
overlap keeps the old credential valid until the new one is
|
||||
proven. atomic replaces it in place, because the provider
|
||||
allows only one value.
|
||||
intervalHours:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: How often to rotate.
|
||||
suspend:
|
||||
type: boolean
|
||||
description: Stop automatic rotation without deleting the resource.
|
||||
target:
|
||||
type: object
|
||||
required: [secretName, secretNamespace]
|
||||
properties:
|
||||
zitadelProjectID: {type: string}
|
||||
zitadelAppID: {type: string}
|
||||
machineUserID: {type: string}
|
||||
secretName: {type: string}
|
||||
secretNamespace: {type: string}
|
||||
secretKeys:
|
||||
type: object
|
||||
additionalProperties: {type: string}
|
||||
description: >-
|
||||
Logical field name to Secret key. Unmapped fields keep
|
||||
their logical name.
|
||||
reload:
|
||||
type: string
|
||||
enum: [hot, restart]
|
||||
description: >-
|
||||
hot means the consumer watches the file. restart rolls the
|
||||
consumer so it reads the new value at start.
|
||||
consumers:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [kind, name, namespace]
|
||||
properties:
|
||||
kind: {type: string, enum: [Deployment, StatefulSet]}
|
||||
name: {type: string}
|
||||
namespace: {type: string}
|
||||
verify:
|
||||
type: object
|
||||
properties:
|
||||
introspect:
|
||||
type: boolean
|
||||
description: Check client id and secret against introspection.
|
||||
tokenExchange:
|
||||
type: boolean
|
||||
description: Exchange a token with the new machine key.
|
||||
audienceProject:
|
||||
type: string
|
||||
description: Project id added to the token audience scope.
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
phase:
|
||||
type: string
|
||||
enum: [Pending, Preparing, Propagating, Verifying, Completing, Succeeded, Failed, Suspended]
|
||||
observedGeneration: {type: integer, format: int64}
|
||||
lastRotation: {type: string, format: date-time}
|
||||
nextRotation: {type: string, format: date-time}
|
||||
activeCredentialID: {type: string}
|
||||
previousCredentialID: {type: string}
|
||||
lastError: {type: string}
|
||||
conditions:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required: [type, status, reason, lastTransitionTime]
|
||||
properties:
|
||||
type: {type: string}
|
||||
status: {type: string}
|
||||
reason: {type: string}
|
||||
message: {type: string}
|
||||
lastTransitionTime: {type: string, format: date-time}
|
||||
Reference in New Issue
Block a user