Initial commit - production deployment

This commit is contained in:
2026-01-21 17:17:16 +01:00
commit c23d00dd92
2289 changed files with 638440 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
# Storage infrastructure
- minio/minio-deployment.yaml
- minio/minio-pvc.yaml
- minio/minio-secrets.yaml
- minio/minio-bucket-init-job.yaml
- minio/secrets/minio-tls-secret.yaml
# Cache infrastructure
- redis/redis.yaml
- redis/secrets/redis-tls-secret.yaml
# Database infrastructure
- postgres/secrets/postgres-tls-secret.yaml
- postgres/configs/postgres-logging-config.yaml
- postgres/configs/postgres-init-config.yaml

View File

@@ -0,0 +1,193 @@
apiVersion: batch/v1
kind: Job
metadata:
name: minio-bucket-init
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio-bucket-init
app.kubernetes.io/component: storage-init
app.kubernetes.io/part-of: bakery-ia
spec:
ttlSecondsAfterFinished: 300
backoffLimit: 3
template:
metadata:
labels:
app.kubernetes.io/name: minio-bucket-init
app.kubernetes.io/component: storage-init
spec:
restartPolicy: OnFailure
initContainers:
# Wait for MinIO to be ready
- name: wait-for-minio
image: busybox:1.36
command:
- sh
- -c
- |
echo "Waiting for MinIO to be ready..."
until nc -z minio.bakery-ia.svc.cluster.local 9000; do
echo "MinIO not ready, waiting..."
sleep 5
done
echo "MinIO is ready!"
containers:
- name: bucket-init
image: minio/mc:RELEASE.2024-11-17T19-35-25Z
command:
- /bin/sh
- -c
- |
set -e
echo "Configuring MinIO client..."
# Configure mc alias with TLS (skip cert verification for self-signed)
mc alias set myminio https://minio.bakery-ia.svc.cluster.local:9000 \
${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD} --insecure
echo "Creating buckets..."
# Create training-models bucket if not exists
if ! mc ls myminio/training-models --insecure 2>/dev/null; then
mc mb myminio/training-models --insecure
echo "Created bucket: training-models"
else
echo "Bucket already exists: training-models"
fi
# Set bucket policy (private by default)
mc anonymous set none myminio/training-models --insecure
# Enable versioning for model backups
mc version enable myminio/training-models --insecure
echo "Enabled versioning on training-models bucket"
# Set lifecycle policy to expire old versions after 90 days
cat > /tmp/lifecycle.json << 'EOF'
{
"Rules": [
{
"ID": "expire-old-versions",
"Status": "Enabled",
"Filter": {
"Prefix": "models/"
},
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90
}
},
{
"ID": "expire-old-metadata",
"Status": "Enabled",
"Filter": {
"Prefix": "models/"
},
"Expiration": {
"ExpiredObjectDeleteMarker": true
}
}
]
}
EOF
mc ilm import myminio/training-models < /tmp/lifecycle.json --insecure || true
echo "Lifecycle policy configured"
# Create service accounts with limited permissions
echo "Creating service accounts..."
# Training service policy (read/write models)
cat > /tmp/training-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": [
"arn:aws:s3:::training-models",
"arn:aws:s3:::training-models/*"
]
}
]
}
EOF
# Forecasting service policy (read-only models)
cat > /tmp/forecasting-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::training-models",
"arn:aws:s3:::training-models/*"
]
}
]
}
EOF
# Create service accounts using credentials from secrets
echo "Creating service accounts..."
mc admin user add myminio ${TRAINING_MINIO_USER} ${TRAINING_MINIO_PASSWORD} --insecure 2>/dev/null || true
mc admin user add myminio ${FORECASTING_MINIO_USER} ${FORECASTING_MINIO_PASSWORD} --insecure 2>/dev/null || true
# Apply policies (ignore errors if already exists)
mc admin policy create myminio training-policy /tmp/training-policy.json --insecure 2>/dev/null || true
mc admin policy attach myminio training-policy --user=${TRAINING_MINIO_USER} --insecure 2>/dev/null || true
mc admin policy create myminio forecasting-policy /tmp/forecasting-policy.json --insecure 2>/dev/null || true
mc admin policy attach myminio forecasting-policy --user=${FORECASTING_MINIO_USER} --insecure 2>/dev/null || true
echo "MinIO bucket initialization complete!"
# List buckets for verification
echo "Current buckets:"
mc ls myminio --insecure
env:
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_ROOT_USER
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_ROOT_PASSWORD
# Training service MinIO credentials
- name: TRAINING_MINIO_USER
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_ACCESS_KEY
- name: TRAINING_MINIO_PASSWORD
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_SECRET_KEY
# Forecasting service MinIO credentials
- name: FORECASTING_MINIO_USER
valueFrom:
secretKeyRef:
name: minio-secrets
key: FORECASTING_MINIO_ACCESS_KEY
- name: FORECASTING_MINIO_PASSWORD
valueFrom:
secretKeyRef:
name: minio-secrets
key: FORECASTING_MINIO_SECRET_KEY

View File

@@ -0,0 +1,154 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
app.kubernetes.io/part-of: bakery-ia
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
template:
metadata:
labels:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
spec:
# Init container to set up TLS certificates with correct permissions
initContainers:
- name: init-certs
image: busybox:1.36
command:
- sh
- -c
- |
mkdir -p /certs/CAs
cp /certs-secret/minio-cert.pem /certs/public.crt
cp /certs-secret/minio-key.pem /certs/private.key
cp /certs-secret/ca-cert.pem /certs/CAs/ca.crt
chmod 600 /certs/private.key
chmod 644 /certs/public.crt /certs/CAs/ca.crt
volumeMounts:
- name: certs-secret
mountPath: /certs-secret
readOnly: true
- name: certs
mountPath: /certs
containers:
- name: minio
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
args:
- server
- /data
- --console-address
- :9001
- --address
- :9000
- --certs-dir
- /certs
env:
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_ROOT_USER
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: minio-secrets
key: MINIO_ROOT_PASSWORD
# Enable TLS for MinIO
- name: MINIO_SERVER_URL
value: "https://minio.bakery-ia.svc.cluster.local:9000"
- name: MINIO_BROWSER_REDIRECT_URL
value: "https://minio-console.bakery-ia.svc.cluster.local:9001"
ports:
- containerPort: 9000
name: api
- containerPort: 9001
name: console
volumeMounts:
- name: minio-data
mountPath: /data
- name: certs
mountPath: /certs
readOnly: true
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /minio/health/live
port: 9000
scheme: HTTPS
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /minio/health/ready
port: 9000
scheme: HTTPS
initialDelaySeconds: 5
periodSeconds: 15
volumes:
- name: minio-data
persistentVolumeClaim:
claimName: minio-data
- name: certs-secret
secret:
secretName: minio-tls
- name: certs
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: minio
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
spec:
type: ClusterIP
ports:
- port: 9000
targetPort: 9000
protocol: TCP
name: api
- port: 9001
targetPort: 9001
protocol: TCP
name: console
selector:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
---
apiVersion: v1
kind: Service
metadata:
name: minio-console
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage
spec:
type: ClusterIP
ports:
- port: 9001
targetPort: 9001
protocol: TCP
name: console
selector:
app.kubernetes.io/name: minio
app.kubernetes.io/component: storage

View File

@@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minio-data
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio-data
app.kubernetes.io/component: storage
app.kubernetes.io/part-of: bakery-ia
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: standard

View File

@@ -0,0 +1,22 @@
apiVersion: v1
kind: Secret
metadata:
name: minio-secrets
namespace: bakery-ia
labels:
app.kubernetes.io/name: minio-secrets
app.kubernetes.io/component: storage
app.kubernetes.io/part-of: bakery-ia
type: Opaque
data:
# MinIO Root Credentials (base64 encoded)
MINIO_ROOT_USER: YWRtaW4= # admin
MINIO_ROOT_PASSWORD: c2VjdXJlLXBhc3N3b3Jk # secure-password
# Service Account Credentials for applications
MINIO_ACCESS_KEY: dHJhaW5pbmctc2VydmljZQ== # training-service
MINIO_SECRET_KEY: dHJhaW5pbmctc2VjcmV0LWtleQ== # training-secret-key
# Forecasting Service Credentials
FORECASTING_MINIO_ACCESS_KEY: Zm9yZWNhc3Rpbmctc2VydmljZQ== # forecasting-service
FORECASTING_MINIO_SECRET_KEY: Zm9yZWNhc3Rpbmctc2VjcmV0LWtleQ== # forecasting-secret-key

View File

