Initial public release v1.0.7
- Streamlined README focused on quick start - Complete examples for all major use cases - Decision tree for choosing right pattern - Comprehensive troubleshooting guide
This commit is contained in:
287
examples/example-2-registry-rotation-simple.yaml
Normal file
287
examples/example-2-registry-rotation-simple.yaml
Normal file
@@ -0,0 +1,287 @@
|
||||
# Example 2: Container Registry with Rotation + Reloader
|
||||
#
|
||||
# Use case: Docker registry with basic auth that rotates every 90 days
|
||||
#
|
||||
# Characteristics:
|
||||
# - Password rotates every 90 days
|
||||
# - Registry doesn't need old password to accept new one
|
||||
# - InitContainer regenerates htpasswd on pod restart
|
||||
# - Reloader automatically restarts pod when secret changes
|
||||
# - No keepPreviousVersion needed
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: registry
|
||||
|
||||
---
|
||||
# ManagedSecret generates and rotates registry credentials
|
||||
apiVersion: secrets.c5ai.ch/v1alpha1
|
||||
kind: ManagedSecret
|
||||
metadata:
|
||||
name: registry-auth
|
||||
namespace: registry
|
||||
spec:
|
||||
vault:
|
||||
address: "http://openbao.openbao.svc.cluster.local:8200"
|
||||
authMethod: kubernetes
|
||||
role: managedsecret-operator
|
||||
kvVersion: v2
|
||||
mount: secret
|
||||
path: registry/auth
|
||||
|
||||
fields:
|
||||
- name: username
|
||||
type: static
|
||||
value: "admin"
|
||||
|
||||
- name: password
|
||||
type: generated
|
||||
generator:
|
||||
type: password
|
||||
length: 32
|
||||
minDigits: 5
|
||||
minSymbols: 5
|
||||
minLowercase: 5
|
||||
minUppercase: 5
|
||||
symbolCharacters: "!@#$%^&*"
|
||||
allowRepeat: false
|
||||
|
||||
destination:
|
||||
name: registry-credentials
|
||||
type: Opaque
|
||||
# No need for previous version - htpasswd is regenerated fresh
|
||||
|
||||
rotation:
|
||||
enabled: true
|
||||
schedule: 2160h # 90 days
|
||||
rotateGeneratedOnly: true # Only rotate password, keep username
|
||||
|
||||
---
|
||||
# PersistentVolumeClaim for registry storage
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: registry-pvc
|
||||
namespace: registry
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
storageClassName: longhorn
|
||||
|
||||
---
|
||||
# Registry Deployment with Reloader integration
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: registry
|
||||
namespace: registry
|
||||
labels:
|
||||
app: registry
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: registry
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: registry
|
||||
annotations:
|
||||
# Reloader watches registry-credentials and restarts pod on change
|
||||
reloader.stakater.com/auto: "true"
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
fsGroup: 65534
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
initContainers:
|
||||
# Generate htpasswd file from current credentials at pod startup
|
||||
- name: generate-htpasswd
|
||||
image: httpd:2.4-alpine
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
USERNAME=$(cat /credentials/username)
|
||||
PASSWORD=$(cat /credentials/password)
|
||||
htpasswd -Bbn "$USERNAME" "$PASSWORD" > /auth/htpasswd
|
||||
chmod 644 /auth/htpasswd
|
||||
echo "htpasswd generated with user: $USERNAME"
|
||||
volumeMounts:
|
||||
- name: credentials
|
||||
mountPath: /credentials
|
||||
readOnly: true
|
||||
- name: auth
|
||||
mountPath: /auth
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
|
||||
containers:
|
||||
- name: registry
|
||||
image: registry:2
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
name: http
|
||||
env:
|
||||
- name: REGISTRY_STORAGE_DELETE_ENABLED
|
||||
value: "true"
|
||||
- name: REGISTRY_HTTP_ADDR
|
||||
value: "0.0.0.0:5000"
|
||||
# Enable HTTP basic auth
|
||||
- name: REGISTRY_AUTH
|
||||
value: "htpasswd"
|
||||
- name: REGISTRY_AUTH_HTPASSWD_REALM
|
||||
value: "Registry Realm"
|
||||
- name: REGISTRY_AUTH_HTPASSWD_PATH
|
||||
value: "/auth/htpasswd"
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
volumeMounts:
|
||||
- name: registry-storage
|
||||
mountPath: /var/lib/registry
|
||||
- name: auth
|
||||
mountPath: /auth
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 5000
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 5000
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
volumes:
|
||||
- name: registry-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: registry-pvc
|
||||
- name: credentials
|
||||
secret:
|
||||
secretName: registry-credentials
|
||||
- name: auth
|
||||
emptyDir: {}
|
||||
|
||||
---
|
||||
# Service for internal access
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: registry
|
||||
namespace: registry
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app: registry
|
||||
ports:
|
||||
- port: 5000
|
||||
targetPort: 5000
|
||||
protocol: TCP
|
||||
name: http
|
||||
|
||||
---
|
||||
# Ingress for external access with TLS
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: registry
|
||||
namespace: registry
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-production
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- registry.c5ai.ch
|
||||
secretName: registry-ingress-tls
|
||||
rules:
|
||||
- host: registry.c5ai.ch
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: registry
|
||||
port:
|
||||
number: 5000
|
||||
|
||||
---
|
||||
# How the rotation flow works:
|
||||
#
|
||||
# 1. After 90 days, ManagedSecret operator:
|
||||
# - Generates new password
|
||||
# - Updates Vault
|
||||
# - Updates registry-credentials Secret
|
||||
#
|
||||
# 2. Reloader detects Secret change:
|
||||
# - Sees resourceVersion changed
|
||||
# - Triggers rolling restart of registry Deployment
|
||||
#
|
||||
# 3. Pod restart with new credentials:
|
||||
# - InitContainer runs
|
||||
# - Reads NEW password from registry-credentials
|
||||
# - Generates fresh htpasswd file
|
||||
# - Registry container starts with new htpasswd
|
||||
#
|
||||
# 4. Result:
|
||||
# - Old clients with old password: FAIL (401 Unauthorized)
|
||||
# - New clients with new password: SUCCESS
|
||||
# - Downtime: ~1-2 minutes during rolling restart
|
||||
|
||||
---
|
||||
# Testing commands:
|
||||
#
|
||||
# # Get current credentials
|
||||
# kubectl get secret registry-credentials -n registry -o jsonpath='{.data.username}' | base64 -d
|
||||
# kubectl get secret registry-credentials -n registry -o jsonpath='{.data.password}' | base64 -d
|
||||
#
|
||||
# # Test without auth (should fail)
|
||||
# curl -i https://registry.c5ai.ch/v2/
|
||||
#
|
||||
# # Test with auth (should succeed)
|
||||
# REGISTRY_USER=$(kubectl get secret registry-credentials -n registry -o jsonpath='{.data.username}' | base64 -d)
|
||||
# REGISTRY_PASS=$(kubectl get secret registry-credentials -n registry -o jsonpath='{.data.password}' | base64 -d)
|
||||
# curl -u $REGISTRY_USER:$REGISTRY_PASS https://registry.c5ai.ch/v2/_catalog
|
||||
#
|
||||
# # Docker login
|
||||
# docker login registry.c5ai.ch -u $REGISTRY_USER -p $REGISTRY_PASS
|
||||
#
|
||||
# # Force rotation test
|
||||
# kubectl annotate managedsecret registry-auth -n registry reconcile="$(date +%s)" --overwrite
|
||||
# kubectl get pods -n registry -w # Watch pod restart
|
||||
Reference in New Issue
Block a user