- ExternalSecret syncs age key from Vault to pod - CRD defines rotation schedule for each secret - Controller watches CRD, rotates on schedule: * Call provider API (Authentik/Forgejo/MinIO) for new secret * Update k8s Secret * Update .enc.yaml via sops (uses age key from Vault) * Git commit and push - Vault is source of truth for age key (never on disk) - Examples: minio-oidc (90d), portfolio-agent (90d), forgejo-token (90d), minio-root (180d)
145 lines
3.7 KiB
YAML
145 lines
3.7 KiB
YAML
apiVersion: apiextensions.k8s.io/v1
|
|
kind: CustomResourceDefinition
|
|
metadata:
|
|
name: secretrotations.homelab.riotpiao.com
|
|
spec:
|
|
group: homelab.riotpiao.com
|
|
names:
|
|
kind: SecretRotation
|
|
plural: secretrotations
|
|
scope: Namespaced
|
|
versions:
|
|
- name: v1
|
|
served: true
|
|
storage: true
|
|
schema:
|
|
openAPIV3Schema:
|
|
type: object
|
|
properties:
|
|
metadata:
|
|
type: object
|
|
spec:
|
|
type: object
|
|
required:
|
|
- provider
|
|
- rotationInterval
|
|
properties:
|
|
# External system: authentik | forgejo | minio | vault
|
|
provider:
|
|
type: string
|
|
enum: [authentik, forgejo, minio, vault]
|
|
|
|
# How often to rotate (hours)
|
|
rotationInterval:
|
|
type: integer
|
|
minimum: 24
|
|
|
|
# Application ID in external system
|
|
appId:
|
|
type: string
|
|
|
|
# k8s Secret to update (name, namespace, key)
|
|
secretRef:
|
|
type: object
|
|
required: [name, namespace]
|
|
properties:
|
|
name:
|
|
type: string
|
|
namespace:
|
|
type: string
|
|
key:
|
|
type: string
|
|
description: "Secret key to update (e.g., MINIO_IDENTITY_OPENID_CLIENT_SECRET)"
|
|
|
|
# Path to git file that holds the secret (for .enc.yaml files)
|
|
gitPath:
|
|
type: string
|
|
description: "Path in homelab repo to .enc.yaml file"
|
|
|
|
# Ansible template values to substitute
|
|
templateValues:
|
|
type: object
|
|
additionalProperties:
|
|
type: string
|
|
|
|
status:
|
|
type: object
|
|
properties:
|
|
lastRotationTime:
|
|
type: string
|
|
format: date-time
|
|
nextRotationTime:
|
|
type: string
|
|
format: date-time
|
|
lastRotationStatus:
|
|
type: string
|
|
enum: [Success, Failed, Pending]
|
|
lastRotationError:
|
|
type: string
|
|
lastCommitHash:
|
|
type: string
|
|
|
|
---
|
|
# Example usage:
|
|
apiVersion: homelab.riotpiao.com/v1
|
|
kind: SecretRotation
|
|
metadata:
|
|
name: minio-oidc
|
|
namespace: secret-rotation
|
|
spec:
|
|
provider: authentik
|
|
rotationInterval: 2160 # 90 days in hours
|
|
appId: minio
|
|
secretRef:
|
|
name: minio-oidc
|
|
namespace: storage
|
|
key: MINIO_IDENTITY_OPENID_CLIENT_SECRET
|
|
gitPath: k8s/argocd/secrets/minio-oidc.enc.yaml
|
|
|
|
---
|
|
apiVersion: homelab.riotpiao.com/v1
|
|
kind: SecretRotation
|
|
metadata:
|
|
name: portfolio-agent-oidc
|
|
namespace: secret-rotation
|
|
spec:
|
|
provider: authentik
|
|
rotationInterval: 2160
|
|
appId: portfolio-agent
|
|
secretRef:
|
|
name: portfolio-agent-oidc
|
|
namespace: portfolio
|
|
key: CLIENT_SECRET
|
|
gitPath: k8s/argocd/secrets/portfolio-agent-oidc.enc.yaml
|
|
|
|
---
|
|
apiVersion: homelab.riotpiao.com/v1
|
|
kind: SecretRotation
|
|
metadata:
|
|
name: forgejo-registry-token
|
|
namespace: secret-rotation
|
|
spec:
|
|
provider: forgejo
|
|
rotationInterval: 2160
|
|
appId: rock/riotpiao.com
|
|
secretRef:
|
|
name: forgejo-registry-secret
|
|
namespace: kube-system
|
|
key: REGISTRY_TOKEN
|
|
gitPath: k8s/argocd/secrets/forgejo-registry-secret.enc.yaml
|
|
|
|
---
|
|
apiVersion: homelab.riotpiao.com/v1
|
|
kind: SecretRotation
|
|
metadata:
|
|
name: minio-root-credentials
|
|
namespace: secret-rotation
|
|
spec:
|
|
provider: minio
|
|
rotationInterval: 4320 # 180 days in hours
|
|
appId: root
|
|
secretRef:
|
|
name: minio-creds
|
|
namespace: storage
|
|
gitPath: k8s/argocd/secrets/minio-secrets.enc.yaml
|