@@ -0,0 +1,28 @@
apiVersion: v1
kind: Secret
metadata:
name: minio-tls
namespace: bakery-ia
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: minio-tls
app.kubernetes.io/part-of: bakery-ia
type: Opaque
data:
# MinIO TLS certificates (base64 encoded)
# Generated using infrastructure/tls/generate-minio-certificates.sh
# Valid for 3 years from generation date
#
# Certificate details:
# Subject: CN=minio.bakery-ia.svc.cluster.local, O=BakeryIA, OU=Storage
# Issuer: CN=BakeryIA-CA, O=BakeryIA, OU=Security
#
# To regenerate:
# 1. Run: infrastructure/tls/generate-minio-certificates.sh
# 2. Run: scripts/create-tls-secrets.sh
ca-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZ5ekNDQTdPZ0F3SUJBZ0lVUGdPcU5ZK1pvS0J5UTFNZk84bGtpR2hPbXhJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOVEV3TVRneE5ESXlNVFJhRncwek5URXcKTVRZeE5ESXlNVFJhTUhVeEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJVdwpFd1lEVlFRSERBeFRZVzVHY21GdVkybHpZMjh4RVRBUEJnTlZCQW9NQ0VKaGEyVnllVWxCTVJFd0R3WURWUVFMCkRBaFRaV04xY21sMGVURVVNQklHQTFVRUF3d0xRbUZyWlhKNVNVRXRRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUURSRDVPMmVna1lnOUhOUlI1U1UwYkxuR0hqcHYvUmFnck03ZGh1c2FXbgpyZkRGNVZwVFo0czkvOXNPRUowTnlqdW9LWGFtb3VUd1IxbncxOUZkSDhmMWVvbWNRNGVLdzJIa3hveHFSMzR0ClJEYUFHejNiV08rcmFUUTRTeU1LN1hGTW92VVVpTGwrR08yM2wxQk5QZmh6a2NEa1o5N200MzRmMVFWbzk5dGIKaFY0YklMYW9GSXFmMDlNMEUxL2ZhQitKQ1I4WWtsN0xvWGd1ejNWUi9CVW5kMHZNc1RNV3VlRC8yblZ1VVpPMAowcFVtVFVCUTJRZDc2NTdrL0hXZC8xd2NFQUw5ZFhOUmJ4aEROZkdnYzNXdFFoZ2djcFlMUWFmTGE4MXRseHljCndEZ042UGRFbFVseGdYL091b1oxeWxNWkU3eHBzTXRwbjFBd2VvZFZibTNRcDVBMXlkeWJFNjF1MXVyWXoxTHQKV05aOWVPZkFxZXdpWVFIVlpXTUM0YTRTYSsyeU02cTVQWC80ZytUYklUaDhoWkp3WFBLNUVEaWc3dkYxNEpQbApsRVJOcHdpYTNuNmEwUDcwM0hQTjZya1FPNWtWVGRpVXNmaWJNdGNVSkhMeVdXUUFSQm15ZVZma0lDYWFlWUVsCkVMa3N3YTlOVkVTS3ZRYUhLU2lIWkZoRUkwYUF2Y3BBam0xRU9oRWEraFNSaE9vRnlVT3ZHK2NNT2ZjQlNtTDAKVW1sRC9sZmFuVFQwems1YXFzcEVrWEdlQnczMXJtWi8wQVpPalYycHBSeFdXZWt6bzlCZjdnNmVMVFk0VUNDNQpNeVB0em14OVRiWHJOQW5YaGlGNkxnNWgyOFI0MkdUZTVBZDZUSGtGOVMvS2hxOHUwZFk1U0EyR1VGMUViUU84Ckt3SURBUUFCbzFNd1VUQWRCZ05WSFE0RUZnUVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3SHdZRFZSMGoKQkJnd0ZvQVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcQpoa2lHOXcwQkFRc0ZBQU9DQWdFQVF1dkZoMitIUUZ5OFZUY1VnYWxFVmlheXQxelFHdjRySVNtaXEzRzZJZVhQClhTNGd3cUhrRnpUd1p2bW9oVHdtT0N3Vy94RjRLZ3htRmJ5V05yRUpKRXFjYmVkcVVXVi8wQkNhRm1KdlVkZEkKK2V4L2lEM0ZlYnU4QUZJK0o4bEJIL0NlbkRpU0xIaGd5c2VZOHV3Um5Yc3NoWDVSbkRpckYxdUtyMUo2MzVhbgpHbHlGSU5Vcm5RbGd1RXZ0cjBlbkdVbHpUNXJXajR5MEFXVWRiWGk4dlJzaldvUThKYTBCeFRyWVloL2tPL0ZJClB0cVg3d3N4b0pNREVRNzF6aHdhN1dMUWMyZGZiMnJBcjF1QmgzcU53aVZCSU5CK3QzSkZ2NzJ4cXNXZ3VySUIKSWYyc29SVEkybk1lNWdURzFEZmQrVjI0amZhL3lJZ0FzTWpDem1HUUsyMHZvYlg0c0FWbm1QVmJaZzlTTEZaaQpNaWRrbjlPOVU2OE1FT2UzSWFzY2xkN2ZwNUprK0hyYkpVNi9zMTZFRVIvQWdEM09vajN3UmdqVENTK0FERCtqCnhvMk84Vlgya1BvMDNBTitpWWEzbkptbE1GekNyelQrOFp4U25QNUZxR2cyRUNFYnFxQTBCLzVuYVZwbWRZYVYKNDFvRkxzd2NGbTJpcUdhd2JzTE45eDN0dklDdUU5M0hZazFqNzJQelhhaVNMdHB2YW1IMWRSWUMrSFVNMUwwTwo0OUNOTVlKZUwvTmx5UXVaSm0yWDBxRE5TWG1STUw4SFU5c093V1g2cFBQSk96dXF0Z2R4Lytsa0dBZDJ3WkpVCklWYm1MNlF2emRidGEvY1NWd3NMdEJ6RzQ4YTFiNEtCYzdXTEhUd2JyZEJSVGcwVGtMWTRrdkNaZTVuTmw0RT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
minio-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdyVENDQkpXZ0F3SUJBZ0lVRytCME0ycnhucWpHZHRmbzBCaGV2S0N4MGdBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOakF4TVRjeE5EVTBORGhhRncweU9UQXgKTVRZeE5EVTBORGhhTUlHS01Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFVgpNQk1HQTFVRUJ3d01VMkZ1Um5KaGJtTnBjMk52TVJFd0R3WURWUVFLREFoQ1lXdGxjbmxKUVRFUU1BNEdBMVVFCkN3d0hVM1J2Y21GblpURXFNQ2dHQTFVRUF3d2hiV2x1YVc4dVltRnJaWEo1TFdsaExuTjJZeTVqYkhWemRHVnkKTG14dlkyRnNNSUlDSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQWc4QU1JSUNDZ0tDQWdFQW5qdTd0cFF3dkYvVgprL011UmhySllWME1KcXRyRkovTlgrMU9MSmFNaEZYL0tZMTBMUCtCNjV3L3BsWkd5SnRidFVkV2o1d1pMclpRCm1KYjNwNFR0dUs0QlQxZ3UzYlNaS0lIUU5lQWc4MUtzTUdxKzV1WE9vUFdOckFoaDRoWU9KNDVtSXNZYmEwRGQKTzJNRnY5V3VXVm4zVDZGenpNN3FMZENKelpOamVhQjdtVEpqZEhHcjg0aVQ4NkFFQStIeXd2c3FPb2paZStVagpLdThYcmp4VUdSL2VQRnZRQ3lNZFdnRmJqd2lqSi9CbjhSQ0FSSXVpRXNzalNMUVdPZ1FncklBVHZFRi9jeVVkClpLR2hhYzMvNEk3MXhEV2hYNzFYV1l3T05FbXJRNmNHelhtdmNVTVY4SHZFV016YjA1UnBPWXp5bUtyYnhOTDQKZVdOYUt2cnZjWnpjTXpwSU00UmVHS3cyTjlzQUdzM1lCVFI3V1hMS1dnbkxZYnNvSHgzZGRadXlRK0hKd0RUWApxcFh1dFloYW9DZmZIMjNuTU1GaUFLMWltZWJCSTFoVWNBaVB2cFN4N2RJM21nTlA0YWZOL29xaE1PUGc4VHhtCndNZWt2cHovN2NXYkNPTmprZDlkcTBWTExTVyt0cUlmZlZRajBMT1VQdlhyTE9tUG1jTDZsU2xSTzg4NVRWdngKSkRidDJYVVJtaHFKenBhcklmTmhGOUVscEhtYnNkc2xtWVBvLzlKV1VtcmtiSjZBYWZkbEpuckNUR3hKcGl3TAowbEpveEl3dnFZdDhEQnVjMWNORktKSVNMWkl5bzZ1WFJ1TlZvTnByeGdmVXZsOENscDNnUyttSVNGZzMzdTJrCkpjYnF6bnZ2YzN0YmxIZTB4ZzJNSE1JVlRkWmlSamNDQXdFQUFhT0NBUjB3Z2dFWk1Bc0dBMVVkRHdRRUF3SUUKTURBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUlLd1lCQlFVSEF3SXdnYW9HQTFVZEVRU0JvakNCbjRJaApiV2x1YVc4dVltRnJaWEo1TFdsaExuTjJZeTVqYkhWemRHVnlMbXh2WTJGc2dnOXRhVzVwYnk1aVlXdGxjbmt0CmFXR0NLVzFwYm1sdkxXTnZibk52YkdVdVltRnJaWEo1TFdsaExuTjJZeTVqYkhWemRHVnlMbXh2WTJGc2doZHQKYVc1cGJ5MWpiMjV6YjJ4bExtSmhhMlZ5ZVMxcFlZSUZiV2x1YVcrQ0RXMXBibWx2TFdOdmJuTnZiR1dDQ1d4dgpZMkZzYUc5emRJY0Vmd0FBQVRBZEJnTlZIUTRFRmdRVXJXMzNxOWkreE5MdVZjcGUrKzlxUE56dVF4VXdId1lEClZSMGpCQmd3Rm9BVUErNnEva2M4ZlRRVTFFRHF6R1JmS1FwcTZtMHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnSUIKQUlTT0NieFJWd2xtaWdjNldLM3hUaUJxNlJGMGNzdnV5NjJNYnI3N0h0Q3VPNHgxOTI5QjAxMXd1djdnWEhmawpPQm9qa3ZwZnFQUXlRZTk2dGFwRGJqYWZpeStlSHBPSm1lQjFNN2lQKzEzTGJJRjN3alE5SXZ1TWtnN3FQczZXCk15cnBvd1ZwK1BPeDU2SlJRK3lPcm5nakgxRG9FMW45NDBJR0lTZkRmb2g3cTljMkNvSlA2cWo3YWxid1U4RU0KYlB5d3B4WkFTNjYydUtBR0VNcFNLK2NuMXdUU3ZWSDN6NDVrMk9yUmwvQ05PZ0Fad1dyNzdQK1A3bW9FSHlmUQplR0dpclJTWWswUkJtYzdOTGd0Ry9iV0JQTEt4dHIyQmZidDFwZFZXakd4TmlwaDR4c1Z0YldpNnVOeUxYNE1qCllyK0FVUjd1MHlCVWxSc1VUL1dDbkFYdnRmNzRwcWJaNDZ3YjFnajEreU1GWHRNUldVV2NFcU1GVXRJdEsrUngKSlA4bUErbW9qdEdOcGdJZG53b1pPMTBsQkZ2U0ZKL1hGUFlsbHFKOGJpWmJ3RDZtWElzei9WQmdDRHlyQ3kybwpQeVhzR29HNDdTZkovQldvdHUwRkNaZERreCtQU0k2bkdKdyt2empSVzJ3TU9tdzJiZ0xkK3dsVDNpTXp4V3VOCkNidk0wSmpTQ2J3YVMvdE84emtrNGROeVhkWWNQbkJPNVJlM1IrQUV3T0RxV2F4T0ZXYmVUWW10bHlOTXdNT04Kd2lpR3pLWjkwaHM5QSt6M2x0QldNNmxNOFBJaFplcHB1TEZNTDRMSjZ0Ti93anJrOEVVMFBNT2ZlUTVjWXprZAp3QXdiRjVXaVhDd2JtaERCbW4xVVBrMjdPQUV0TzRSM3luaXM0eGNJbmVTQwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
minio-key.pem: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS2dJQkFBS0NBZ0VBbmp1N3RwUXd2Ri9Way9NdVJockpZVjBNSnF0ckZKL05YKzFPTEphTWhGWC9LWTEwCkxQK0I2NXcvcGxaR3lKdGJ0VWRXajV3WkxyWlFtSmIzcDRUdHVLNEJUMWd1M2JTWktJSFFOZUFnODFLc01HcSsKNXVYT29QV05yQWhoNGhZT0o0NW1Jc1liYTBEZE8yTUZ2OVd1V1ZuM1Q2Rnp6TTdxTGRDSnpaTmplYUI3bVRKagpkSEdyODRpVDg2QUVBK0h5d3ZzcU9valplK1VqS3U4WHJqeFVHUi9lUEZ2UUN5TWRXZ0ZiandpakovQm44UkNBClJJdWlFc3NqU0xRV09nUWdySUFUdkVGL2N5VWRaS0doYWMzLzRJNzF4RFdoWDcxWFdZd09ORW1yUTZjR3pYbXYKY1VNVjhIdkVXTXpiMDVScE9ZenltS3JieE5MNGVXTmFLdnJ2Y1p6Y016cElNNFJlR0t3Mk45c0FHczNZQlRSNwpXWExLV2duTFlic29IeDNkZFp1eVErSEp3RFRYcXBYdXRZaGFvQ2ZmSDIzbk1NRmlBSzFpbWViQkkxaFVjQWlQCnZwU3g3ZEkzbWdOUDRhZk4vb3FoTU9QZzhUeG13TWVrdnB6LzdjV2JDT05qa2Q5ZHEwVkxMU1crdHFJZmZWUWoKMExPVVB2WHJMT21QbWNMNmxTbFJPODg1VFZ2eEpEYnQyWFVSbWhxSnpwYXJJZk5oRjlFbHBIbWJzZHNsbVlQbwovOUpXVW1ya2JKNkFhZmRsSm5yQ1RHeEpwaXdMMGxKb3hJd3ZxWXQ4REJ1YzFjTkZLSklTTFpJeW82dVhSdU5WCm9OcHJ4Z2ZVdmw4Q2xwM2dTK21JU0ZnMzN1MmtKY2Jxem52dmMzdGJsSGUweGcyTUhNSVZUZFppUmpjQ0F3RUEKQVFLQ0FnQVhHQWE4amdKUzYvWERBeUlFejFJRzZNcW1OaXlKdFEwSGJCNFZ1ZDlHVFRyUmVMaTAvSkdjcnBCSAptWjM1RjF1YUtKQkVvM2ExYjV4eHVNN3FYeWRHNWZhQSt4RFVBTkM5cmJ5U3NHUit2dGtzczllcTRXMTM1bjdICjFlMWJUdmEvNVRPWTdhc0F5MVcrbmlRdnJHTW0zVStRQ3JOWTkvWUx1N3p4Q1FyaXJINTlqSEloZzVtaUVKUHYKWWJKVVVyellva20yZzFTaWxYMjlmV25LWHpteTlRaTliSFQvdXg5RWpLQXRUd2hwQXRoWXdaekc1RTVDU2UyYgpaZFU4b0crWVhaVUR5OWRyR2NhaGNrbVpwSndzelJDbmsyQTdGZXBTd25Nc1JIZy9obmdpc3hqZEFmcUl2N2VYCmNrYS9LWkQxK2xGSjROMzBhd29peFZKYXBZY2VwZk1hMS83dE1vZFFsOXdaOVZLWTZ6YlEwL1U0QndlMGQ0OEYKQ1graVlOZ2t4UWRmdVdwMFU2RkVlUTluR2tPMndZQUJxMCtzSDIxU2puRTQvTXh5anpLZCtjR08zUkdkTktxUwo5QTVubkh4MUwxVDN6Z0hOR2ZHS1F6Tzg5L09sVDBWVE80OEhkamxva0hmc3VTVG03N2tkZkU1TVFwamF2WktaCmo0QXoyWENGWkM2WkJxYm9wZlA1amVNWmI1WDU0aXVtclIwcHpRRGloQ3ZZWmYxTlVDa3hFdFZmaTF1eUtvLzYKMzhQK0pDcEtWSk1mYzhyYTFlWVRTV0ZaZDc1UXVMK1FtblpPVUNqQktXMnNQQTVGbERyTkVTdTQrREhCVVFtOApxdUxDUGdLaHA1TmVJRDVjcm5iVElYclVCb2tQdHpsWm10SEs5TFRYeTNPWkdXUmt5UUtDQVFFQTF0OFRhdWdCCmpMUVI2NXBTbGRXTDdVSnVGVlZUVW9DSlB5cHlOQjkvc1VsTC9Nd1RBbHlhWHoveU15Q2VCdWt3cnBMT1M0NHMKaG5kQlJOL3ZsdkRCaEovVjdYaDBEUWUvMGlqczRJdGNYQ1lpN3hFcWZOd1FQTUJEKzVyWkdKeU1iOEtLV3YwSwpBUnhES0k0YytLUkQwemQ1d1ZtelZSTjdLZlUzT3FXbGV1TjNMTFZqN3R6YU9kT2xSU0E3YWlCTS9odWQ1VFE5CkUwcEF3SDhIaGMxYW1qaUM4dEJsYUZlZ0lodXpJenhNU1hIUkJVcDNsaDMvb2UzNjM4Mm5zRUxjbE4xaFVWRGsKdDNUQVpjdHlYRkIzSEUydHpJdm9xRUpRN0Zkd3MwNUVQZXFIODFOekdjRlRNS1NieVJzNmtYYzhFQ0hPc2lYSAp6TDd5dlI3S1BmVHZhd0tDQVFFQXZJVlZRV3lpcU5ScTdTQkd3czg3WjVjZFlJOGdwSkI4bFlySklqaTRyVUVFCk14MmdVeCtYaHM5QTJSczQxZ1hsYXdvRWNqUDliZXJ2ZTYzMVZOV0M0K3Q5cFR2Vm9qcVhtcnZaNVVEN3V2Q0kKRlFPLy9JSUdqa0tFZkRwSUgvcWxEUlZlbEZTU1JjOVEvY0piZlNwS2JsYnJYZ1FtdG5KOWpsQkpFL1NMSW14UAo3OURVdGlmWmx5cFVRbDl5YzhSZzFSYmpyQWtjQVZhOVBHMXQ3cGhTanJkZHRKbXRVUmtFdGhYWTc3R3c5WHJUCjgwWlJHdkpIS0lsWlBmaHF2WlNGQzg4MVJJZ0lpRitCdWxobm16TUo0dmdYeXEwVCtRY1VGN0FBdFBRU0hyMHIKQm5wN1JlUDF5R201UDd0MjNmRU00Z0R1RENBUHQ0R1lZeUxFY2dpelpRS0NBUUVBaE9MVGJITnR1ZW9IaHpFYQowQ1dRY3p4NVBtSlZ0SmxmeUJ2bEkwMHp1SjMvQzZuZU84Q3ZqQ2JORUVlazA5dFZ5ekZwdWhxRWVPaTZDZkdBCmlGWC9LSmw5UVc4VVBwYkRVQ01WVkUxNzRsV0hsMWlEY1ZMY0MrWlFaUVBBTGROcm14YXlZRkZMNWFIbit1WGgKRHZqd0pXbVN1RHhVaDFJVUFyL3YxeXBvckJhUE5xdzcwSmJ2czRHc0haTXdpNUxNYXY4RGFLUWsvWkFYZWJWVwpIcThBMEk0UWxrREI1b1VDdVBWdWxXVU9QUUhSNWpiR3ZLVnkybCtHbnZEZU8wa3VpRFpkb0YrcUE3ZUY0YTZ2CjNGMjdQRnJpR0xXU1ByVTh2TjNiQ2xsbUpQQ3VBWk5qaE5NbU10Z3FySFpWZzI4OVN6RE5WeW04Wm1qVlVKY0IKTnM0TFh3S0NBUUVBdDRua0tBOFpDZC9NdmxJbk1qREorQit5ZFRqRG9oUWRod1lZcmgybEJ1QitzemxMeHNIQwpKM2lOL1JFNHMzNElEcjh3OXZMUThIdkRicGs5ZWJ0cGRIYm4yNysyVFB4WWIwZ21hc0ZxazJUc1IvRmZyL256CllmczJ1eStPMnJ1T2gzOWZsbkFEL0wxTGI5TVNlWGg4QUpMVkViSmU4ay9qRjNQb3dlbmFyOGZkeDNCOE4xL3kKd3U1dUhEU0szRlM3cFpwa1REQ09PR3QzVDJhR21iMW8yeE9Bd255L3RXM3pIVWVGN2s4RUp1clBnVkRiVTYyLwpRNkw4NUkxL2RsVXJkd1RrS25WNlFUTWl2UWFtei8zUHlVNmE4ekt3ZUVuQThSTGtqVWYyZ0VEUnE3d0JXbGtICkNIaU41NU9ldFpPaVpFSmRnQ2FTeHFrQWNMdi9uN29DMVFLQ0FRRUFxRkNHVDFWWG4yUGEwdFQ2ZCtvRnZYYTkKSENVMTFEbG9ad1hUOTY4cmhGOEJSazdLRVVvZXpFdjZiTUZsdUwzak9jMDNkUUs1WlF0anZUQkZKYlc3NVZMVgphcnR1U0xiVS9CVytnRGtZWmszQ241Z1B6QzlIbGRDa3MrS0lDOHJBcUNPdW9NRzc3SFlOVys3ckJLS3did2w1CmtDQW1uSmE2NWZZczdDWXpEOThmb0crVmxsc25VWCttMUxMZUtjclBEZWlpcW5kQmFTWi9NRVJnWmE2SXZid2kKMDVtNnFqL3ZXL1ZiV05iNVR4Z2N5MWpOOXpRbWJONFJ0Zmdzc3NKRmZzS3JNS0lxVnp1NkNMcEJ4eXBOUXZHYQo0S3UzVFZGcm9zaFlxWUpMVm1xVklYT1dWZk9IQTRMT2VpNmtDZTlHaTQydjdqS014M0dEK25CK1BWbVFXZz09Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==

View File

@@ -0,0 +1,33 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-init-config
namespace: bakery-ia
labels:
app.kubernetes.io/component: database
app.kubernetes.io/part-of: bakery-ia
data:
init.sql: |
-- Create required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- Create monitoring user for SigNoz metrics collection
-- This user will be created only if it doesn't already exist
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_user WHERE usename = 'monitoring') THEN
CREATE USER monitoring WITH PASSWORD 'monitoring_369f9c001f242b07ef9e2826e17169ca';
GRANT pg_monitor TO monitoring;
GRANT SELECT ON pg_stat_database TO monitoring;
RAISE NOTICE 'Created monitoring user for SigNoz metrics collection';
ELSE
-- User already exists, ensure it has the correct password and permissions
ALTER USER monitoring WITH PASSWORD 'monitoring_369f9c001f242b07ef9e2826e17169ca';
GRANT pg_monitor TO monitoring;
GRANT SELECT ON pg_stat_database TO monitoring;
RAISE NOTICE 'Updated monitoring user permissions for SigNoz metrics collection';
END IF;
END $$
;

View File

@@ -0,0 +1,60 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-logging-config
namespace: bakery-ia
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: database-logging
data:
postgresql.conf: |
# PostgreSQL Configuration for Kubernetes
# Generated for security compliance and monitoring
# Network Configuration
listen_addresses = '*'
port = 5432
# Connection Logging
log_connections = on
log_disconnections = on
log_hostname = off
# Query Logging
log_statement = 'all'
log_duration = on
log_min_duration_statement = 1000
# Log Destination
log_destination = 'stderr'
logging_collector = off
# Log Output Format
log_line_prefix = '%t [%p]: user=%u,db=%d,app=%a,client=%h '
log_timezone = 'UTC'
# Error Logging
log_error_verbosity = default
log_min_messages = warning
log_min_error_statement = error
# Checkpoints
log_checkpoints = on
# Lock Waits
log_lock_waits = on
deadlock_timeout = 1s
# Temporary Files
log_temp_files = 0
# Autovacuum Logging
log_autovacuum_min_duration = 0
# SSL/TLS Configuration
ssl = on
ssl_cert_file = '/tls/server-cert.pem'
ssl_key_file = '/tls/server-key.pem'
ssl_ca_file = '/tls/ca-cert.pem'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'

View File

@@ -0,0 +1,124 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{SERVICE_NAME}}-db
namespace: bakery-ia
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
app.kubernetes.io/part-of: bakery-ia
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
template:
metadata:
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
spec:
containers:
- name: postgres
image: postgres:17-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: bakery-config
key: {{SERVICE_NAME_UPPER}}_DB_NAME
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: database-secrets
key: {{SERVICE_NAME_UPPER}}_DB_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: database-secrets
key: {{SERVICE_NAME_UPPER}}_DB_PASSWORD
- name: POSTGRES_INITDB_ARGS
valueFrom:
configMapKeyRef:
name: bakery-config
key: POSTGRES_INITDB_ARGS
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 10
failureThreshold: 3
readinessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 5
failureThreshold: 3
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: {{SERVICE_NAME}}-db-pvc
---
apiVersion: v1
kind: Service
metadata:
name: {{SERVICE_NAME}}-db-service
namespace: bakery-ia
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
spec:
type: ClusterIP
ports:
- port: 5432
targetPort: 5432
protocol: TCP
name: postgres
selector:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{SERVICE_NAME}}-db-pvc
namespace: bakery-ia
labels:
app.kubernetes.io/name: {{SERVICE_NAME}}-db
app.kubernetes.io/component: database
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

View File

@@ -0,0 +1,25 @@
apiVersion: v1
kind: Secret
metadata:
name: postgres-tls
namespace: bakery-ia
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: database-tls
type: Opaque
data:
# PostgreSQL TLS certificates (base64 encoded)
# Generated using infrastructure/tls/generate-certificates.sh
# Valid for 3 years from generation date
#
# Certificate details:
# Subject: CN=*.bakery-ia.svc.cluster.local, O=BakeryIA, OU=Database
# Issuer: CN=BakeryIA-CA, O=BakeryIA, OU=Security
#
# To regenerate:
# 1. Run: infrastructure/tls/generate-certificates.sh
# 2. Run: scripts/create-tls-secrets.sh
ca-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZ5ekNDQTdPZ0F3SUJBZ0lVUGdPcU5ZK1pvS0J5UTFNZk84bGtpR2hPbXhJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOVEV3TVRneE5ESXlNVFJhRncwek5URXcKTVRZeE5ESXlNVFJhTUhVeEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJVdwpFd1lEVlFRSERBeFRZVzVHY21GdVkybHpZMjh4RVRBUEJnTlZCQW9NQ0VKaGEyVnllVWxCTVJFd0R3WURWUVFMCkRBaFRaV04xY21sMGVURVVNQklHQTFVRUF3d0xRbUZyWlhKNVNVRXRRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUURSRDVPMmVna1lnOUhOUlI1U1UwYkxuR0hqcHYvUmFnck03ZGh1c2FXbgpyZkRGNVZwVFo0czkvOXNPRUowTnlqdW9LWGFtb3VUd1IxbncxOUZkSDhmMWVvbWNRNGVLdzJIa3hveHFSMzR0ClJEYUFHejNiV08rcmFUUTRTeU1LN1hGTW92VVVpTGwrR08yM2wxQk5QZmh6a2NEa1o5N200MzRmMVFWbzk5dGIKaFY0YklMYW9GSXFmMDlNMEUxL2ZhQitKQ1I4WWtsN0xvWGd1ejNWUi9CVW5kMHZNc1RNV3VlRC8yblZ1VVpPMAowcFVtVFVCUTJRZDc2NTdrL0hXZC8xd2NFQUw5ZFhOUmJ4aEROZkdnYzNXdFFoZ2djcFlMUWFmTGE4MXRseHljCndEZ042UGRFbFVseGdYL091b1oxeWxNWkU3eHBzTXRwbjFBd2VvZFZibTNRcDVBMXlkeWJFNjF1MXVyWXoxTHQKV05aOWVPZkFxZXdpWVFIVlpXTUM0YTRTYSsyeU02cTVQWC80ZytUYklUaDhoWkp3WFBLNUVEaWc3dkYxNEpQbApsRVJOcHdpYTNuNmEwUDcwM0hQTjZya1FPNWtWVGRpVXNmaWJNdGNVSkhMeVdXUUFSQm15ZVZma0lDYWFlWUVsCkVMa3N3YTlOVkVTS3ZRYUhLU2lIWkZoRUkwYUF2Y3BBam0xRU9oRWEraFNSaE9vRnlVT3ZHK2NNT2ZjQlNtTDAKVW1sRC9sZmFuVFQwems1YXFzcEVrWEdlQnczMXJtWi8wQVpPalYycHBSeFdXZWt6bzlCZjdnNmVMVFk0VUNDNQpNeVB0em14OVRiWHJOQW5YaGlGNkxnNWgyOFI0MkdUZTVBZDZUSGtGOVMvS2hxOHUwZFk1U0EyR1VGMUViUU84Ckt3SURBUUFCbzFNd1VUQWRCZ05WSFE0RUZnUVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3SHdZRFZSMGoKQkJnd0ZvQVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcQpoa2lHOXcwQkFRc0ZBQU9DQWdFQVF1dkZoMitIUUZ5OFZUY1VnYWxFVmlheXQxelFHdjRySVNtaXEzRzZJZVhQClhTNGd3cUhrRnpUd1p2bW9oVHdtT0N3Vy94RjRLZ3htRmJ5V05yRUpKRXFjYmVkcVVXVi8wQkNhRm1KdlVkZEkKK2V4L2lEM0ZlYnU4QUZJK0o4bEJIL0NlbkRpU0xIaGd5c2VZOHV3Um5Yc3NoWDVSbkRpckYxdUtyMUo2MzVhbgpHbHlGSU5Vcm5RbGd1RXZ0cjBlbkdVbHpUNXJXajR5MEFXVWRiWGk4dlJzaldvUThKYTBCeFRyWVloL2tPL0ZJClB0cVg3d3N4b0pNREVRNzF6aHdhN1dMUWMyZGZiMnJBcjF1QmgzcU53aVZCSU5CK3QzSkZ2NzJ4cXNXZ3VySUIKSWYyc29SVEkybk1lNWdURzFEZmQrVjI0amZhL3lJZ0FzTWpDem1HUUsyMHZvYlg0c0FWbm1QVmJaZzlTTEZaaQpNaWRrbjlPOVU2OE1FT2UzSWFzY2xkN2ZwNUprK0hyYkpVNi9zMTZFRVIvQWdEM09vajN3UmdqVENTK0FERCtqCnhvMk84Vlgya1BvMDNBTitpWWEzbkptbE1GekNyelQrOFp4U25QNUZxR2cyRUNFYnFxQTBCLzVuYVZwbWRZYVYKNDFvRkxzd2NGbTJpcUdhd2JzTE45eDN0dklDdUU5M0hZazFqNzJQelhhaVNMdHB2YW1IMWRSWUMrSFVNMUwwTwo0OUNOTVlKZUwvTmx5UXVaSm0yWDBxRE5TWG1STUw4SFU5c093V1g2cFBQSk96dXF0Z2R4Lytsa0dBZDJ3WkpVCklWYm1MNlF2emRidGEvY1NWd3NMdEJ6RzQ4YTFiNEtCYzdXTEhUd2JyZEJSVGcwVGtMWTRrdkNaZTVuTmw0RT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
server-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUhjakNDQlZxZ0F3SUJBZ0lVRytCME0ycnhucWpHZHRmbzBCaGV2S0N4MGY0d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOVEV3TVRneE5ESXlNVFJhRncweU9ERXcKTVRjeE5ESXlNVFJhTUlHSE1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFVgpNQk1HQTFVRUJ3d01VMkZ1Um5KaGJtTnBjMk52TVJFd0R3WURWUVFLREFoQ1lXdGxjbmxKUVRFUk1BOEdBMVVFCkN3d0lSR0YwWVdKaGMyVXhKakFrQmdOVkJBTU1IU291WW1GclpYSjVMV2xoTG5OMll5NWpiSFZ6ZEdWeUxteHYKWTJGc01JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBMWIvVlNmdS9QTXZZb3JiTAoyOTVWMlpBR1JSTld1cEhIM0s5eERBUG00NVR1ZGdQV0x4bnlBOUhWejVqbUtnV0hRS1ZyU0kwNDZ1THVFWUErClJtdGg3RkVWQ0x0OWk1aWZoYVhtQWZTb3VHOTFuQzJOQ3NobUVoWHRaQkpYMG9tYU5oaUREb3R4NzhrakthTFIKQTIybVFvQ2NQdmt6RXFPRUNwaVZGVTlVSEIzQzV1bm10SFNDNDhiQitBUnlpRTJ6N1JyYUcxWUVLa2lsamlsRgptSlRTNk4zNkJxYWJGNkF4cVNwSWFub0VnRmdXQzZhSVh0QStmbzNFejFtSkVGd2Z6UUJXY0t0L09OM254M3hECmJSTnNtb3J4SHBzUGluT0E0aEhWdzdUY1U0THFxVVJZZGROb2NtYmtLaVZYSlpFRmdMZW5nQjFsbS9sQVlXcVoKUWRQYlQxVWNDZlFMdlN0NmxWaytWQjA2ZVo0WktmaS9rb2ZsRlAwZisyU0IyaFE2YWo5N0cvUmJya0NHYUlGWApDeDVkNjlBb3FTd3VFeHRYL1FtMVVLME8yeHBMdjM1S2RTY3krWjFJRk9jWXpjWHEyOGZ4bXUrVERETnlTU2NLCmxzYmp3ZnU0RUdLR0xza3RHdlRBR0gxRXlLdktrc3F4MEV4OXMvOHZBaS8yVDQrRkMxQmwyNUI1ZnpERUQ1RHAKS0h0SmF0eHdqV2lpRGxheXJrOFdnMDNSeUZTZjVuNEY3UmJwMytvRm1zU1NuRUVaK1JDT25DZ3FDWlkxTXM5cgpGVDlmejdoQXMyK1hQZXB1MHZ3RktCVXdseGlXZER6SDZzRElRQ2VTM3hTMjQzdnlpYXRFdTZLOEM3eDBlV2xzCjU5SUJRcXY1eDJUYkZ0VHdEWGdiK1NKMGsyVUNBd0VBQWFPQ0FlVXdnZ0hoTUFzR0ExVWREd1FFQXdJRU1EQWQKQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUJCUVVIQXdJd2dnRnhCZ05WSFJFRWdnRm9NSUlCWklJZApLaTVpWVd0bGNua3RhV0V1YzNaakxtTnNkWE4wWlhJdWJHOWpZV3lDQ3lvdVltRnJaWEo1TFdsaGdnOWhkWFJvCkxXUmlMWE5sY25acFkyV0NFWFJsYm1GdWRDMWtZaTF6WlhKMmFXTmxnaE4wY21GcGJtbHVaeTFrWWkxelpYSjIKYVdObGdoWm1iM0psWTJGemRHbHVaeTFrWWkxelpYSjJhV05sZ2hCellXeGxjeTFrWWkxelpYSjJhV05sZ2hObAplSFJsY201aGJDMWtZaTF6WlhKMmFXTmxnaGR1YjNScFptbGpZWFJwYjI0dFpHSXRjMlZ5ZG1salpZSVVhVzUyClpXNTBiM0o1TFdSaUxYTmxjblpwWTJXQ0VuSmxZMmx3WlhNdFpHSXRjMlZ5ZG1salpZSVVjM1Z3Y0d4cFpYSnoKTFdSaUxYTmxjblpwWTJXQ0RuQnZjeTFrWWkxelpYSjJhV05sZ2hGdmNtUmxjbk10WkdJdGMyVnlkbWxqWllJVgpjSEp2WkhWamRHbHZiaTFrWWkxelpYSjJhV05sZ2hwaGJHVnlkQzF3Y205alpYTnpiM0l0WkdJdGMyVnlkbWxqClpZSUpiRzlqWVd4b2IzTjBod1IvQUFBQk1CMEdBMVVkRGdRV0JCUitaeU1BTUNNeUN2NTBNSlRjSFN3MTNWVjkKM1RBZkJnTlZIU01FR0RBV2dCUUQ3cXIrUnp4OU5CVFVRT3JNWkY4cENtcnFiVEFOQmdrcWhraUc5dzBCQVFzRgpBQU9DQWdFQUM3V0NOM2FKdzR2VDNOcjVmV3Fqa3p4Y2wrc3BUUnlCREViSlpZcDNIZEszUU9peGhUZDBCM2JGCkZ6V1NJWDc5R3Z2cy9yajhTWkRYUDNCZHNTcG9JeFRKZitpbnpQbThoUFJvMmN1U05qTzl5aGYxdTFBQnliMmcKZVdtMkw1OGRMTElZbmdjc2wvQWFUaGlmT3VLZlZjN2tYNUY1K3BwSGxXRTRJTkdhT0tsMlpxQkxwT20rNG5YcAo3OGlCQXRmSEtWTG1NQmtJRHNZZ1g5RURVNGdZWWVyU0V1WTNUYWM5NGVhOW5FY0dwdkhEaEdSYk5SUzQ2RmwvCk8zVmoxOE9TK0tkZE1lckF1ZU5qdm9wNXZzSzBUNk1DZWxMT2hscnRvTWVOSEVjd3prQkx3anZEbzJHV2FIbU8KU3lKTndTRUFqbHlVMXJyYTBUWHRweU1nNi9jbldicjlnS2hybmYrTzBDTUdMdVYwOEZpUEN3YTYvcW1QYWlLQQppMCs2VGJ1c2JGTEdrZVdDUEszanlaRmFsU1puV1BINWRMSkV3dVNZZTlTRnhaVlpTSFNNV24weXR2NUh1Wk5qClpJbnh2YmpqNlMrYTVTZVJjNXB2ako1Vk1Ea2tRSjM0bUJsMjJub3lCaXA4Y3J1UWdBN3l6SG45c3ljYkF5VGsKWWdOWEpIbmI0UW11dHJiTTd6YnFrR1BORlhFQnl5VmFZL203WnJsRTNvRzRHUmxOc3NtS3lVZ3ZMUHhVbWdZSwpwNFg1eERoUlFsNE1WNDkvL0E1RjYrcVM2dXIrQitwOXhIb0xKZm9CUlRTVytTNlB1YmI0d1FINDl6cDNObW05Cjk0YVRoaktISzhUaU1iSkErYlEva0YyT25KWXVua3VjWWpZek52ald3ZjFTL3JlQmcyRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
server-key.pem: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRRFZ2OVZKKzc4OHk5aWkKdHN2YjNsWFprQVpGRTFhNmtjZmNyM0VNQStiamxPNTJBOVl2R2ZJRDBkWFBtT1lxQllkQXBXdElqVGpxNHU0UgpnRDVHYTJIc1VSVUl1MzJMbUorRnBlWUI5S2k0YjNXY0xZMEt5R1lTRmUxa0VsZlNpWm8yR0lNT2kzSHZ5U01wCm90RURiYVpDZ0p3KytUTVNvNFFLbUpVVlQxUWNIY0xtNmVhMGRJTGp4c0g0QkhLSVRiUHRHdG9iVmdRcVNLV08KS1VXWWxOTG8zZm9HcHBzWG9ER3BLa2hxZWdTQVdCWUxwb2hlMEQ1K2pjVFBXWWtRWEIvTkFGWndxMzg0M2VmSApmRU50RTJ5YWl2RWVtdytLYzREaUVkWER0TnhUZ3VxcFJGaDEwMmh5WnVRcUpWY2xrUVdBdDZlQUhXV2IrVUJoCmFwbEIwOXRQVlJ3SjlBdTlLM3FWV1Q1VUhUcDVuaGtwK0wrU2grVVUvUi83WklIYUZEcHFQM3NiOUZ1dVFJWm8KZ1ZjTEhsM3IwQ2lwTEM0VEcxZjlDYlZRclE3YkdrdS9ma3AxSnpMNW5VZ1U1eGpOeGVyYngvR2E3NU1NTTNKSgpKd3FXeHVQQis3Z1FZb1l1eVMwYTlNQVlmVVRJcThxU3lySFFUSDJ6L3k4Q0wvWlBqNFVMVUdYYmtIbC9NTVFQCmtPa29lMGxxM0hDTmFLSU9Wckt1VHhhRFRkSElWSi9tZmdYdEZ1bmY2Z1dheEpLY1FSbjVFSTZjS0NvSmxqVXkKejJzVlAxL1B1RUN6YjVjOTZtN1MvQVVvRlRDWEdKWjBQTWZxd01oQUo1TGZGTGJqZS9LSnEwUzdvcndMdkhSNQphV3puMGdGQ3EvbkhaTnNXMVBBTmVCdjVJblNUWlFJREFRQUJBb0lDQUFYcG5nZnVDa2xhRVg2Q3Z2Q0YzY0JuCkR2MVhLUnJWRUg4UmJVenZTTEk2a0Q2OGRzUVdjWG1GNkR1clY1RTBWa2J3QWNxS2VZSVVlcEJmczBQMXZCK0gKZmZwS3NXWXNvbkVBZUo4aU9qazJnQkxYWWJqa0lvcXFoNXdHaVRPemh3d0FXK2tKbGhlK0ZtdSs2MkxadVhQSwplZktncUdIWGNHakRTcnNYQVgvR1JQb1NpMFZVN3cveVBnaFRHeXRHWWFLVDVSSkUxcTJvRlIyY2FsRkJBSi9jCnVyU2lEdFUxb3dTeVo0Njd4dnh1aUt3KzFEUGNpbllCWVpSNHZoQUdud0huMmZ4RGlpdmVXNGNnUlZTSVBvU24KTU9udlVSdm1lN0N2M0p3TmJkdHpoTWswMjV1UUdGU3pJRDd0aWRPL1hMUndTc0VDVHlsa0xpYzVCYzgvMXllZwpKcmxyRU1hNW8va3hvRGtSWjNQMHhZd29mS3gxMWVlRXA3SmNoaHRmajRzYUNWeEw3aHlmTzVQRTFSWTV2UHVmCjlqcEVGUTNJbDBsMjRRUTU4TWthN0gzZCtSdzNjbk1MYkpTSEE3MUdSOWFqZS9WUVVPcmF5MG1XZnRkVjYrVGEKWlAvdDBrL2pqcWxxUmlxek9ZMDhrMGY4dGptamhzdHgxQ1laaVJQQVhydWlFb1N3UzRGQVV2VHdSeW8wODdJMgprZ3NYbTlGd2NFWkRVbXpsMGxURy8xYk5sSEVsdWx5cVJMd1plUXdMcEF0ZTNFdmpNQzE3TnVCbkZUOFd4bHRjCjhzVGRUczNNSEZNdnZiM3IvaXJjelkwTncvdzd3czhOWkZ1VWxXMm4xTE9iWkNrTUNIaVc2RldPRUFhSmNzbXkKMXlQbEFaMXB0cGJ3b3IxdzAvMTdBb0lCQVFEOEFJMlpvNktMOTRRMGpPYmltcm5yQlRXUW5aSFp4U240L1ZQTQpTQ2hOZ245bHR0QlJxMkYyYXZlU0xHMlRhRjRCUWRjR0tSQTV1ODZPdnp3N2VFWUpkdEsvQnBQRjZFa0hERlR2Ci9EVXBTaGEvZ2JCa3FtUmFESmZGamc5cE1QWmR2Z0VWeHlMWW1zUlliLy9FOFI3dUxlbDA0aXlwQ1UwSVNsMmMKZlVOTGZXa0NBNGk0Y21kSE1xdEd0bm9LbnNXcVYzVWsybUVRSkpZSTY2UERtcjNLVndvUk1vcVpNUDRwcjE3NQpSSG5rQTZmOWxFVzh0a1VYbnV0Vmk0MW5zOEpoRlpmblFaREtmWGR1VDQxN0dDSGVHa2tXblhpenQ1ejZNdVdtCmhMbFErUDY5UzZpVlNRUU5uS3JaWnVFdUZOVE1ublRTZ1ZPdWZuUkxWWDFjZDRFTEFvSUJBUURaSSt6aWFxenAKRktqdmxaUnlCa3A3aUYrSmpkUDc5QmRmZUswU0pWT3QrRzROVU5RT1BMVXhjdUIxeWVYd3Z2NVhWaWtkOHR4SgpGbVZMcUNNNjlhODFSbkhHNnVOTlNVMW1vRTFWQVgwd2p3ajFoaStuQUdjZWdJcGRpdHpKckJpUDhsZGtWNStyClpIaUM1L1F2SDcrUVphQXVRNnMwZmdoUEk3cXNmWFNucU5TNVcxNEFzYWJNcVBZUHhHcjRQMEJPaEVjZ2R4dFIKRjY1SFB6OXY5clFkOUxtT2JJWTMxOENrTTdtY2ZzRys2Y2tBd3RRVWdGdmVmZ3RTOG4vMGR0Rm1Ca0RUZkF4cApBU2ZENWk2Nkw1Y3g2Qm5VTzFnc2dNUHBMamtzaDVEMXFaK2d5Tldrd2xRbERSTHM2SXVCRVc0dkVuSWMxYVNsCi9BUE95MnBNMWVOUEFvSUJBQkVIeElvR2lmeWxqSlMwbFFIcGJQa2FFQVdtOEcxa0tyTCtBOFRCZDUvTld1aTMKMHhwQjE4TlY5VWMybzIwYjE0YUVPWkRjQTVHelJJRlhJUzN2c2VQLzJMdzZLSkJ1WTBrTHAwM1VvSThheDdESApoZkUzcHJLRE9WcUxnRFVlcnZlazJKUHRNa2lySk92SkhlTGtYSy9DQUkzNm53UUpjZUJHams3K0ZDY3M0WVRXClVrNE14VGdGajVlbXkxYWVaa05keDdmbTNqcG1EcEdwd3haOEJhbC8rbGt4TGphdUhlOFpQL1Rla05JOUFRUmQKR2Qxb0FBRlpweFBQNjQxL2szcFdLRDdqcW5KVXlsWjFIOTJhd3Vjc3BaWFdySXFRdFJZZmpHK1ZkcVNuUHlmeAp6Z0hRdm1waEZSYStJaWVvRnIyQlUrbkovYXJFTnYzRVdFV0FlZ01DZ2dFQVQxVVl6d0E2ZkUzWUN2Q1RjN1ZvCnNRbDZIajk3RzZwcWY2OFBUSG5td01Eck5HSTdsNWdHZXpLRlg0T01SeEVBeTlmbTNkSkZPVTY5WTQ3aWtFQUMKNjJ2NVZidXJvQ2tQNWxiYTZodkpLVnlZNFZ0TlBhNmYvanpvVUpUVFpidENuaFRrYVB5NmtWdjd5NWdEVnRRNgpvUDhBTHViNlBndHQ3YndZRDcwbVNic2RQVHRzZE1Sek5JTG1vNHdYcU9zekMzeTRuOXZrVnhSWDBDQURoVnlWCklmeXZicUdueCs5RHFycGJMaG9CbjBhNjhWUTlOK0JOc0ZSTXZ0bHFkbDZTMHJ1bUk1NUd5blpwbU9FWVlWM1IKMTZIOURkVkF1Y0d4MGhmWk83T3IrcFVtaFEvYlBuN2hUMGdmaWY3TU9UT3RGZldmUzNtaTFpSGxJa0NmYmNNWApjUUtDQVFCY25sMFRDVU1JZFhiTW5JRzEwQ29MOW15SFdsMUpqSFYrTDdJOVRRL09rdnV4dUlvSlBSYnBQVURLCmRuQkNXM05ZODZ6c2dMKytJNWIyTFdoWHpTamxBZ1pTRDVySklCenY1Lzh5ekdoNUVaSzUxOXdnL2JDYkpMREUKTFFsUTcrai9CS1VsbG1ySUtENHZva2lyOXJvbkdKblROSjlhU09kdEQ1ZDd1M1ZCZkpkRGltS1J0M3VVcHdabQpCbkxyTFlaS21SVW5aK0k3SGdyd0NPNSs4MTVXNlh1dDlQaGR6NnBwOXJUK2Z5b1VoeTFWK3VpdTJhVDFQbHJTCkhTdUFvdFdBa0lZS2I1ZWlQd1NBeXRvbWdmYnA3R2JBRTRtY1A2d0l1eFhMbkJneVpIbzBhM3FCY3drRnlXYjYKMStBR3cyMFcyaHZnY3dKNDRjTEgySUUyOGR5NAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==

View File

@@ -0,0 +1,177 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: bakery-ia
labels:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
app.kubernetes.io/part-of: bakery-ia
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
template:
metadata:
labels:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
spec:
securityContext:
fsGroup: 999 # redis group
initContainers:
- name: fix-tls-permissions
image: busybox:1.36
securityContext:
runAsUser: 0
command: ['sh', '-c']
args:
- |
cp /tls-source/* /tls/
chmod 600 /tls/redis-key.pem
chmod 644 /tls/redis-cert.pem /tls/ca-cert.pem
chown 999:999 /tls/*
ls -la /tls/
volumeMounts:
- name: tls-certs-source
mountPath: /tls-source
readOnly: true
- name: tls-certs-writable
mountPath: /tls
containers:
- name: redis
image: redis:7.4-alpine
ports:
- containerPort: 6379
name: redis-tls
- containerPort: 6380
name: redis-plain
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: redis-secrets
key: REDIS_PASSWORD
command:
- redis-server
- --appendonly
- "yes"
- --requirepass
- $(REDIS_PASSWORD)
- --maxmemory
- "512mb"
- --databases
- "16"
# TLS port for external/secure connections
- --tls-port
- "6379"
# Plain TCP port for internal cluster services (Mailu)
- --port
- "6380"
- --tls-cert-file
- /tls/redis-cert.pem
- --tls-key-file
- /tls/redis-key.pem
- --tls-ca-cert-file
- /tls/ca-cert.pem
- --tls-auth-clients
- "no"
volumeMounts:
- name: redis-data
mountPath: /data
- name: tls-certs-writable
mountPath: /tls
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
exec:
command:
- redis-cli
- --tls
- --cert
- /tls/redis-cert.pem
- --key
- /tls/redis-key.pem
- --cacert
- /tls/ca-cert.pem
- -a
- $(REDIS_PASSWORD)
- ping
initialDelaySeconds: 30
timeoutSeconds: 5
periodSeconds: 10
failureThreshold: 3
readinessProbe:
exec:
command:
- redis-cli
- --tls
- --cert
- /tls/redis-cert.pem
- --key
- /tls/redis-key.pem
- --cacert
- /tls/ca-cert.pem
- -a
- $(REDIS_PASSWORD)
- ping
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 5
failureThreshold: 3
volumes:
- name: redis-data
persistentVolumeClaim:
claimName: redis-pvc
- name: tls-certs-source
secret:
secretName: redis-tls-secret
- name: tls-certs-writable
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: bakery-ia
labels:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: 6379
protocol: TCP
name: redis-tls
- port: 6380
targetPort: 6380
protocol: TCP
name: redis-plain
selector:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-pvc
namespace: bakery-ia
labels:
app.kubernetes.io/name: redis
app.kubernetes.io/component: cache
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi

View File

@@ -0,0 +1,25 @@
apiVersion: v1
kind: Secret
metadata:
name: redis-tls-secret
namespace: bakery-ia
labels:
app.kubernetes.io/name: bakery-ia
app.kubernetes.io/component: redis-tls
type: Opaque
data:
# Redis TLS certificates (base64 encoded)
# Generated using infrastructure/tls/generate-certificates.sh
# Valid for 3 years from generation date
#
# Certificate details:
# Subject: CN=redis-service.bakery-ia.svc.cluster.local, O=BakeryIA, OU=Cache
# Issuer: CN=BakeryIA-CA, O=BakeryIA, OU=Security
#
# To regenerate:
# 1. Run: infrastructure/tls/generate-certificates.sh
# 2. Run: scripts/create-tls-secrets.sh
ca-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZ5ekNDQTdPZ0F3SUJBZ0lVUGdPcU5ZK1pvS0J5UTFNZk84bGtpR2hPbXhJd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOVEV3TVRneE5ESXlNVFJhRncwek5URXcKTVRZeE5ESXlNVFJhTUhVeEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUlEQXBEWVd4cFptOXlibWxoTVJVdwpFd1lEVlFRSERBeFRZVzVHY21GdVkybHpZMjh4RVRBUEJnTlZCQW9NQ0VKaGEyVnllVWxCTVJFd0R3WURWUVFMCkRBaFRaV04xY21sMGVURVVNQklHQTFVRUF3d0xRbUZyWlhKNVNVRXRRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUURSRDVPMmVna1lnOUhOUlI1U1UwYkxuR0hqcHYvUmFnck03ZGh1c2FXbgpyZkRGNVZwVFo0czkvOXNPRUowTnlqdW9LWGFtb3VUd1IxbncxOUZkSDhmMWVvbWNRNGVLdzJIa3hveHFSMzR0ClJEYUFHejNiV08rcmFUUTRTeU1LN1hGTW92VVVpTGwrR08yM2wxQk5QZmh6a2NEa1o5N200MzRmMVFWbzk5dGIKaFY0YklMYW9GSXFmMDlNMEUxL2ZhQitKQ1I4WWtsN0xvWGd1ejNWUi9CVW5kMHZNc1RNV3VlRC8yblZ1VVpPMAowcFVtVFVCUTJRZDc2NTdrL0hXZC8xd2NFQUw5ZFhOUmJ4aEROZkdnYzNXdFFoZ2djcFlMUWFmTGE4MXRseHljCndEZ042UGRFbFVseGdYL091b1oxeWxNWkU3eHBzTXRwbjFBd2VvZFZibTNRcDVBMXlkeWJFNjF1MXVyWXoxTHQKV05aOWVPZkFxZXdpWVFIVlpXTUM0YTRTYSsyeU02cTVQWC80ZytUYklUaDhoWkp3WFBLNUVEaWc3dkYxNEpQbApsRVJOcHdpYTNuNmEwUDcwM0hQTjZya1FPNWtWVGRpVXNmaWJNdGNVSkhMeVdXUUFSQm15ZVZma0lDYWFlWUVsCkVMa3N3YTlOVkVTS3ZRYUhLU2lIWkZoRUkwYUF2Y3BBam0xRU9oRWEraFNSaE9vRnlVT3ZHK2NNT2ZjQlNtTDAKVW1sRC9sZmFuVFQwems1YXFzcEVrWEdlQnczMXJtWi8wQVpPalYycHBSeFdXZWt6bzlCZjdnNmVMVFk0VUNDNQpNeVB0em14OVRiWHJOQW5YaGlGNkxnNWgyOFI0MkdUZTVBZDZUSGtGOVMvS2hxOHUwZFk1U0EyR1VGMUViUU84Ckt3SURBUUFCbzFNd1VUQWRCZ05WSFE0RUZnUVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3SHdZRFZSMGoKQkJnd0ZvQVVBKzZxL2tjOGZUUVUxRURxekdSZktRcHE2bTB3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcQpoa2lHOXcwQkFRc0ZBQU9DQWdFQVF1dkZoMitIUUZ5OFZUY1VnYWxFVmlheXQxelFHdjRySVNtaXEzRzZJZVhQClhTNGd3cUhrRnpUd1p2bW9oVHdtT0N3Vy94RjRLZ3htRmJ5V05yRUpKRXFjYmVkcVVXVi8wQkNhRm1KdlVkZEkKK2V4L2lEM0ZlYnU4QUZJK0o4bEJIL0NlbkRpU0xIaGd5c2VZOHV3Um5Yc3NoWDVSbkRpckYxdUtyMUo2MzVhbgpHbHlGSU5Vcm5RbGd1RXZ0cjBlbkdVbHpUNXJXajR5MEFXVWRiWGk4dlJzaldvUThKYTBCeFRyWVloL2tPL0ZJClB0cVg3d3N4b0pNREVRNzF6aHdhN1dMUWMyZGZiMnJBcjF1QmgzcU53aVZCSU5CK3QzSkZ2NzJ4cXNXZ3VySUIKSWYyc29SVEkybk1lNWdURzFEZmQrVjI0amZhL3lJZ0FzTWpDem1HUUsyMHZvYlg0c0FWbm1QVmJaZzlTTEZaaQpNaWRrbjlPOVU2OE1FT2UzSWFzY2xkN2ZwNUprK0hyYkpVNi9zMTZFRVIvQWdEM09vajN3UmdqVENTK0FERCtqCnhvMk84Vlgya1BvMDNBTitpWWEzbkptbE1GekNyelQrOFp4U25QNUZxR2cyRUNFYnFxQTBCLzVuYVZwbWRZYVYKNDFvRkxzd2NGbTJpcUdhd2JzTE45eDN0dklDdUU5M0hZazFqNzJQelhhaVNMdHB2YW1IMWRSWUMrSFVNMUwwTwo0OUNOTVlKZUwvTmx5UXVaSm0yWDBxRE5TWG1STUw4SFU5c093V1g2cFBQSk96dXF0Z2R4Lytsa0dBZDJ3WkpVCklWYm1MNlF2emRidGEvY1NWd3NMdEJ6RzQ4YTFiNEtCYzdXTEhUd2JyZEJSVGcwVGtMWTRrdkNaZTVuTmw0RT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
redis-cert.pem: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdjekNDQkZ1Z0F3SUJBZ0lVRytCME0ycnhucWpHZHRmbzBCaGV2S0N4MGY4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNWVk14RXpBUkJnTlZCQWdNQ2tOaGJHbG1iM0p1YVdFeEZUQVRCZ05WQkFjTQpERk5oYmtaeVlXNWphWE5qYnpFUk1BOEdBMVVFQ2d3SVFtRnJaWEo1U1VFeEVUQVBCZ05WQkFzTUNGTmxZM1Z5CmFYUjVNUlF3RWdZRFZRUUREQXRDWVd0bGNubEpRUzFEUVRBZUZ3MHlOVEV3TVRneE5ESXlNVFJhRncweU9ERXcKTVRjeE5ESXlNVFJhTUlHUU1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDQXdLUTJGc2FXWnZjbTVwWVRFVgpNQk1HQTFVRUJ3d01VMkZ1Um5KaGJtTnBjMk52TVJFd0R3WURWUVFLREFoQ1lXdGxjbmxKUVRFT01Bd0dBMVVFCkN3d0ZRMkZqYUdVeE1qQXdCZ05WQkFNTUtYSmxaR2x6TFhObGNuWnBZMlV1WW1GclpYSjVMV2xoTG5OMll5NWoKYkhWemRHVnlMbXh2WTJGc01JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBdnNhMgo1MUdFR0VuaW81NHUxdGtNeFNCTGQ4Mm9ML3VsYWIxYXdxREJqcUJkVUFpZzJsMWpScFFyNUxHNVh3UzVoNzM5ClkrdnlQbFpWZW16dVRiNmszbjhPckxNcnUvUFBSRytpUWc3cXlUR1orYmF3YWY2YVhFZUNLOEExWW5xSy9ONEsKQTFIUkxXRXNXRzBKQ2VZakZPZnFzempWTEtydFJhSDd6S2lBREZxREJCbXhScWsvUDJvSjZmK1hXaWpwNE5KdQpPaVdoQmNoYmpjRi9mTTZ2MGVsQlMvOGs1cHVpOGtFdWRNZWExSVFLNXFTSll3TjZZNXRNT3BKcm1IdTFFN05vCkJRZWduakJvMWJaUkFkMWgrL2NxOHAwWWt3amE5dTJnSk5jczMxcWY4MUFtNitxNklXMExqTHFUMnlINVU1aW8KS2hTa0FuczNwcUFPNFZrSWRuM3l0Y2tkK00wQmNNcTRKQm5iYk0vZ1ZPV3I1RXorSERKOWsyckFSbzBWWFB5cQpnT1JxMnNXU2N0eVFiV0pPdExOUWVVbUN0dXZ4d0RyVVNoQWlYZGhhM3ptejdYOWJiNCtWUXA2elJaM3h2bXBnCnFFeG1Pc05zMDBMak9sMHBsalVmR0ZBR2Rmb21JSXpSWmxnVkN6TVVsWkQ0cGNQVnNhSGJuR1ovNi9ZbXhNZGUKOUxjbjRrYmlrNjVmZEFJbnhmVFAySU1NZER3TUZkYkZpcy9SbDIwZWo3QUJ0YTNLdVhvZFluMXkwbitYTFIyTAo3YWJUcW9xSXRnUW1BY2lITlBVYWNnREMvbFBRSk95ckRaVTloQ3NMdDJJVVZKTUN6U2QzR3JDQzA4d2dSb2U1CjZRNUh0NEUyWG5kV3NlWWZxVnRRM2c4WktDaVUrUU1JQmt4SzdHOENBd0VBQWFPQjNqQ0IyekFMQmdOVkhROEUKQkFNQ0JEQXdIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHQ0NzR0FRVUZCd01DTUcwR0ExVWRFUVJtTUdTQwpLWEpsWkdsekxYTmxjblpwWTJVdVltRnJaWEo1TFdsaExuTjJZeTVqYkhWemRHVnlMbXh2WTJGc2doZHlaV1JwCmN5MXpaWEoyYVdObExtSmhhMlZ5ZVMxcFlZSU5jbVZrYVhNdGMyVnlkbWxqWllJSmJHOWpZV3hvYjNOMGh3Ui8KQUFBQk1CMEdBMVVkRGdRV0JCU2RJV1V6Q2gvNE9SZmJLR2JYTVJ2eXhXTFdyekFmQmdOVkhTTUVHREFXZ0JRRAo3cXIrUnp4OU5CVFVRT3JNWkY4cENtcnFiVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBZ0VBaEd2cFBSSlpqQkZpCnBaNDNVaFVGTGFIeCtRMHZncy96eXlxVzVqSys3ZWZwY3Z0Sk9CbXVrRUtMaXUwWGFrZit5VDhWRlp4R2tzZkYKcVZyL1Vvb2x3bTVEamlHOE9FT29PYTJCZTlqb0dTdmI3c0JzZ24wYS9pdElGUnpEUXdadGJQZmdpMGFndkJmTQpxczFCNm9IempBMkdSNmlMUDFXYzg4VXRNWFJwV1c0VnZSclZIallzWHVuM2ZHdGYxR1J3ZndBWFFJNys5YldpClNPQ2hEOWVJNk1xdUNYQmRCQVgvQ3FueGs4aHVia3dXY3NIeVNGQkRMcVFoUHM1dU04bGkzK01QZ3BMWENmYVkKWDYvWnpIM05nSjNEK1BJSDU5WllwaEczenZsRnBHRDRvRzNRMkFvbHhxd01SMytQNmM5SWYxRGZNTW9TZ1YzKwptZnZnUmpONXRuZ0IrL29CaXVtYk00K0VGOGFNUmsxR095V3BmM2VSZkc1NStPVEpsTHNEWE9TQlcrSzFOQ3o0CnlOWVR5c2h3eGpWU1BYcWZhdGVBWnpDNVNqRk1SZHJkSEQxME0wZ2w1L2RYY3AreDVocFFTWTNNK2dNMndXZEkKem83SkJPdDlRMUZRRGdUM2pJVldRNVB0TmhkOW9UOVdkYzBFZEppenlObDN2aTltMi9iSktWcEhPMnltZG5IWQpoUG12UVlWdGZzTWxOdmtzdkRMcFhlbUc3czR2akhmMTJZRVA4VFQ1REpnRDQ2TlZvZTM5S2E0N0lmYVRXdWdOCkZXb1YvUGFqUkl4L0lPL2tPcDROQnBlQjY5TytudVlVVU5jQ3cwZmlsQSttRmdXUWpxRkdQK2ZxV05hSmorcFAKNTByelBOc3hwK3FpdzZGVm9aNTVjY3hFMjdrbnZlWT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
redis-key.pem: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUpRUUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQ1Nzd2dna25BZ0VBQW9JQ0FRQyt4cmJuVVlRWVNlS2oKbmk3VzJRekZJRXQzemFndis2VnB2VnJDb01HT29GMVFDS0RhWFdOR2xDdmtzYmxmQkxtSHZmMWo2L0krVmxWNgpiTzVOdnFUZWZ3NnNzeXU3ODg5RWI2SkNEdXJKTVpuNXRyQnAvcHBjUjRJcndEVmllb3I4M2dvRFVkRXRZU3hZCmJRa0o1aU1VNStxek9OVXNxdTFGb2Z2TXFJQU1Xb01FR2JGR3FUOC9hZ25wLzVkYUtPbmcwbTQ2SmFFRnlGdU4Kd1g5OHpxL1I2VUZML3lUbW02THlRUzUweDVyVWhBcm1wSWxqQTNwam0wdzZrbXVZZTdVVHMyZ0ZCNkNlTUdqVgp0bEVCM1dINzl5cnluUmlUQ05yMjdhQWsxeXpmV3AvelVDYnI2cm9oYlF1TXVwUGJJZmxUbUtncUZLUUNlemVtCm9BN2hXUWgyZmZLMXlSMzR6UUZ3eXJna0dkdHN6K0JVNWF2a1RQNGNNbjJUYXNCR2pSVmMvS3FBNUdyYXhaSnkKM0pCdFlrNjBzMUI1U1lLMjYvSEFPdFJLRUNKZDJGcmZPYlB0ZjF0dmo1VkNuck5GbmZHK2FtQ29UR1k2dzJ6VApRdU02WFNtV05SOFlVQVoxK2lZZ2pORm1XQlVMTXhTVmtQaWx3OVd4b2R1Y1puL3I5aWJFeDE3MHR5ZmlSdUtUCnJsOTBBaWZGOU0vWWd3eDBQQXdWMXNXS3o5R1hiUjZQc0FHMXJjcTVlaDFpZlhMU2Y1Y3RIWXZ0cHRPcWlvaTIKQkNZQnlJYzA5UnB5QU1MK1U5QWs3S3NObFQyRUt3dTNZaFJVa3dMTkozY2FzSUxUekNCR2g3bnBEa2UzZ1RaZQpkMWF4NWgrcFcxRGVEeGtvS0pUNUF3Z0dURXJzYndJREFRQUJBb0lDQUFGdjRtMTlwTFFXSW1TVWRYVXkyZ1liCmNkWVdNTlVqc25iekc5MlVIbXZNODNHb2p2cjJISFdwK2hGVlJyaUdMWlpETFJ4MVBqUTZyRUYrMCtZTUJldm8KZUhEVDdLNit3eFNZanExV3RXMWg0cG9KOFVHVnp3M2JrQW5LVklkSVlGeFA3b2dMTkJDQkhJeThvdHZMT3YvQQorM2ljSTFHY2ZBQm1uRXlmWEUrUTJFOGpRNzJYaFhMSExBbnlNMFAvbU9ZVHBRdy92NlhEMWtTMndoZHJsZEYyCm8xZWM0Qkh6VEMxQ1VScEV3cVY2ZjlFd1NNU21nR1BZVzB1a1VndlZBQTZFN3h5bjY3Z2xWSW9xUHhQM2hKeHUKOFRPTFVXVzh6d0Z3Z0NDbTZrbnpGeVN3WkRWVXV2cmVKUlIxOTFVb1BWdU8yU2dhcUYyZHdLazYvV3hmSWxHQgpoRndkbmN1Q1UwdVV5QXp3VUh2bGlEWndWUFFxaVBMbXFYWEp3WjY5RjUzMEZlVHM4L2hUU0Y1UTAwaUFqTmhlClhRbzhJQjA0U1N2VDdMQno1OVg4Y3M0Mkh5VG80YWZ6bWhLK051OEsvQ0ZxOERMT1orRTFtYnhYRE9DM1ZWVHAKaDFFaXd1a0Z0ekpxRzVRSEJjTTlNNVlTK3EzaUw4YXY2N052M29wTm0vUG5YWkdYenFtVjRzK1FwMDdtSUhiVQpsamFCcWVzNGN4RTZZRUtkS1NOSnJ6Y09EVFNFT2hOYUJXN2RNSFRmay8zbXBpODIyNENBdEVJcmVlZy9Ua2VBCjJLWVBmTzJEd3hYZHZJd1NvajBSM0JDbkdVOWVRKzl2L2c5WVU3SXRyS2UxQjlFZTAxNjNUOC9tbnFlZy9QenEKOFNDSFA3Yk1Zb1gxaUlmbjk3MXhBb0lCQVFEZWE2YlY5blQ1dVJHL21FK2FLd0pFTHdkTzFCQTdwc2RIcnV4UApjSW5Hcjdqa3g1S21KV3gvU3c4RXdRZjR1dThEcjYxcC9QUDZLSTZoSzVtQlJhOUpWeVdVbUhTaFFDb0g5TGhPCk5mMkxtMEVOalZVZkdOb2JHMzhsbmhLd082QnNKS3JxTzc2SW5rc3hrN0htaGZ6emlBbFVtTDF5dFhFb0s2Qm4KM3BHZHNRZzEzYjlnWCt6NXZVcGlEOHI5R0U1Rm56cDhNa1BsTWhqcWsvVmp3VXNKcGluSDhMY1B3aEMyZlM5Zwpac2dYdmt6MVR5R2FZVHU5LytBazBMZzJqMU5kNFY0SmIyR0Fvc1NDRUtGQnJrZVNVMTVLK2YrOEtIdFFtMVVBCjBqaExWQWpUTkx1U3d4elB1VUpEaGF4K3kvRFpRRmJPRG1kQmtRWXFBWFpDL0pKNUFvSUJBUURibEFwTGg3c1QKcjhtbjdFcUxEU0ZyVDlQSitsQnhqL210bWd0QVE0MjhBNXVhMFVzbGJ4NGNid0pzcktlejVldkhjWGdmL1Y4cwpBaTFtNnJLcmFBOWlMaFFXSk1wRkFoOEZvRnlIK0pFN1l6N0F3elY2WXRha1h0ZVlrNVIzSlg0UmRZQ0xSeHpDCkpBY25ZMUZDSWRrRzhWcFZPSkZFVnBnWkNFMGRQTldEdHM5cTRyaUR3NXNodWVHd2RldXdoSytwenhQNmlDUmsKNEdER3hzT0hnUERkNy9vVUxzYm9EaEJCT3lOb0VyL2kvWjVQOHpzc1psR20rY2FnTTJETG1oNkxONUlVaTUzWgptNEdHTi81NEN5Zk5pMUFFUitWazlMOTNzOWNkODJuZnlEMkZ3QXNZdkZRcEFRL2c1ekROZ3NsUHZYeUR6OGo1CnNLQmRzcXdnVG53bkFvSUJBQXkxdUIzbjdIMU1ydy8wd3krN0gzRUlBdkhsT2x3K1JvcjVHdlhiSjNSY0hFT3UKaDluSXI2K0NlWVE3QjVxV0RBeDQ0SDc2L25JZ0dTNXFrR1lMdGwySmhsTThkd1d6NWZMNGNBUEFJQkgzT0R0dgpCUnMyejFmWE5XZlA1WjkrZU1kVlBSTVBnTzdMcE41YlkwSWFDLzlhbWJYazJJYVNpYm5TN0dLakhFMFhqYkdPClQxNVJmUGcwY2VpeW9GWGdLckRkelhqRllvM1pWQVVybVUwdkFYdTJyQktKMWR3bnFjN1R6bjVDd1ZKaUJJSE0KR001Nm1mQmNpOUZ1ditnV1BweFJ3WTdtZDNyalVqbGdlK2FGNy84VGxvTFFVR1hQSm1UUHk0YTFmSlFKWkV1MQphcmFUUWJVNUQrbE4zVEtOc3VDblJZNlcwaDIwRE5jZnFFTmhyWGtDZ2dFQVdIN1FxMkkzdnBaeGNwRWo5ZWpECjJFa2k5VnRDQXBMaE1OdE52NGU2WHRVaGFJTURnMEhHWS9WRmgrRUo4ZEl2ZFlGQXhidkxHS1NFQWQrRFJOdTYKbjNvc3RFUDlsVlJtaGxEOEdmelBJNTA3RkZ0WWVVdk9jQTZkVzZ2WEFUSUdIaWs2Tm1maHFrajA3U1gxQU84OQpWYlArRVN5c04xdWpEeXV1VUtOTTlqbStYTGlsWHMxOS8xaTRJZk5VbXg3TzRXUkpEQWJFakRkMktZYkFGU09kCmNBVWd4L09XVEw0bVJQUDlzQnNtWk9pTVhuS01IYmZiSHEyNkpLU3dWVDUzSXVxeG9FQW96U1FFVHNEUWVUY2QKd3BSc0dsMlRrVjJtc1NxMC95ZzBPbkdzZ2ZSRlJLSGFWWEJOSXZwcVM5bHpJd1VlWXMxaWxXZGZLb1F4SlJBYwpyd0tDQVFCemdWeFZxYTV0T0ZudzhRbWZVWU1lN0RIQ1U0cjNSUzFPTndtR29YSTFSTHp6M0k4U1JHSWJOcFYxCnlJczRnRldXd0l1WG40ekxvMCtZZExwT2prRmg1S2FrMEVya2g3QjUvWm01OWZkR013dWpBMnZpUUdZalJyek8Ka1RTQ1hQZ3JHd0s5QmxqWWZlbFM5cVd1aTl2RHVSaEFXUVpPT0NDeVB0eEVjT3ZyOXFmOUtoT2MweEVFTnRVagp6L01CSDc4NnJwckJFQVhuT0FGRkpibWZ0TFhZeTlSaEFhdTJTTURYMGc5dWRIRE1RTk9Cb1dPN2RoLzVBNXZhCkxMa3BWZ3ZvWWtjU1NjRGFKSUtzb2RQTGNManFYWGQ1MVhOV3BDOWNPWkJaUVM4RXVOMVZmR3JqT0RZOW1SOGIKakNvbUgxUDBGenlQVm1MU2JvV21qRGJzMFNGZQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==