mirror of
https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git
synced 2026-08-21 23:56:46 +00:00
Initial commit
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Environment-specific overrides
|
||||||
|
environments/local.yaml
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Helm
|
||||||
|
charts/*/charts/
|
||||||
|
charts/*/tmpcharts/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code when working with this repository.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Homelabv4 is a fully automated Kubernetes homelab deployment using **ArgoCD App-of-Apps pattern** for GitOps-based continuous delivery. It replaces the Helmfile-based Homelabv5 with declarative ArgoCD Application CRDs, sync waves for ordering, and Kubernetes Jobs for complex hooks.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Bootstrap (one-time)
|
||||||
|
```bash
|
||||||
|
# Prerequisites: ArgoCD must already be running on the cluster
|
||||||
|
# Replace <GIT_REPO_URL> in all Application CRDs with your actual repo URL
|
||||||
|
# Then:
|
||||||
|
kubectl apply -f bootstrap.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
1. `bootstrap.yaml` creates a root Application pointing to `argocd-apps/`
|
||||||
|
2. ArgoCD discovers all Application CRDs in `argocd-apps/infrastructure/` and `argocd-apps/apps/`
|
||||||
|
3. Sync waves control deployment order (lower waves first)
|
||||||
|
4. ArgoCD waits for resources to be healthy before advancing waves
|
||||||
|
5. PreSync/PostSync hook Jobs handle complex initialization
|
||||||
|
|
||||||
|
### Verify Deployment
|
||||||
|
```bash
|
||||||
|
kubectl get applications -n argocd
|
||||||
|
kubectl get pods -A | grep -v Running | grep -v Completed
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Sync Wave Scheme
|
||||||
|
| Wave | Phase | Components |
|
||||||
|
|------|-------|-----------|
|
||||||
|
| -1 | Bootstrap | Prometheus CRDs |
|
||||||
|
| 1-7 | Core Net | Cilium, Istio, cert-manager, metrics-server, envoy-gateway |
|
||||||
|
| 10-14 | Storage | Rook-Ceph, CNPG, Redis, MariaDB, Scylla operators |
|
||||||
|
| 20-23 | Security | Vault, ESO, Reloader, Authentik, Kyverno, Tetragon, CrowdSec |
|
||||||
|
| 30-31 | Net Extra | External-DNS, Netbird, Mosquitto |
|
||||||
|
| 40-43 | Monitoring | Prometheus, Grafana, Kiali, Checkov |
|
||||||
|
| 50-52 | Apps | GitLab, ArgoCD, n8n, Nextcloud, TeslaMate, HA, Frigate, etc. |
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
```
|
||||||
|
Homelabv4/
|
||||||
|
├── bootstrap.yaml # Root App-of-Apps
|
||||||
|
├── argocd-apps/ # Application CRDs
|
||||||
|
│ ├── infrastructure/ # ~35 infra Applications
|
||||||
|
│ └── apps/ # ~10 user Applications
|
||||||
|
├── infrastructure/ # Source files for infra
|
||||||
|
│ └── <service>/
|
||||||
|
│ ├── values.yaml # Helm values
|
||||||
|
│ └── manifests/ # Raw K8s manifests
|
||||||
|
├── apps/ # Source files for apps
|
||||||
|
│ └── <app>/
|
||||||
|
│ ├── values.yaml
|
||||||
|
│ └── manifests/
|
||||||
|
├── charts/ # Local Helm charts
|
||||||
|
├── hooks/ # Shared hook RBAC
|
||||||
|
├── environments/ # Environment config
|
||||||
|
└── scripts/ # Manual scripts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Patterns
|
||||||
|
|
||||||
|
#### Multi-Source Applications
|
||||||
|
Most Applications use 3 sources:
|
||||||
|
1. Remote Helm chart repo
|
||||||
|
2. Git repo ref for values files
|
||||||
|
3. Git repo path for raw manifests
|
||||||
|
|
||||||
|
#### Hook Jobs
|
||||||
|
Complex initialization (Vault init, OAuth sync) uses K8s Jobs with ArgoCD hook annotations:
|
||||||
|
- `argocd.argoproj.io/hook: PreSync` or `PostSync`
|
||||||
|
- `argocd.argoproj.io/hook-delete-policy: BeforeHookCreation`
|
||||||
|
- Jobs use `argocd-hook-sa` ServiceAccount with cluster-admin
|
||||||
|
|
||||||
|
#### Secrets Flow
|
||||||
|
Vault → External Secrets Operator → Kubernetes Secrets → Apps
|
||||||
|
|
||||||
|
## Common Operations
|
||||||
|
|
||||||
|
### Add a New Application
|
||||||
|
1. Create `apps/<name>/values.yaml` with Helm values
|
||||||
|
2. Create `apps/<name>/manifests/` with any raw manifests
|
||||||
|
3. Create `argocd-apps/apps/<name>.yaml` Application CRD
|
||||||
|
4. Commit and push — ArgoCD auto-syncs
|
||||||
|
|
||||||
|
### Update Helm Values
|
||||||
|
1. Edit `infrastructure/<service>/values.yaml` or `apps/<app>/values.yaml`
|
||||||
|
2. Commit and push — ArgoCD auto-syncs
|
||||||
|
|
||||||
|
### Force Sync
|
||||||
|
```bash
|
||||||
|
argocd app sync <app-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
- **Git repo URL**: Replace `<GIT_REPO_URL>` placeholder in all Application CRDs
|
||||||
|
- **Secrets**: Never commit secrets — use Vault + ExternalSecret
|
||||||
|
- **Domain**: All services use `*.kube.huskypup.net`
|
||||||
|
- **Storage**: Default StorageClass is `rook-ceph-block`
|
||||||
|
- **Ingress**: Istio VirtualServices + Envoy Gateway HTTPRoutes
|
||||||
|
- **mTLS**: Istio ambient mesh with STRICT PeerAuthentication
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: argocd-cm-custom-health
|
||||||
|
namespace: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-1"
|
||||||
|
data:
|
||||||
|
resource.customizations.health.ceph.rook.io_CephCluster: |
|
||||||
|
hs = {}
|
||||||
|
if obj.status ~= nil then
|
||||||
|
if obj.status.phase == "Ready" and obj.status.ceph ~= nil and obj.status.ceph.health == "HEALTH_OK" then
|
||||||
|
hs.status = "Healthy"
|
||||||
|
hs.message = "CephCluster is healthy"
|
||||||
|
elseif obj.status.phase == "Progressing" then
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = obj.status.message or "CephCluster is progressing"
|
||||||
|
else
|
||||||
|
hs.status = "Degraded"
|
||||||
|
hs.message = obj.status.message or "CephCluster is not healthy"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = "Waiting for CephCluster status"
|
||||||
|
end
|
||||||
|
return hs
|
||||||
|
resource.customizations.health.postgresql.cnpg.io_Cluster: |
|
||||||
|
hs = {}
|
||||||
|
if obj.status ~= nil then
|
||||||
|
if obj.status.phase == "Cluster in healthy state" then
|
||||||
|
hs.status = "Healthy"
|
||||||
|
hs.message = "CNPG Cluster is healthy"
|
||||||
|
elseif obj.status.phase == "Setting up primary" or obj.status.phase == "Creating primary" then
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = obj.status.phase
|
||||||
|
else
|
||||||
|
hs.status = "Degraded"
|
||||||
|
hs.message = obj.status.phase or "CNPG Cluster is not healthy"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = "Waiting for CNPG Cluster status"
|
||||||
|
end
|
||||||
|
return hs
|
||||||
|
resource.customizations.health.external-secrets.io_ClusterSecretStore: |
|
||||||
|
hs = {}
|
||||||
|
if obj.status ~= nil and obj.status.conditions ~= nil then
|
||||||
|
for i, condition in ipairs(obj.status.conditions) do
|
||||||
|
if condition.type == "Ready" then
|
||||||
|
if condition.status == "True" then
|
||||||
|
hs.status = "Healthy"
|
||||||
|
hs.message = "ClusterSecretStore is ready"
|
||||||
|
else
|
||||||
|
hs.status = "Degraded"
|
||||||
|
hs.message = condition.message or "ClusterSecretStore is not ready"
|
||||||
|
end
|
||||||
|
return hs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = "Waiting for ClusterSecretStore status"
|
||||||
|
return hs
|
||||||
|
resource.customizations.health.kiali.io_Kiali: |
|
||||||
|
hs = {}
|
||||||
|
if obj.status ~= nil then
|
||||||
|
if obj.status.conditions ~= nil then
|
||||||
|
for i, condition in ipairs(obj.status.conditions) do
|
||||||
|
if condition.type == "Successful" and condition.status == "True" then
|
||||||
|
hs.status = "Healthy"
|
||||||
|
hs.message = "Kiali is healthy"
|
||||||
|
return hs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = "Kiali is being deployed"
|
||||||
|
else
|
||||||
|
hs.status = "Progressing"
|
||||||
|
hs.message = "Waiting for Kiali status"
|
||||||
|
end
|
||||||
|
return hs
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: argocd
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- argocd.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: argocd-server
|
||||||
|
port: 80
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: argocd-oauth
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: argocd-oauth-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: client-id
|
||||||
|
remoteRef:
|
||||||
|
key: argocd-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client-secret
|
||||||
|
remoteRef:
|
||||||
|
key: argocd-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: argocd
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- argocd.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: argocd-server.argocd.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# values/argocd.values.yaml
|
||||||
|
|
||||||
|
global:
|
||||||
|
domain: argocd.kube.huskypup.net
|
||||||
|
|
||||||
|
configs:
|
||||||
|
cm:
|
||||||
|
url: https://argocd.kube.huskypup.net
|
||||||
|
oidc.config: |
|
||||||
|
name: Authentik
|
||||||
|
issuer: https://auth.kube.huskypup.net/application/o/argocd/
|
||||||
|
clientID: $oidc.authentik.clientId
|
||||||
|
clientSecret: $oidc.authentik.clientSecret
|
||||||
|
requestedScopes:
|
||||||
|
- openid
|
||||||
|
- profile
|
||||||
|
- email
|
||||||
|
- groups
|
||||||
|
|
||||||
|
rbac:
|
||||||
|
policy.default: role:readonly
|
||||||
|
policy.csv: |
|
||||||
|
g, Authentik Admins, role:admin
|
||||||
|
g, ArgoCD Admins, role:admin
|
||||||
|
|
||||||
|
server:
|
||||||
|
extraArgs:
|
||||||
|
- --insecure # TLS is terminated at Istio gateway
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
- name: oidc.authentik.clientId
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: argocd-oauth-secret
|
||||||
|
key: client-id
|
||||||
|
- name: oidc.authentik.clientSecret
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: argocd-oauth-secret
|
||||||
|
key: client-secret
|
||||||
|
|
||||||
|
dex:
|
||||||
|
enabled: false # using Authentik instead of built-in Dex
|
||||||
|
|
||||||
|
# Enable Prometheus metrics
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus
|
||||||
|
|
||||||
|
controller:
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus
|
||||||
|
|
||||||
|
repoServer:
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus
|
||||||
|
|
||||||
|
applicationSet:
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: frigate
|
||||||
|
namespace: frigate
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- frigate.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: frigate
|
||||||
|
port: 5000
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: frigate
|
||||||
|
namespace: frigate
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- frigate.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
# Authentik forward-auth endpoints must be reachable on the protected host
|
||||||
|
- match:
|
||||||
|
- uri:
|
||||||
|
prefix: /outpost.goauthentik.io
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: authentik-server.authentik.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: frigate.frigate.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 5000
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: frigate-config
|
||||||
|
namespace: frigate
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: frigate
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: rook-ceph-block
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 500Mi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: frigate-media
|
||||||
|
namespace: frigate
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: frigate
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: rook-ceph-block
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 500Gi
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: frigate-rtsp-credentials
|
||||||
|
namespace: frigate
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# Update these with your actual camera credentials
|
||||||
|
# Then update apps/frigate/values.yaml with your camera RTSP URLs
|
||||||
|
FRIGATE_RTSP_USERNAME: your_camera_username
|
||||||
|
FRIGATE_RTSP_PASSWORD: your_camera_password
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
# Frigate Helm Chart Values
|
||||||
|
# NVR with realtime object detection for IP cameras
|
||||||
|
#
|
||||||
|
# FEATURES:
|
||||||
|
# ✓ Object detection for IP cameras
|
||||||
|
# ✓ Persistent storage for recordings via Rook-Ceph
|
||||||
|
# ✓ TLS certificates via cert-manager
|
||||||
|
# ✓ Ingress via Istio VirtualService
|
||||||
|
# ✓ MQTT integration (optional)
|
||||||
|
|
||||||
|
# Reduce Istio sidecar CPU request - frigate already uses 1 CPU request
|
||||||
|
# and the cluster runs at ~98% CPU allocation. Default 10m sidecar request
|
||||||
|
# can prevent scheduling.
|
||||||
|
podAnnotations:
|
||||||
|
sidecar.istio.io/proxyCPU: "1m"
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/blakeblackshear/frigate
|
||||||
|
tag: "0.13.2"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 5000
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualService handles routing
|
||||||
|
ingress:
|
||||||
|
main:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
env:
|
||||||
|
TZ: America/New_York
|
||||||
|
FRIGATE_MQTT_HOST: "mosquitto.mqtt"
|
||||||
|
FRIGATE_MQTT_PORT: "1883"
|
||||||
|
|
||||||
|
envFromSecrets:
|
||||||
|
- frigate-rtsp-credentials
|
||||||
|
|
||||||
|
config: |
|
||||||
|
mqtt:
|
||||||
|
host: mosquitto.mqtt
|
||||||
|
port: 1883
|
||||||
|
topic_prefix: frigate
|
||||||
|
client_id: frigate
|
||||||
|
detectors:
|
||||||
|
cpu1:
|
||||||
|
type: cpu
|
||||||
|
cameras:
|
||||||
|
basement:
|
||||||
|
ffmpeg:
|
||||||
|
inputs:
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.10:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
roles:
|
||||||
|
- detect
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.10:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
roles:
|
||||||
|
- record
|
||||||
|
detect:
|
||||||
|
width: 704
|
||||||
|
height: 480
|
||||||
|
fps: 5
|
||||||
|
record:
|
||||||
|
enabled: true
|
||||||
|
retain:
|
||||||
|
days: 5
|
||||||
|
mode: all
|
||||||
|
snapshots:
|
||||||
|
enabled: true
|
||||||
|
timestamp: true
|
||||||
|
bounding_box: true
|
||||||
|
patio:
|
||||||
|
ffmpeg:
|
||||||
|
inputs:
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.11:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
roles:
|
||||||
|
- detect
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.11:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
roles:
|
||||||
|
- record
|
||||||
|
detect:
|
||||||
|
width: 704
|
||||||
|
height: 480
|
||||||
|
fps: 5
|
||||||
|
record:
|
||||||
|
enabled: true
|
||||||
|
retain:
|
||||||
|
days: 5
|
||||||
|
mode: all
|
||||||
|
snapshots:
|
||||||
|
enabled: true
|
||||||
|
timestamp: true
|
||||||
|
bounding_box: true
|
||||||
|
backyard:
|
||||||
|
ffmpeg:
|
||||||
|
inputs:
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.12:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
roles:
|
||||||
|
- detect
|
||||||
|
- path: rtsp://admin:admin!@172.28.200.12:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
roles:
|
||||||
|
- record
|
||||||
|
detect:
|
||||||
|
width: 704
|
||||||
|
height: 480
|
||||||
|
fps: 5
|
||||||
|
record:
|
||||||
|
enabled: true
|
||||||
|
retain:
|
||||||
|
days: 5
|
||||||
|
mode: all
|
||||||
|
snapshots:
|
||||||
|
enabled: true
|
||||||
|
timestamp: true
|
||||||
|
bounding_box: true
|
||||||
|
go2rtc:
|
||||||
|
streams:
|
||||||
|
basement: rtsp://admin:admin!@172.28.200.10:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
basement_alt: rtsp://admin:admin!@172.28.200.10:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
patio: rtsp://admin:admin!@172.28.200.11:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
patio_alt: rtsp://admin:admin!@172.28.200.11:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
backyard: rtsp://admin:admin!@172.28.200.12:554/cam/realmonitor?channel=1&subtype=0
|
||||||
|
backyard_alt: rtsp://admin:admin!@172.28.200.12:554/cam/realmonitor?channel=1&subtype=1
|
||||||
|
objects:
|
||||||
|
track:
|
||||||
|
- person
|
||||||
|
- car
|
||||||
|
- dog
|
||||||
|
- cat
|
||||||
|
- vehicle
|
||||||
|
motion:
|
||||||
|
threshold: 25
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 500Mi
|
||||||
|
media:
|
||||||
|
enabled: true
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 500Gi
|
||||||
|
|
||||||
|
shmSize: 2Gi
|
||||||
|
|
||||||
|
tmpfs:
|
||||||
|
enabled: true
|
||||||
|
sizeLimit: 2Gi
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
privileged: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 1Gi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 4Gi
|
||||||
|
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
enabled: true
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
failureThreshold: 5
|
||||||
|
readiness:
|
||||||
|
enabled: true
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
failureThreshold: 5
|
||||||
|
startup:
|
||||||
|
enabled: true
|
||||||
|
failureThreshold: 5
|
||||||
|
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/arch: amd64
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-gitlab
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 3 # 3 instances for production HA
|
||||||
|
|
||||||
|
# Database resources (homelab-friendly requests, burstable CPU)
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "4Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 50Gi # Increased for production
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: gitlabhq_production
|
||||||
|
owner: app
|
||||||
|
postInitSQL:
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS btree_gist;
|
||||||
|
|
||||||
|
# PostgreSQL configuration tuning for GitLab
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
max_connections: "400"
|
||||||
|
shared_buffers: "1GB"
|
||||||
|
effective_cache_size: "3GB"
|
||||||
|
maintenance_work_mem: "256MB"
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: "16MB"
|
||||||
|
default_statistics_target: "100"
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
work_mem: "16MB"
|
||||||
|
min_wal_size: "1GB"
|
||||||
|
max_wal_size: "4GB"
|
||||||
|
max_worker_processes: "4"
|
||||||
|
max_parallel_workers_per_gather: "2"
|
||||||
|
max_parallel_workers: "4"
|
||||||
|
|
||||||
|
# Backup configuration to MinIO
|
||||||
|
backup:
|
||||||
|
barmanObjectStore:
|
||||||
|
destinationPath: s3://gitlab-backups/pg-gitlab
|
||||||
|
endpointURL: http://gitlab-minio-svc.gitlab.svc.cluster.local:9000
|
||||||
|
s3Credentials:
|
||||||
|
accessKeyId:
|
||||||
|
name: gitlab-minio-secret
|
||||||
|
key: accesskey
|
||||||
|
secretAccessKey:
|
||||||
|
name: gitlab-minio-secret
|
||||||
|
key: secretkey
|
||||||
|
wal:
|
||||||
|
compression: gzip
|
||||||
|
maxParallel: 2
|
||||||
|
retentionPolicy: "30d"
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitlab-web
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- gitlab.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitlab-webservice-default
|
||||||
|
port: 8181
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitlab-registry
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- registry.gitlab.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitlab-registry
|
||||||
|
port: 5000
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitlab-minio
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- minio.gitlab.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitlab-minio-svc
|
||||||
|
port: 9000
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitlab-kas
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- kas.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitlab-kas
|
||||||
|
port: 8154
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: gitlab-saml
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: gitlab-saml-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
template:
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
GITLAB_SAML_IDP_SSO_URL: "{{ .idp_sso_url }}"
|
||||||
|
GITLAB_SAML_IDP_FINGERPRINT: "{{ .idp_fingerprint }}"
|
||||||
|
data:
|
||||||
|
- secretKey: idp_sso_url
|
||||||
|
remoteRef:
|
||||||
|
key: gitlab/saml
|
||||||
|
property: idp_sso_url
|
||||||
|
- secretKey: idp_fingerprint
|
||||||
|
remoteRef:
|
||||||
|
key: gitlab/saml
|
||||||
|
property: idp_fingerprint
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# GitLab Unified TLS Certificate
|
||||||
|
# Covers all GitLab domains in a single certificate
|
||||||
|
# This prevents issues with GitLab chart creating separate certificates
|
||||||
|
# that may have incorrect domain names
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: gitlab-unified-tls
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
secretName: gitlab-tls
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-production
|
||||||
|
kind: ClusterIssuer
|
||||||
|
dnsNames:
|
||||||
|
- gitlab.kube.huskypup.net
|
||||||
|
- registry.gitlab.kube.huskypup.net
|
||||||
|
- minio.gitlab.kube.huskypup.net
|
||||||
|
- kas.kube.huskypup.net
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: gitlab
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- gitlab.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: gitlab-webservice-default.gitlab.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8181
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: gitlab-registry
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- registry.gitlab.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: gitlab-registry.gitlab.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 5000
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: gitlab-minio
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- minio.gitlab.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: gitlab-minio-svc.gitlab.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 9000
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: gitlab-kas
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- kas.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: gitlab-kas.gitlab.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8154
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
---
|
||||||
|
# ServiceAccount for the CronJob that monitors PostgreSQL secret changes
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: pg-restart-sa
|
||||||
|
namespace: gitlab
|
||||||
|
---
|
||||||
|
# Role to allow patching Deployments, StatefulSets, Clusters and reading Secrets
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: pg-restart-role
|
||||||
|
namespace: gitlab
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments", "statefulsets"]
|
||||||
|
verbs: ["get", "patch"]
|
||||||
|
- apiGroups: ["postgresql.cnpg.io"]
|
||||||
|
resources: ["clusters"]
|
||||||
|
verbs: ["get", "patch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments/status", "statefulsets/status"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: ["postgresql.cnpg.io"]
|
||||||
|
resources: ["clusters/status"]
|
||||||
|
verbs: ["get"]
|
||||||
|
---
|
||||||
|
# RoleBinding to grant permissions to the ServiceAccount
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pg-restart-binding
|
||||||
|
namespace: gitlab
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: pg-restart-role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pg-restart-sa
|
||||||
|
namespace: gitlab
|
||||||
|
---
|
||||||
|
# CronJob to monitor pg-gitlab-app secret and trigger restarts on changes
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: pg-gitlab-secret-monitor
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
# Run every 30 minutes to check for secret changes (rotations happen at most daily)
|
||||||
|
schedule: "*/30 * * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pg-gitlab-secret-monitor
|
||||||
|
spec:
|
||||||
|
serviceAccountName: pg-restart-sa
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: monitor
|
||||||
|
image: docker.io/alpine/k8s:1.32.13
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get current secret version
|
||||||
|
SECRET_VERSION=$(kubectl get secret -n gitlab pg-gitlab-app -o jsonpath='{.metadata.resourceVersion}')
|
||||||
|
|
||||||
|
# Get last known secret version from pgbouncer deployment annotation
|
||||||
|
LAST_VERSION=$(kubectl get deployment -n gitlab pgbouncer-gitlab -o jsonpath='{.spec.template.metadata.annotations.secret-version/pg-password}' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
echo "Current secret version: $SECRET_VERSION"
|
||||||
|
echo "Last known version: $LAST_VERSION"
|
||||||
|
|
||||||
|
# If versions differ, update database password and restart resources
|
||||||
|
if [ "$SECRET_VERSION" != "$LAST_VERSION" ]; then
|
||||||
|
echo "Secret has changed! Updating database password and resources..."
|
||||||
|
|
||||||
|
# Get the new password from the secret
|
||||||
|
NEW_PASSWORD=$(kubectl get secret -n gitlab pg-gitlab-app -o jsonpath='{.data.password}' | base64 -d)
|
||||||
|
|
||||||
|
# Update the database user password
|
||||||
|
# Try both pg-gitlab-1 and pg-gitlab-2 in case one is restarting
|
||||||
|
kubectl exec -n gitlab pg-gitlab-1 -c postgres -- psql -U postgres -d gitlabhq_production -c "ALTER USER app PASSWORD '$NEW_PASSWORD';" 2>/dev/null || \
|
||||||
|
kubectl exec -n gitlab pg-gitlab-2 -c postgres -- psql -U postgres -d gitlabhq_production -c "ALTER USER app PASSWORD '$NEW_PASSWORD';" 2>/dev/null || \
|
||||||
|
echo "Database password update failed"
|
||||||
|
|
||||||
|
# Update password table with new hash for PgBouncer SCRAM auth
|
||||||
|
kubectl exec -n gitlab pg-gitlab-1 -c postgres -- psql -U postgres -d gitlabhq_production -c "INSERT INTO public.user_passwords (usename, passwd) SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'app' ON CONFLICT (usename) DO UPDATE SET passwd = EXCLUDED.passwd;" 2>/dev/null || \
|
||||||
|
kubectl exec -n gitlab pg-gitlab-2 -c postgres -- psql -U postgres -d gitlabhq_production -c "INSERT INTO public.user_passwords (usename, passwd) SELECT rolname, rolpassword FROM pg_authid WHERE rolname = 'app' ON CONFLICT (usename) DO UPDATE SET passwd = EXCLUDED.passwd;" 2>/dev/null || \
|
||||||
|
echo "Password table update failed, PgBouncer may need manual restart"
|
||||||
|
|
||||||
|
# Patch pgbouncer deployments to trigger restart
|
||||||
|
kubectl patch deployment -n gitlab pgbouncer-gitlab -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"secret-version/pg-password\":\"$SECRET_VERSION\",\"restarted-at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}}}}" 2>/dev/null || echo "Deployment patch failed"
|
||||||
|
|
||||||
|
echo "Database password updated and resources will restart."
|
||||||
|
else
|
||||||
|
echo "Secret has not changed. No restart needed."
|
||||||
|
fi
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
---
|
||||||
|
# CronJob to monitor pg-praefect-app secret and trigger restarts on changes
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: pg-praefect-secret-monitor
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
# Run every 30 minutes to check for secret changes (rotations happen at most daily)
|
||||||
|
schedule: "*/30 * * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pg-praefect-secret-monitor
|
||||||
|
spec:
|
||||||
|
serviceAccountName: pg-restart-sa
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: monitor
|
||||||
|
image: docker.io/alpine/k8s:1.32.13
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get current secret version
|
||||||
|
SECRET_VERSION=$(kubectl get secret -n gitlab pg-praefect-app -o jsonpath='{.metadata.resourceVersion}')
|
||||||
|
|
||||||
|
# Get last known secret version from gitaly statefulset annotation
|
||||||
|
LAST_VERSION=$(kubectl get statefulset -n gitlab gitlab-gitaly-default -o jsonpath='{.spec.template.metadata.annotations.secret-version/pg-password}' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
echo "Current secret version: $SECRET_VERSION"
|
||||||
|
echo "Last known version: $LAST_VERSION"
|
||||||
|
|
||||||
|
# If versions differ, update database password and restart resources
|
||||||
|
if [ "$SECRET_VERSION" != "$LAST_VERSION" ]; then
|
||||||
|
echo "Secret has changed! Updating database password and resources..."
|
||||||
|
|
||||||
|
# Get the new password from the secret
|
||||||
|
NEW_PASSWORD=$(kubectl get secret -n gitlab pg-praefect-app -o jsonpath='{.data.password}' | base64 -d)
|
||||||
|
|
||||||
|
# Update the database user password
|
||||||
|
# Try both pg-praefect-3 and pg-praefect-4
|
||||||
|
kubectl exec -n gitlab pg-praefect-3 -c postgres -- psql -U postgres -d gitlabhq_production -c "ALTER USER app PASSWORD '$NEW_PASSWORD';" 2>/dev/null || \
|
||||||
|
kubectl exec -n gitlab pg-praefect-4 -c postgres -- psql -U postgres -d gitlabhq_production -c "ALTER USER app PASSWORD '$NEW_PASSWORD';" 2>/dev/null || \
|
||||||
|
echo "Database password update failed"
|
||||||
|
|
||||||
|
# Patch gitaly and praefect statefulsets
|
||||||
|
kubectl patch statefulset -n gitlab gitlab-gitaly-default -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"secret-version/pg-password\":\"$SECRET_VERSION\",\"restarted-at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}}}}"
|
||||||
|
kubectl patch statefulset -n gitlab gitlab-praefect -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"secret-version/pg-password\":\"$SECRET_VERSION\",\"restarted-at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}}}}"
|
||||||
|
|
||||||
|
# Patch CNPG cluster
|
||||||
|
kubectl patch cluster -n gitlab pg-praefect -p "{\"metadata\":{\"annotations\":{\"secret-version/pg-password\":\"$SECRET_VERSION\",\"restarted-at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}}" --type merge
|
||||||
|
|
||||||
|
echo "Database password updated and resources will restart."
|
||||||
|
else
|
||||||
|
echo "Secret has not changed. No restart needed."
|
||||||
|
fi
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
---
|
||||||
|
# PgBouncer Pooler for GitLab PostgreSQL
|
||||||
|
# Managed by CloudNativePG Operator
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Pooler
|
||||||
|
metadata:
|
||||||
|
name: pgbouncer-gitlab
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
cluster:
|
||||||
|
name: pg-gitlab
|
||||||
|
|
||||||
|
# Number of PgBouncer instances (keep small; GitLab points directly at CNPG RW service)
|
||||||
|
instances: 1
|
||||||
|
|
||||||
|
# PgBouncer configuration
|
||||||
|
type: rw # Read-Write pooler (connects to primary)
|
||||||
|
|
||||||
|
pgbouncer:
|
||||||
|
poolMode: transaction
|
||||||
|
authQuerySecret:
|
||||||
|
name: pg-gitlab-app
|
||||||
|
# Use custom user_search function for SCRAM-SHA-256 authentication
|
||||||
|
# This function is created by gitlab-bootstrap.sh script
|
||||||
|
authQuery: "SELECT usename, passwd FROM public.user_search($1)"
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
max_client_conn: "2000"
|
||||||
|
default_pool_size: "50"
|
||||||
|
reserve_pool_size: "10"
|
||||||
|
server_idle_timeout: "600" # Keep connections alive for 10 minutes
|
||||||
|
log_connections: "1"
|
||||||
|
log_disconnections: "1"
|
||||||
|
log_pooler_errors: "1"
|
||||||
|
stats_period: "60"
|
||||||
|
|
||||||
|
# Template for PgBouncer pods
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pgbouncer-gitlab
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pgbouncer
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# Anti-affinity to spread PgBouncer pods across nodes
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: pgbouncer-gitlab
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
---
|
||||||
|
# Read-only Pooler for Database Load Balancing
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Pooler
|
||||||
|
metadata:
|
||||||
|
name: pgbouncer-gitlab-ro
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
cluster:
|
||||||
|
name: pg-gitlab
|
||||||
|
|
||||||
|
instances: 3
|
||||||
|
|
||||||
|
type: ro # Read-Only pooler (connects to replicas)
|
||||||
|
|
||||||
|
pgbouncer:
|
||||||
|
poolMode: transaction
|
||||||
|
authQuerySecret:
|
||||||
|
name: pg-gitlab-app
|
||||||
|
# Use custom user_search function for SCRAM-SHA-256 authentication
|
||||||
|
# This function is created by gitlab-bootstrap.sh script
|
||||||
|
authQuery: "SELECT usename, passwd FROM public.user_search($1)"
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
max_client_conn: "2000"
|
||||||
|
default_pool_size: "50"
|
||||||
|
reserve_pool_size: "10"
|
||||||
|
max_db_connections: "100"
|
||||||
|
server_idle_timeout: "600" # Keep connections alive for 10 minutes
|
||||||
|
log_connections: "1"
|
||||||
|
log_disconnections: "1"
|
||||||
|
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: pgbouncer-gitlab-ro
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: pgbouncer
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
affinity:
|
||||||
|
podAntiAffinity:
|
||||||
|
preferredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
- weight: 100
|
||||||
|
podAffinityTerm:
|
||||||
|
labelSelector:
|
||||||
|
matchLabels:
|
||||||
|
app: pgbouncer-gitlab-ro
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-praefect
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 2
|
||||||
|
|
||||||
|
# Resources: keep memory, keep CPU requests low for scheduling.
|
||||||
|
# CPU limits omitted so Postgres can burst when available.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: praefect_production
|
||||||
|
owner: app
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
# ServiceAccount for the CronJob that monitors Redis secret changes
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: redis-restart-sa
|
||||||
|
namespace: gitlab
|
||||||
|
---
|
||||||
|
# Role to allow patching StatefulSets and reading Secrets
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: redis-restart-role
|
||||||
|
namespace: gitlab
|
||||||
|
rules:
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["statefulsets"]
|
||||||
|
verbs: ["get", "patch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["statefulsets/status"]
|
||||||
|
verbs: ["get"]
|
||||||
|
---
|
||||||
|
# RoleBinding to grant permissions to the ServiceAccount
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: redis-restart-binding
|
||||||
|
namespace: gitlab
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: redis-restart-role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: redis-restart-sa
|
||||||
|
namespace: gitlab
|
||||||
|
---
|
||||||
|
# CronJob to monitor Redis secret and trigger StatefulSet restart on changes
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: redis-secret-monitor
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
# Run every hour to check for secret changes
|
||||||
|
# This aligns with the 24-hour secret rotation schedule
|
||||||
|
schedule: "*/60 * * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 1
|
||||||
|
failedJobsHistoryLimit: 1
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis-secret-monitor
|
||||||
|
spec:
|
||||||
|
serviceAccountName: redis-restart-sa
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: monitor
|
||||||
|
image: docker.io/alpine/k8s:1.32.13
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
command:
|
||||||
|
- /bin/bash
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Get current secret version
|
||||||
|
SECRET_VERSION=$(kubectl get secret -n gitlab redis-gitlab-secret -o jsonpath='{.metadata.resourceVersion}')
|
||||||
|
|
||||||
|
# Get last known secret version from StatefulSet annotation
|
||||||
|
LAST_VERSION=$(kubectl get statefulset -n gitlab redis-gitlab -o jsonpath='{.spec.template.metadata.annotations.secret-version/redis-password}' 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
echo "Current secret version: $SECRET_VERSION"
|
||||||
|
echo "Last known version: $LAST_VERSION"
|
||||||
|
|
||||||
|
# If versions differ, restart StatefulSet
|
||||||
|
if [ "$SECRET_VERSION" != "$LAST_VERSION" ]; then
|
||||||
|
echo "Secret has changed! Updating StatefulSet with new version annotation..."
|
||||||
|
|
||||||
|
# Patch StatefulSet with new secret version annotation
|
||||||
|
# This will trigger a rolling restart of the Redis pod
|
||||||
|
kubectl patch statefulset -n gitlab redis-gitlab -p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"secret-version/redis-password\":\"$SECRET_VERSION\",\"restarted-at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}}}}}"
|
||||||
|
|
||||||
|
echo "StatefulSet will now perform a rolling restart to pick up the new password."
|
||||||
|
else
|
||||||
|
echo "Secret has not changed. No restart needed."
|
||||||
|
fi
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# Redis standalone instance for GitLab (used instead of Sentinel for simplicity)
|
||||||
|
# Password auth is required - GitLab reads the password from redis-gitlab-secret
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: redis-gitlab-additional
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
name: redis
|
||||||
|
selector:
|
||||||
|
app: redis-gitlab-standalone
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: redis-gitlab-standalone
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
name: redis
|
||||||
|
selector:
|
||||||
|
app: redis-gitlab-standalone
|
||||||
|
type: ClusterIP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: redis-gitlab-standalone
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
serviceName: redis-gitlab-additional
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: redis-gitlab-standalone
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis-gitlab-standalone
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: redis:7.0-alpine
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsGroup: 1000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
name: redis
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- redis-server --appendonly yes --requirepass "$REDIS_PASSWORD"
|
||||||
|
env:
|
||||||
|
- name: REDIS_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: redis-gitlab-secret
|
||||||
|
key: password
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: rook-ceph-block
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
# Password generator and ESO for GitLab Redis
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
metadata:
|
||||||
|
name: gitlab-redis-password
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
length: 32
|
||||||
|
digits: 5
|
||||||
|
symbols: 0
|
||||||
|
noUpper: false
|
||||||
|
allowRepeat: true
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: gitlab-redis-password
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
refreshInterval: "0" # Generate once, never rotate (Password generator creates new value each refresh)
|
||||||
|
target:
|
||||||
|
name: redis-gitlab-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
template:
|
||||||
|
data:
|
||||||
|
password: "{{ .password }}"
|
||||||
|
dataFrom:
|
||||||
|
- sourceRef:
|
||||||
|
generatorRef:
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
name: gitlab-redis-password
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
# Job to sync GitLab admin status from Authentik groups
|
||||||
|
# Run this after users login via Authentik SSO to grant them admin access
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
namespace: gitlab
|
||||||
|
spec:
|
||||||
|
ttlSecondsAfterFinished: 3600 # Clean up after 1 hour
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
containers:
|
||||||
|
- name: sync-admin
|
||||||
|
image: docker.io/library/alpine:3.21
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
apk add --no-cache postgresql-client curl
|
||||||
|
|
||||||
|
echo "🔄 Syncing GitLab admin permissions from Authentik..."
|
||||||
|
|
||||||
|
# Get list of users in "authentik Admins" group
|
||||||
|
ADMIN_USERS=$(PGPASSWORD="$AUTHENTIK_DB_PASSWORD" psql -h pg-authentik-rw.authentik.svc.cluster.local -U app -d app -t -c "
|
||||||
|
SELECT DISTINCT u.email
|
||||||
|
FROM authentik_core_user u
|
||||||
|
JOIN authentik_core_user_groups ug ON u.id = ug.user_id
|
||||||
|
JOIN authentik_core_group g ON ug.group_id = g.group_uuid
|
||||||
|
WHERE g.name = 'authentik Admins' AND u.is_active = true;
|
||||||
|
" | xargs)
|
||||||
|
|
||||||
|
if [ -z "$ADMIN_USERS" ]; then
|
||||||
|
echo "⚠️ No users found in 'authentik Admins' group"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ Found admin users: $ADMIN_USERS"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# For each admin user, grant admin access in GitLab
|
||||||
|
for email in $ADMIN_USERS; do
|
||||||
|
echo "🔐 Checking user: $email"
|
||||||
|
|
||||||
|
# Use GitLab Rails runner to promote user
|
||||||
|
kubectl exec -n gitlab deployment/gitlab-toolbox -- \
|
||||||
|
gitlab-rails runner "
|
||||||
|
user = User.find_by(email: '$email')
|
||||||
|
if user
|
||||||
|
if user.admin?
|
||||||
|
puts ' ✓ Already admin'
|
||||||
|
else
|
||||||
|
user.update(admin: true)
|
||||||
|
puts ' ✅ Promoted to admin'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts ' ⚠️ User not found (needs to login via SSO first)'
|
||||||
|
end
|
||||||
|
" || echo " ❌ Failed to update user"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Admin sync complete"
|
||||||
|
env:
|
||||||
|
- name: AUTHENTIK_DB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-authentik-app
|
||||||
|
namespace: authentik
|
||||||
|
key: password
|
||||||
|
serviceAccountName: gitlab-sync-admin
|
||||||
|
---
|
||||||
|
# ServiceAccount for the sync job
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
namespace: gitlab
|
||||||
|
---
|
||||||
|
# Role to allow exec into toolbox pod
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
namespace: gitlab
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods", "pods/exec"]
|
||||||
|
verbs: ["get", "list", "create"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["deployments"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
---
|
||||||
|
# RoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
namespace: gitlab
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
namespace: gitlab
|
||||||
|
roleRef:
|
||||||
|
kind: Role
|
||||||
|
name: gitlab-sync-admin
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
@@ -0,0 +1,333 @@
|
|||||||
|
# values/gitlab.values.yaml
|
||||||
|
# GitLab with Authentik OIDC SSO Integration
|
||||||
|
|
||||||
|
global:
|
||||||
|
hosts:
|
||||||
|
domain: kube.huskypup.net
|
||||||
|
gitlab:
|
||||||
|
name: gitlab.kube.huskypup.net
|
||||||
|
registry:
|
||||||
|
name: registry.gitlab.kube.huskypup.net
|
||||||
|
tls:
|
||||||
|
secretName: gitlab-tls
|
||||||
|
minio:
|
||||||
|
name: minio.gitlab.kube.huskypup.net
|
||||||
|
tls:
|
||||||
|
secretName: gitlab-tls
|
||||||
|
kas:
|
||||||
|
name: kas.kube.huskypup.net
|
||||||
|
tls:
|
||||||
|
secretName: gitlab-tls
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualServices handle routing
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
configureCertmanager: false # Use cluster-wide cert-manager, not GitLab's
|
||||||
|
|
||||||
|
# Edition: Community Edition
|
||||||
|
edition: ce
|
||||||
|
|
||||||
|
# Time zone
|
||||||
|
time_zone: UTC
|
||||||
|
|
||||||
|
# Email configuration (configure as needed)
|
||||||
|
email:
|
||||||
|
from: 'gitlab@kube.huskypup.net'
|
||||||
|
display_name: GitLab
|
||||||
|
reply_to: 'noreply@kube.huskypup.net'
|
||||||
|
|
||||||
|
# External PostgreSQL configuration
|
||||||
|
# NOTE: PgBouncer service currently has no endpoints (replicas=0),
|
||||||
|
# so GitLab is pointed directly at the CNPG primary service.
|
||||||
|
psql:
|
||||||
|
host: pg-gitlab-rw.gitlab.svc.cluster.local
|
||||||
|
port: 5432
|
||||||
|
database: gitlabhq_production
|
||||||
|
username: app
|
||||||
|
password:
|
||||||
|
secret: pg-gitlab-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
# Gitaly configuration - using Praefect for HA
|
||||||
|
gitaly:
|
||||||
|
enabled: true # Enabled to deploy Gitaly pods
|
||||||
|
internal:
|
||||||
|
names: [] # No internal Gitaly, using Praefect
|
||||||
|
external: [] # Praefect configured below
|
||||||
|
|
||||||
|
# Praefect configuration
|
||||||
|
praefect:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Use CNPG database secret
|
||||||
|
dbSecret:
|
||||||
|
secret: pg-praefect-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
virtualStorages:
|
||||||
|
- name: default
|
||||||
|
gitalyReplicas: 3 # Production HA
|
||||||
|
maxUnavailable: 1
|
||||||
|
|
||||||
|
# Praefect PostgreSQL configuration
|
||||||
|
psql:
|
||||||
|
host: pg-praefect-rw.gitlab.svc.cluster.local
|
||||||
|
port: 5432
|
||||||
|
dbName: praefect_production
|
||||||
|
user: app
|
||||||
|
|
||||||
|
# External Redis configuration - using standalone Redis for writes
|
||||||
|
# (replicated Redis service causes READONLY errors from replicas)
|
||||||
|
redis:
|
||||||
|
host: redis-gitlab-standalone.gitlab.svc.cluster.local
|
||||||
|
port: 6379
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
secret: redis-gitlab-secret
|
||||||
|
key: password
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
appConfig:
|
||||||
|
# OmniAuth SSO Configuration
|
||||||
|
omniauth:
|
||||||
|
enabled: true
|
||||||
|
allowSingleSignOn: ['openid_connect']
|
||||||
|
blockAutoCreatedUsers: false
|
||||||
|
autoLinkUser: ['openid_connect']
|
||||||
|
syncProfileFromProvider: ['openid_connect']
|
||||||
|
syncProfileAttributes: ['email', 'name']
|
||||||
|
providers:
|
||||||
|
- secret: gitlab-oidc-secret
|
||||||
|
key: provider
|
||||||
|
|
||||||
|
# Settings for Let's Encrypt ACME Issuer - disabled, using cluster-wide cert-manager
|
||||||
|
certmanager-issuer:
|
||||||
|
email: admin@kube.huskypup.net
|
||||||
|
|
||||||
|
# Authentik OIDC Configuration via Rails omnibus config
|
||||||
|
# Note: Credentials are loaded from gitlab-oidc-secret via environment variables
|
||||||
|
|
||||||
|
# SAML Configuration via Rails omnibus config
|
||||||
|
# Note: SAML provider configuration is loaded from gitlab-saml-secret
|
||||||
|
|
||||||
|
# PostgreSQL (external via CloudNativePG)
|
||||||
|
postgresql:
|
||||||
|
install: false
|
||||||
|
|
||||||
|
# Redis (external)
|
||||||
|
redis:
|
||||||
|
install: false
|
||||||
|
|
||||||
|
# PgBouncer connection pooler
|
||||||
|
# NOTE: PgBouncer is deployed via CNPG Pooler CRD (see pgbouncer-pooler.yaml)
|
||||||
|
# This setting disables GitLab's bundled PgBouncer chart
|
||||||
|
pgbouncer:
|
||||||
|
enabled: false # Using external CNPG Pooler instead
|
||||||
|
|
||||||
|
# MinIO for object storage
|
||||||
|
minio:
|
||||||
|
persistence:
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
size: 100Gi # Production storage
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# Container Registry - enabled with S3 storage
|
||||||
|
registry:
|
||||||
|
enabled: true
|
||||||
|
hpa:
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 2
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
# GitLab components
|
||||||
|
gitlab:
|
||||||
|
# GitLab Webservice - Main application
|
||||||
|
webservice:
|
||||||
|
minReplicas: 1 # Homelab sizing
|
||||||
|
maxReplicas: 3
|
||||||
|
|
||||||
|
# Note: hostAliases for OIDC SSL validation are applied via helmfile postsync hook
|
||||||
|
# (GitLab chart doesn't support hostAliases in values.yaml)
|
||||||
|
|
||||||
|
extraEnvFrom:
|
||||||
|
GITLAB_OIDC_CLIENT_ID:
|
||||||
|
secretKeyRef:
|
||||||
|
name: gitlab-oidc-secret
|
||||||
|
key: GITLAB_OIDC_CLIENT_ID
|
||||||
|
GITLAB_OIDC_CLIENT_SECRET:
|
||||||
|
secretKeyRef:
|
||||||
|
name: gitlab-oidc-secret
|
||||||
|
key: GITLAB_OIDC_CLIENT_SECRET
|
||||||
|
GITLAB_SAML_IDP_FINGERPRINT:
|
||||||
|
secretKeyRef:
|
||||||
|
name: gitlab-saml-secret
|
||||||
|
key: GITLAB_SAML_IDP_FINGERPRINT
|
||||||
|
GITLAB_SAML_IDP_SSO_URL:
|
||||||
|
secretKeyRef:
|
||||||
|
name: gitlab-saml-secret
|
||||||
|
key: GITLAB_SAML_IDP_SSO_URL
|
||||||
|
extraEnv:
|
||||||
|
GITLAB_OMNIBUS_CONFIG: |
|
||||||
|
# Authentik OIDC Configuration
|
||||||
|
gitlab_rails['omniauth_enabled'] = true
|
||||||
|
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect', 'saml']
|
||||||
|
gitlab_rails['omniauth_block_auto_created_users'] = false
|
||||||
|
gitlab_rails['omniauth_auto_link_user'] = ['openid_connect', 'saml']
|
||||||
|
gitlab_rails['omniauth_auto_sign_in_with_provider'] = nil
|
||||||
|
gitlab_rails['omniauth_sync_profile_from_provider'] = ['openid_connect', 'saml']
|
||||||
|
gitlab_rails['omniauth_sync_profile_attributes'] = ['email', 'name']
|
||||||
|
|
||||||
|
gitlab_rails['omniauth_providers'] = [
|
||||||
|
{
|
||||||
|
'name' => 'openid_connect',
|
||||||
|
'label' => 'Authentik',
|
||||||
|
'args' => {
|
||||||
|
'name' => 'openid_connect',
|
||||||
|
'scope' => ['openid', 'profile', 'email'],
|
||||||
|
'response_type' => 'code',
|
||||||
|
'issuer' => 'https://auth.kube.huskypup.net/application/o/gitlab/',
|
||||||
|
'discovery' => true,
|
||||||
|
'client_auth_method' => 'query',
|
||||||
|
'uid_field' => 'sub',
|
||||||
|
'send_scope_to_token_endpoint' => true,
|
||||||
|
'pkce' => true,
|
||||||
|
'client_options' => {
|
||||||
|
'identifier' => ENV['GITLAB_OIDC_CLIENT_ID'],
|
||||||
|
'secret' => ENV['GITLAB_OIDC_CLIENT_SECRET'],
|
||||||
|
'redirect_uri' => 'https://gitlab.kube.huskypup.net/users/auth/openid_connect/callback'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name' => 'saml',
|
||||||
|
'label' => 'Authentik SAML',
|
||||||
|
'args' => {
|
||||||
|
'assertion_consumer_service_url' => 'https://gitlab.kube.huskypup.net/users/auth/saml/callback',
|
||||||
|
'idp_cert_fingerprint' => ENV['GITLAB_SAML_IDP_FINGERPRINT'],
|
||||||
|
'idp_sso_target_url' => ENV['GITLAB_SAML_IDP_SSO_URL'],
|
||||||
|
'issuer' => 'https://gitlab.kube.huskypup.net',
|
||||||
|
'name_identifier_format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
|
||||||
|
'attribute_statements' => {
|
||||||
|
'email' => ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'],
|
||||||
|
'name' => ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'],
|
||||||
|
'first_name' => ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'],
|
||||||
|
'last_name' => ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
# Homelab resource allocation
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# GitLab KAS (Kubernetes Agent Server) - enabled for Kubernetes cluster integration
|
||||||
|
kas:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 1Gi
|
||||||
|
|
||||||
|
# Gitaly Cluster (Praefect) - High Availability Git storage
|
||||||
|
gitaly:
|
||||||
|
# Note: enabled is in global.gitaly
|
||||||
|
persistence:
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
size: 200Gi # Production storage
|
||||||
|
# Production resources
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# GitLab Runner - enabled for CI/CD
|
||||||
|
gitlab-runner:
|
||||||
|
install: false # Will be installed separately
|
||||||
|
|
||||||
|
# Praefect - Gitaly Cluster routing and transaction manager
|
||||||
|
praefect:
|
||||||
|
enabled: true
|
||||||
|
minReplicas: 1 # Homelab sizing
|
||||||
|
maxReplicas: 1
|
||||||
|
|
||||||
|
# Note: Praefect PostgreSQL config is in global.praefect.psql
|
||||||
|
|
||||||
|
# Use CNPG-generated database secret
|
||||||
|
dbSecret:
|
||||||
|
secret: pg-praefect-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
# Resources
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# Virtual storage configuration
|
||||||
|
virtualStorages:
|
||||||
|
- name: default
|
||||||
|
gitalyReplicas: 1 # Homelab sizing
|
||||||
|
maxUnavailable: 1
|
||||||
|
|
||||||
|
# GitLab Exporter for Prometheus metrics
|
||||||
|
gitlab-exporter:
|
||||||
|
enabled: true
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
# Sidekiq background jobs
|
||||||
|
sidekiq:
|
||||||
|
minReplicas: 1 # Homelab sizing
|
||||||
|
maxReplicas: 1
|
||||||
|
|
||||||
|
# Note: hostAliases applied via helmfile postsync hook
|
||||||
|
|
||||||
|
# Homelab resources
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 25m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# Disable components we already have in the cluster
|
||||||
|
certmanager:
|
||||||
|
install: false # Using cluster-wide cert-manager
|
||||||
|
installCRDs: false
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
install: false # Using existing Prometheus
|
||||||
|
|
||||||
|
nginx-ingress:
|
||||||
|
enabled: false # Istio handles ingress
|
||||||
|
|
||||||
|
# Disable GitLab Runner (configure separately if needed)
|
||||||
|
gitlab-runner:
|
||||||
|
install: false
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 2
|
||||||
|
|
||||||
|
# Resource limits to prevent OOM
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
# PostgreSQL configuration for Guacamole
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
max_connections: "100"
|
||||||
|
shared_buffers: "256MB"
|
||||||
|
effective_cache_size: "768MB"
|
||||||
|
maintenance_work_mem: "64MB"
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: "8MB"
|
||||||
|
default_statistics_target: "100"
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
work_mem: "1310kB"
|
||||||
|
min_wal_size: "1GB"
|
||||||
|
max_wal_size: "4GB"
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: guacamole
|
||||||
|
owner: guacamole
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# Job to initialize Guacamole database schema
|
||||||
|
# This should run once after the PostgreSQL cluster is ready
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: guacamole-init-schema
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
ttlSecondsAfterFinished: 300
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-postgres
|
||||||
|
image: postgres:16-alpine
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
echo "Waiting for PostgreSQL to be ready..."
|
||||||
|
until pg_isready -h pg-guacamole-rw -p 5432 -U guacamole; do
|
||||||
|
echo "PostgreSQL not ready, waiting..."
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
echo "PostgreSQL is ready!"
|
||||||
|
env:
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-guacamole-app
|
||||||
|
key: password
|
||||||
|
- name: generate-initdb
|
||||||
|
image: guacamole/guacamole:1.6.0
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
/opt/guacamole/bin/initdb.sh --postgresql > /initdb/initdb.sql
|
||||||
|
test -s /initdb/initdb.sql
|
||||||
|
volumeMounts:
|
||||||
|
- name: initdb
|
||||||
|
mountPath: /initdb
|
||||||
|
containers:
|
||||||
|
- name: init-schema
|
||||||
|
image: postgres:16-alpine
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
echo "Checking if schema already exists..."
|
||||||
|
TABLES=$(PGPASSWORD="$PGPASSWORD" psql -h pg-guacamole-rw -U guacamole -d guacamole -tA -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'guacamole_user';" 2>/dev/null | tr -d '[:space:]' || printf '0')
|
||||||
|
TABLES=${TABLES:-0}
|
||||||
|
|
||||||
|
if [ "$TABLES" -gt "0" ]; then
|
||||||
|
echo "Schema already exists."
|
||||||
|
else
|
||||||
|
echo "Initializing Guacamole database schema..."
|
||||||
|
PGPASSWORD="$PGPASSWORD" psql -v ON_ERROR_STOP=1 -h pg-guacamole-rw -U guacamole -d guacamole -f /initdb/initdb.sql
|
||||||
|
echo "Schema initialization complete!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Setting up Authentik Admins group permissions..."
|
||||||
|
PGPASSWORD="$PGPASSWORD" psql -v ON_ERROR_STOP=1 -h pg-guacamole-rw -U guacamole -d guacamole -f /schema/permissions.sql
|
||||||
|
echo "Authentik Admins group permissions configured!"
|
||||||
|
env:
|
||||||
|
- name: PGPASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-guacamole-app
|
||||||
|
key: password
|
||||||
|
volumeMounts:
|
||||||
|
- name: initdb
|
||||||
|
mountPath: /initdb
|
||||||
|
- name: schema
|
||||||
|
mountPath: /schema
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
- name: initdb
|
||||||
|
emptyDir: {}
|
||||||
|
- name: schema
|
||||||
|
configMap:
|
||||||
|
name: guacamole-schema
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
# Guacamole complete deployment with OpenID/Authentik support
|
||||||
|
# This deployment includes:
|
||||||
|
# - Environment-based OpenID configuration
|
||||||
|
# - PostgreSQL backend for connections/users
|
||||||
|
# - Authentik uses Let's Encrypt (no custom cert import needed)
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: client
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxSurge: 0
|
||||||
|
maxUnavailable: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: guacamole
|
||||||
|
component: client
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: client
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
containers:
|
||||||
|
- name: guacamole
|
||||||
|
image: guacamole/guacamole:1.6.0
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
- name: tomcat-work
|
||||||
|
mountPath: /usr/local/tomcat/work
|
||||||
|
- name: tomcat-logs
|
||||||
|
mountPath: /usr/local/tomcat/logs
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: GUACD_HOSTNAME
|
||||||
|
value: "guacd"
|
||||||
|
- name: GUACD_PORT
|
||||||
|
value: "4822"
|
||||||
|
- name: POSTGRESQL_HOSTNAME
|
||||||
|
value: "pg-guacamole-rw"
|
||||||
|
- name: POSTGRESQL_PORT
|
||||||
|
value: "5432"
|
||||||
|
- name: POSTGRESQL_DATABASE
|
||||||
|
value: "guacamole"
|
||||||
|
- name: POSTGRESQL_ENABLED
|
||||||
|
value: "true"
|
||||||
|
- name: POSTGRESQL_USERNAME
|
||||||
|
value: "guacamole"
|
||||||
|
- name: POSTGRESQL_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-guacamole-app
|
||||||
|
key: password
|
||||||
|
- name: POSTGRESQL_AUTO_CREATE_ACCOUNTS
|
||||||
|
value: "true"
|
||||||
|
- name: ENABLE_ENVIRONMENT_PROPERTIES
|
||||||
|
value: "true"
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: "debug"
|
||||||
|
- name: WEBAPP_CONTEXT
|
||||||
|
value: "ROOT"
|
||||||
|
# FIX: Enabled WebSockets to stop the 10-second tunnel timeout
|
||||||
|
- name: ENABLE_WEBSOCKET
|
||||||
|
value: "true"
|
||||||
|
- name: EXTENSION_PRIORITY
|
||||||
|
value: "*,openid"
|
||||||
|
- name: OPENID_RESPONSE_TYPE
|
||||||
|
value: "code"
|
||||||
|
- name: OPENID_AUTHORIZATION_ENDPOINT
|
||||||
|
value: "https://auth.kube.huskypup.net/application/o/authorize/"
|
||||||
|
- name: OPENID_JWKS_ENDPOINT
|
||||||
|
value: "https://auth.kube.huskypup.net/application/o/guacamole/jwks/"
|
||||||
|
- name: OPENID_ISSUER
|
||||||
|
value: "https://auth.kube.huskypup.net/application/o/guacamole/"
|
||||||
|
- name: OPENID_TOKEN_ENDPOINT
|
||||||
|
value: "https://auth.kube.huskypup.net/application/o/token/"
|
||||||
|
- name: OPENID_REDIRECT_URI
|
||||||
|
value: "https://guacamole.kube.huskypup.net/"
|
||||||
|
- name: OPENID_USERNAME_CLAIM_TYPE
|
||||||
|
value: "preferred_username"
|
||||||
|
- name: OPENID_GROUPS_CLAIM_TYPE
|
||||||
|
value: "groups"
|
||||||
|
- name: OPENID_SCOPE
|
||||||
|
value: "openid email profile groups"
|
||||||
|
- name: OPENID_ALLOWED_CLOCK_SKEW
|
||||||
|
value: "30"
|
||||||
|
- name: OPENID_MAX_TOKEN_VALIDITY
|
||||||
|
value: "300"
|
||||||
|
- name: OPENID_MAX_NONCE_VALIDITY
|
||||||
|
value: "60"
|
||||||
|
- name: OPENID_CLIENT_ID
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: guacamole-oauth-secret
|
||||||
|
key: client-id
|
||||||
|
- name: OPENID_CLIENT_SECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: guacamole-oauth-secret
|
||||||
|
key: client-secret
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "250m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "1000m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/languages
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 30
|
||||||
|
# FIX: Relaxed readiness probe so minor DB lags don't kill the Endpoint
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/languages
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 15
|
||||||
|
failureThreshold: 5
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
- name: tomcat-work
|
||||||
|
emptyDir: {}
|
||||||
|
- name: tomcat-logs
|
||||||
|
emptyDir: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: guacd
|
||||||
|
namespace: guacamole
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: guacd
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: guacamole
|
||||||
|
component: guacd
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: guacd
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
containers:
|
||||||
|
- name: guacd
|
||||||
|
image: guacamole/guacd:1.6.0
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 10000
|
||||||
|
runAsGroup: 10000
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
- name: home
|
||||||
|
mountPath: /home
|
||||||
|
ports:
|
||||||
|
- name: guacd
|
||||||
|
containerPort: 4822
|
||||||
|
protocol: TCP
|
||||||
|
env:
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: "debug"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "10m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
readinessProbe:
|
||||||
|
tcpSocket:
|
||||||
|
port: 4822
|
||||||
|
initialDelaySeconds: 2
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 1
|
||||||
|
successThreshold: 1
|
||||||
|
failureThreshold: 3
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
- name: home
|
||||||
|
emptyDir: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: client
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
|
selector:
|
||||||
|
app: guacamole
|
||||||
|
component: client
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: guacd
|
||||||
|
namespace: guacamole
|
||||||
|
labels:
|
||||||
|
app: guacamole
|
||||||
|
component: guacd
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 4822
|
||||||
|
targetPort: guacd
|
||||||
|
protocol: TCP
|
||||||
|
name: guacd
|
||||||
|
selector:
|
||||||
|
app: guacamole
|
||||||
|
component: guacd
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: guacamole-envoy-tls
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
secretName: guacamole-envoy-tls
|
||||||
|
issuerRef:
|
||||||
|
kind: ClusterIssuer
|
||||||
|
name: letsencrypt-production
|
||||||
|
dnsNames:
|
||||||
|
- guacamole.kube.huskypup.net
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: Gateway
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
gatewayClassName: envoy-gateway
|
||||||
|
listeners:
|
||||||
|
- name: https
|
||||||
|
hostname: guacamole.kube.huskypup.net
|
||||||
|
port: 443
|
||||||
|
protocol: HTTPS
|
||||||
|
tls:
|
||||||
|
mode: Terminate
|
||||||
|
certificateRefs:
|
||||||
|
- kind: Secret
|
||||||
|
name: guacamole-envoy-tls
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: guacamole
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- guacamole.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
# Legacy path support: https://host/guacamole/* -> https://host/*
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /guacamole
|
||||||
|
filters:
|
||||||
|
- type: URLRewrite
|
||||||
|
urlRewrite:
|
||||||
|
path:
|
||||||
|
type: ReplacePrefixMatch
|
||||||
|
replacePrefixMatch: /
|
||||||
|
backendRefs:
|
||||||
|
- name: guacamole
|
||||||
|
port: 8080
|
||||||
|
# Standard root routing
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: guacamole
|
||||||
|
port: 8080
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- guacamole.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /guacamole
|
||||||
|
filters:
|
||||||
|
- type: URLRewrite
|
||||||
|
urlRewrite:
|
||||||
|
path:
|
||||||
|
type: ReplacePrefixMatch
|
||||||
|
replacePrefixMatch: /
|
||||||
|
backendRefs:
|
||||||
|
- name: guacamole
|
||||||
|
port: 8080
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: guacamole
|
||||||
|
port: 8080
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# kubernetes/apps/guacamole/external-secret.yaml
|
||||||
|
# ExternalSecrets for Guacamole - pulls credentials from Vault
|
||||||
|
|
||||||
|
# Note: Database password is managed by CNPG cluster (pg-guacamole-app secret)
|
||||||
|
# We reference it directly in the guacamole values.yaml
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: guacamole-oauth
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: guacamole-oauth-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: client-id
|
||||||
|
remoteRef:
|
||||||
|
key: guacamole-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client-secret
|
||||||
|
remoteRef:
|
||||||
|
key: guacamole-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: guacamole
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- guacamole.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: guacamole.guacamole.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: esphome
|
||||||
|
namespace: home-assistant
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- esphome.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: esphome
|
||||||
|
port: 6052
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: esphome
|
||||||
|
namespace: home-assistant
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- esphome.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: esphome.home-assistant.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 6052
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# ESPHome Helm Chart Values
|
||||||
|
# Deployed in home-assistant namespace as a companion to Home Assistant
|
||||||
|
#
|
||||||
|
# FEATURES:
|
||||||
|
# ✓ ESPHome Dashboard for managing ESP devices
|
||||||
|
# ✓ Persistent storage via Rook-Ceph
|
||||||
|
# ✓ TLS certificates via cert-manager
|
||||||
|
# ✓ Ingress via Istio VirtualService
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/esphome/esphome
|
||||||
|
tag: "2024.11.3"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 6052
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualService handles routing
|
||||||
|
ingress:
|
||||||
|
main:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 5Gi
|
||||||
|
retain: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
TZ: America/New_York
|
||||||
|
ESPHOME_DASHBOARD_USE_PING: "true"
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
privileged: false
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
enabled: true
|
||||||
|
readiness:
|
||||||
|
enabled: true
|
||||||
|
startup:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/arch: amd64
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: home-assistant
|
||||||
|
namespace: home-assistant
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- homeassistant.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: home-assistant
|
||||||
|
port: 8123
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
# Home Assistant OIDC Credentials - External Secret
|
||||||
|
#
|
||||||
|
# This ExternalSecret syncs Home Assistant OIDC credentials from Vault
|
||||||
|
# Credentials are stored in Vault by the sync-homeassistant-oauth.sh script
|
||||||
|
# after Authentik blueprint creates the OAuth provider
|
||||||
|
#
|
||||||
|
# The secret is used by Home Assistant's hass-openid integration
|
||||||
|
# to authenticate users via Authentik OIDC
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: homeassistant-oauth
|
||||||
|
namespace: home-assistant
|
||||||
|
spec:
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: homeassistant-oidc-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
refreshInterval: 1h
|
||||||
|
data:
|
||||||
|
- secretKey: client_id
|
||||||
|
remoteRef:
|
||||||
|
key: secret/homeassistant-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client_secret
|
||||||
|
remoteRef:
|
||||||
|
key: secret/homeassistant-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: home-assistant
|
||||||
|
namespace: home-assistant
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- homeassistant.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: home-assistant.home-assistant.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8123
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
# Home Assistant OIDC Configuration ConfigMap
|
||||||
|
#
|
||||||
|
# This ConfigMap contains the OIDC configuration snippet that gets appended
|
||||||
|
# to Home Assistant's configuration.yaml file during bootstrap
|
||||||
|
#
|
||||||
|
# The configuration enables hass-openid integration for Authentik OIDC auth
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: homeassistant-oidc-config
|
||||||
|
namespace: home-assistant
|
||||||
|
data:
|
||||||
|
oidc.yaml: |
|
||||||
|
# OIDC Authentication via Authentik
|
||||||
|
# Users authenticate via Authentik and are auto-created in Home Assistant
|
||||||
|
openid:
|
||||||
|
client_id: !secret oidc_client_id
|
||||||
|
client_secret: !secret oidc_client_secret
|
||||||
|
configure_url: "https://auth.kube.huskypup.net/application/o/home-assistant/.well-known/openid-configuration"
|
||||||
|
scope: "openid profile email"
|
||||||
|
username_field: "preferred_username"
|
||||||
|
create_user: true
|
||||||
|
block_login: false
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
# Disable Istio sidecar on home-assistant pod because the init container
|
||||||
|
# (install-hass-openid) needs unrestricted network access to git clone.
|
||||||
|
# Istio CNI redirects traffic to the proxy port during init, but the proxy
|
||||||
|
# isn't running yet, causing TLS/connection failures.
|
||||||
|
# ESPHome (same namespace) still gets sidecar injection normally.
|
||||||
|
podAnnotations:
|
||||||
|
sidecar.istio.io/inject: "false"
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/home-assistant/home-assistant
|
||||||
|
tag: "2025.1.2"
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
initContainers:
|
||||||
|
install-hass-openid:
|
||||||
|
image: docker.io/alpine/git:2.47.2
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -e
|
||||||
|
apk add --no-cache git
|
||||||
|
|
||||||
|
# Install hass-openid custom integration
|
||||||
|
mkdir -p /config/custom_components /config/includes
|
||||||
|
cd /tmp
|
||||||
|
git clone --depth 1 https://github.com/cavefire/hass-openid.git
|
||||||
|
cp -r hass-openid/custom_components/openid /config/custom_components/
|
||||||
|
rm -rf hass-openid
|
||||||
|
|
||||||
|
# Write MQTT addons config
|
||||||
|
printf 'mqtt:\n broker: mqtt.kube.huskypup.net\n port: 1883\n username: homeassistant\n password: YOUR_MQTT_PASSWORD' > /config/includes/ha-addons.yaml
|
||||||
|
|
||||||
|
# Write OIDC credentials to secrets.yaml (from mounted k8s secret)
|
||||||
|
if [ -f /oidc-secret/client_id ] && [ -f /oidc-secret/client_secret ]; then
|
||||||
|
CLIENT_ID=$(cat /oidc-secret/client_id)
|
||||||
|
CLIENT_SECRET=$(cat /oidc-secret/client_secret)
|
||||||
|
# Preserve existing secrets, update OIDC entries
|
||||||
|
if [ -f /config/secrets.yaml ]; then
|
||||||
|
sed -i '/^oidc_client_id:/d' /config/secrets.yaml
|
||||||
|
sed -i '/^oidc_client_secret:/d' /config/secrets.yaml
|
||||||
|
fi
|
||||||
|
echo "oidc_client_id: \"${CLIENT_ID}\"" >> /config/secrets.yaml
|
||||||
|
echo "oidc_client_secret: \"${CLIENT_SECRET}\"" >> /config/secrets.yaml
|
||||||
|
echo "OIDC credentials written to secrets.yaml"
|
||||||
|
else
|
||||||
|
echo "WARNING: OIDC secret not mounted, skipping secrets.yaml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure OIDC config is in configuration.yaml
|
||||||
|
if [ ! -f /config/configuration.yaml ]; then
|
||||||
|
echo "Creating configuration.yaml with OIDC config..."
|
||||||
|
cat > /config/configuration.yaml <<'OIDCEOF'
|
||||||
|
# Home Assistant Configuration
|
||||||
|
default_config:
|
||||||
|
|
||||||
|
# OIDC Authentication via Authentik
|
||||||
|
openid:
|
||||||
|
client_id: !secret oidc_client_id
|
||||||
|
client_secret: !secret oidc_client_secret
|
||||||
|
configure_url: "https://auth.kube.huskypup.net/application/o/home-assistant/.well-known/openid-configuration"
|
||||||
|
scope: "openid profile email"
|
||||||
|
username_field: "preferred_username"
|
||||||
|
create_user: true
|
||||||
|
block_login: false
|
||||||
|
OIDCEOF
|
||||||
|
elif ! grep -q "^openid:" /config/configuration.yaml; then
|
||||||
|
echo "Appending OIDC config to existing configuration.yaml..."
|
||||||
|
cat >> /config/configuration.yaml <<'OIDCEOF'
|
||||||
|
|
||||||
|
# OIDC Authentication via Authentik
|
||||||
|
openid:
|
||||||
|
client_id: !secret oidc_client_id
|
||||||
|
client_secret: !secret oidc_client_secret
|
||||||
|
configure_url: "https://auth.kube.huskypup.net/application/o/home-assistant/.well-known/openid-configuration"
|
||||||
|
scope: "openid profile email"
|
||||||
|
username_field: "preferred_username"
|
||||||
|
create_user: true
|
||||||
|
block_login: false
|
||||||
|
OIDCEOF
|
||||||
|
else
|
||||||
|
echo "OIDC config already present in configuration.yaml"
|
||||||
|
fi
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /config
|
||||||
|
- name: oidc-secret
|
||||||
|
mountPath: /oidc-secret
|
||||||
|
readOnly: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
TZ: America/New_York
|
||||||
|
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 8123
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualService handles routing
|
||||||
|
ingress:
|
||||||
|
main:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 10Gi
|
||||||
|
retain: true
|
||||||
|
oidc-secret:
|
||||||
|
enabled: true
|
||||||
|
type: secret
|
||||||
|
name: homeassistant-oidc-secret
|
||||||
|
mountPath: /oidc-secret
|
||||||
|
readOnly: true
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
privileged: false
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
enabled: true
|
||||||
|
readiness:
|
||||||
|
enabled: true
|
||||||
|
startup:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
mariadb:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
influxdb:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
enabled: false
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-n8n
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 2
|
||||||
|
|
||||||
|
# Resource limits to prevent OOM
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "25m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "250m"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
# PostgreSQL configuration for better performance
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
max_connections: "200"
|
||||||
|
shared_buffers: "512MB"
|
||||||
|
effective_cache_size: "1536MB"
|
||||||
|
maintenance_work_mem: "128MB"
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: "16MB"
|
||||||
|
default_statistics_target: "100"
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
work_mem: "2621kB"
|
||||||
|
min_wal_size: "1GB"
|
||||||
|
max_wal_size: "4GB"
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: n8n
|
||||||
|
owner: n8n
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
metadata:
|
||||||
|
name: n8n-cnpg-secret
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
length: 42
|
||||||
|
digits: 5
|
||||||
|
symbols: 5
|
||||||
|
symbolCharacters: "-_$@"
|
||||||
|
noUpper: false
|
||||||
|
allowRepeat: true
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: n8n-cnpg-secret
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
# Rotate database password every 24 hours
|
||||||
|
refreshInterval: "24h"
|
||||||
|
target:
|
||||||
|
# This will merge the generated password into the existing pg-n8n-app secret
|
||||||
|
name: pg-n8n-app
|
||||||
|
creationPolicy: Merge
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
cnpg.io/reload: "true"
|
||||||
|
data:
|
||||||
|
# Override the password field with our ESO-generated password
|
||||||
|
password: "{{ .password }}"
|
||||||
|
dataFrom:
|
||||||
|
- sourceRef:
|
||||||
|
generatorRef:
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
name: n8n-cnpg-secret
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: n8n
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- n8n.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: n8n
|
||||||
|
port: 80
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# kubernetes/apps/n8n/external-secret.yaml
|
||||||
|
# ExternalSecrets for n8n - pulls credentials from Vault
|
||||||
|
|
||||||
|
# Note: Database password is managed by CNPG cluster (pg-n8n-app secret)
|
||||||
|
# We reference it directly in the n8n values.yaml extraEnv section
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: n8n-config
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: n8n-config-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: encryption-key
|
||||||
|
remoteRef:
|
||||||
|
key: n8n-config
|
||||||
|
property: encryption-key
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: n8n-oauth
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: n8n-oauth-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: client-id
|
||||||
|
remoteRef:
|
||||||
|
key: n8n-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client-secret
|
||||||
|
remoteRef:
|
||||||
|
key: n8n-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: n8n-hooks
|
||||||
|
namespace: n8n
|
||||||
|
data:
|
||||||
|
hooks.js: |
|
||||||
|
// n8n v2.0.3 compatible hooks for Authentik forward auth integration
|
||||||
|
const { resolve, dirname } = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
credentials: {
|
||||||
|
create: [],
|
||||||
|
delete: [],
|
||||||
|
update: []
|
||||||
|
},
|
||||||
|
workflow: {
|
||||||
|
create: [],
|
||||||
|
delete: [],
|
||||||
|
update: []
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
started: [
|
||||||
|
async function (app) {
|
||||||
|
console.log('[n8n-hooks] Initializing forward auth middleware');
|
||||||
|
|
||||||
|
// Get Express app
|
||||||
|
const expressApp = app?.app;
|
||||||
|
if (!expressApp) {
|
||||||
|
console.error('[n8n-hooks] Express app not available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let issueCookie, UserRepository, Container;
|
||||||
|
try {
|
||||||
|
const n8nPath = dirname(require.resolve('n8n'));
|
||||||
|
issueCookie = require(resolve(n8nPath, 'dist/auth/jwt')).issueCookie;
|
||||||
|
UserRepository = require(resolve(n8nPath, 'dist/databases/repositories/user.repository')).UserRepository;
|
||||||
|
Container = require('typedi').Container;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[n8n-hooks] Failed to load dependencies:', error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ignoreAuthRegexp = /^\/(assets|healthz|webhook|rest\/oauth2-credential|rest\/settings|static|icons|types)/;
|
||||||
|
|
||||||
|
// Add middleware for forward auth
|
||||||
|
expressApp.use(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
if (ignoreAuthRegexp.test(req.url)) return next();
|
||||||
|
if (req.cookies?.['n8n-auth']) return next();
|
||||||
|
if (!process.env.N8N_FORWARD_AUTH_HEADER) return next();
|
||||||
|
|
||||||
|
const headerName = process.env.N8N_FORWARD_AUTH_HEADER.toLowerCase().replace(/_/g, '-');
|
||||||
|
const email = req.headers[headerName];
|
||||||
|
if (!email) return next();
|
||||||
|
|
||||||
|
const userRepo = Container.get(UserRepository);
|
||||||
|
const user = await userRepo.findOne({ where: { email } });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
console.warn(`[n8n-hooks] User not found: ${email}`);
|
||||||
|
res.statusCode = 401;
|
||||||
|
res.end(`User ${email} not found. Please contact an admin.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[n8n-hooks] Auto-login: ${email}`);
|
||||||
|
issueCookie(res, user);
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[n8n-hooks] Middleware error:', error.message);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[n8n-hooks] Forward auth middleware active');
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: n8n
|
||||||
|
namespace: n8n
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- n8n.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: n8n.n8n.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
# kubernetes/apps/n8n/values.yaml
|
||||||
|
# n8n workflow automation platform
|
||||||
|
# Using chart: https://riatlas.github.io/chart__n8n
|
||||||
|
|
||||||
|
# --- n8n image ---
|
||||||
|
image:
|
||||||
|
repository: n8nio/n8n
|
||||||
|
tag: "2.0.3"
|
||||||
|
|
||||||
|
# --- n8n encryption key (loaded from secret) ---
|
||||||
|
n8n:
|
||||||
|
encryption_key: # Will be set via extraEnv from n8n-config-secret
|
||||||
|
|
||||||
|
# --- n8n configuration ---
|
||||||
|
config:
|
||||||
|
database:
|
||||||
|
type: postgresdb
|
||||||
|
postgresdb:
|
||||||
|
host: pg-n8n-rw # CNPG read-write service
|
||||||
|
port: 5432
|
||||||
|
database: n8n
|
||||||
|
user: n8n
|
||||||
|
schema: public
|
||||||
|
generic:
|
||||||
|
timezone: America/New_York
|
||||||
|
path: /
|
||||||
|
host: n8n.kube.huskypup.net
|
||||||
|
port: 5678
|
||||||
|
protocol: https
|
||||||
|
executions:
|
||||||
|
mode: regular
|
||||||
|
saveDataOnError: all
|
||||||
|
saveDataOnSuccess: all
|
||||||
|
saveDataManualExecutions: true
|
||||||
|
pruneData: true
|
||||||
|
pruneDataMaxAge: 3760 # 1 year in hours
|
||||||
|
|
||||||
|
# --- Secret values (passwords, etc.) ---
|
||||||
|
# Note: password is injected via extraEnvSecrets below
|
||||||
|
secret: {}
|
||||||
|
|
||||||
|
# --- Deployment replicas ---
|
||||||
|
# Increased to 2 for high availability and faster response times
|
||||||
|
replicaCount: 2
|
||||||
|
|
||||||
|
# --- Service configuration ---
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
# --- Security context ---
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
|
||||||
|
# --- Ingress disabled - Istio VirtualService handles routing ---
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# --- Persistence for workflows and data ---
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
type: existing
|
||||||
|
existingClaim: n8n-main-persistence
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
# --- Resources ---
|
||||||
|
# No CPU limits (burst allowed). Keep requests minimal for scheduling.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
# --- Startup probe ---
|
||||||
|
# Allows app to start without being killed by liveness probe
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 12 # 60 seconds total startup time
|
||||||
|
|
||||||
|
# --- Readiness probe ---
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 2
|
||||||
|
|
||||||
|
# --- Liveness probe ---
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
|
||||||
|
# --- Extra environment variables (from secrets) ---
|
||||||
|
# Secrets are loaded from Kubernetes secrets
|
||||||
|
extraEnvSecrets:
|
||||||
|
# Database password from CNPG-managed secret
|
||||||
|
DB_POSTGRESDB_PASSWORD:
|
||||||
|
name: pg-n8n-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
# n8n encryption key
|
||||||
|
N8N_ENCRYPTION_KEY:
|
||||||
|
name: n8n-config-secret
|
||||||
|
key: encryption-key
|
||||||
|
|
||||||
|
# --- Extra environment variables (plain values) ---
|
||||||
|
extraEnv:
|
||||||
|
# Webhook & Editor URLs
|
||||||
|
WEBHOOK_URL: https://n8n.kube.huskypup.net/
|
||||||
|
N8N_EDITOR_BASE_URL: https://n8n.kube.huskypup.net
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
N8N_LOG_LEVEL: error
|
||||||
|
|
||||||
|
# --- Disable built-in PostgreSQL (we'll deploy it separately with Bitnami) ---
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# --- Disable Redis (not needed for single instance) ---
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# --- Scaling (disabled for single instance) ---
|
||||||
|
scaling:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# --- Extra volumes ---
|
||||||
|
extraVolumes: []
|
||||||
|
|
||||||
|
# --- Extra volume mounts ---
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# --- Node selector ---
|
||||||
|
nodeSelector: {}
|
||||||
|
|
||||||
|
# --- Tolerations ---
|
||||||
|
tolerations: []
|
||||||
|
|
||||||
|
# --- Affinity ---
|
||||||
|
affinity: {}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# CloudNative PostgreSQL cluster for Nessus
|
||||||
|
# Low resource configuration for memory-constrained environments
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-nessus
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 2
|
||||||
|
|
||||||
|
# Low resource limits for constrained environments
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes for HA
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 20Gi
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
# PostgreSQL configuration optimized for low memory
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
max_connections: "100"
|
||||||
|
shared_buffers: "256MB"
|
||||||
|
effective_cache_size: "768MB"
|
||||||
|
maintenance_work_mem: "64MB"
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: "8MB"
|
||||||
|
default_statistics_target: "100"
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
work_mem: "2621kB"
|
||||||
|
min_wal_size: "512MB"
|
||||||
|
max_wal_size: "2GB"
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: nessus
|
||||||
|
owner: nessus
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# External Secrets Operator configuration for Nessus PostgreSQL password rotation
|
||||||
|
# This auto-generates and rotates the database password in Vault
|
||||||
|
---
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
metadata:
|
||||||
|
name: nessus-db-password
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
length: 32
|
||||||
|
digits: 10
|
||||||
|
symbols: 0 # No special chars to avoid escaping issues
|
||||||
|
symbolCharacters: ""
|
||||||
|
noUpper: false
|
||||||
|
allowRepeat: true
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: nessus-cnpg-secret
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: nessus-db-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
template:
|
||||||
|
engineVersion: v2
|
||||||
|
data:
|
||||||
|
password: "{{ .password }}"
|
||||||
|
username: "nessus"
|
||||||
|
host: "pg-nessus-rw"
|
||||||
|
port: "5432"
|
||||||
|
database: "nessus"
|
||||||
|
dataFrom:
|
||||||
|
- sourceRef:
|
||||||
|
generatorRef:
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
name: nessus-db-password
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
# Nessus Vulnerability Scanner Deployment
|
||||||
|
# Optimized for low resource usage in constrained environments
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: nessus
|
||||||
|
namespace: nessus
|
||||||
|
labels:
|
||||||
|
app: nessus
|
||||||
|
app.kubernetes.io/name: nessus
|
||||||
|
app.kubernetes.io/component: security-scanner
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate # Only one instance can mount the PVC at a time
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: nessus
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: nessus
|
||||||
|
annotations:
|
||||||
|
# Reloader auto-restart when secrets change
|
||||||
|
secret.reloader.stakater.com/reload: "nessus-admin-credentials"
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: nessus
|
||||||
|
image: docker.io/tenable/nessus:10.8.3-ubuntu
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
# Low resource configuration for constrained environments
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
containerPort: 8834
|
||||||
|
protocol: TCP
|
||||||
|
|
||||||
|
# Environment variables for Nessus configuration
|
||||||
|
env:
|
||||||
|
# Admin credentials from Vault (via ESO)
|
||||||
|
- name: USERNAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: nessus-admin-credentials
|
||||||
|
key: NESSUS_USERNAME
|
||||||
|
- name: PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: nessus-admin-credentials
|
||||||
|
key: NESSUS_PASSWORD
|
||||||
|
|
||||||
|
# Auto-update settings (plugins only to save bandwidth/time)
|
||||||
|
- name: AUTO_UPDATE
|
||||||
|
value: "plugins"
|
||||||
|
|
||||||
|
# Volume mounts for persistent data
|
||||||
|
volumeMounts:
|
||||||
|
- name: nessus-data
|
||||||
|
mountPath: /opt/nessus/var/nessus
|
||||||
|
|
||||||
|
# Startup probe - give Nessus time to initialize
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 8834
|
||||||
|
scheme: HTTPS
|
||||||
|
initialDelaySeconds: 60
|
||||||
|
periodSeconds: 15
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 60 # 15 minutes total startup time
|
||||||
|
|
||||||
|
# Liveness probe
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 8834
|
||||||
|
scheme: HTTPS
|
||||||
|
initialDelaySeconds: 300
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 10
|
||||||
|
failureThreshold: 5
|
||||||
|
|
||||||
|
# Readiness probe
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 8834
|
||||||
|
scheme: HTTPS
|
||||||
|
initialDelaySeconds: 120
|
||||||
|
periodSeconds: 15
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 5
|
||||||
|
|
||||||
|
# Security context
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
runAsNonRoot: false # Nessus requires root
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_ADMIN # Required for network scanning
|
||||||
|
- NET_RAW # Required for raw socket scanning
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: nessus-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: nessus-data
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nessus
|
||||||
|
namespace: nessus
|
||||||
|
labels:
|
||||||
|
app: nessus
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
port: 8834
|
||||||
|
targetPort: 8834
|
||||||
|
protocol: TCP
|
||||||
|
selector:
|
||||||
|
app: nessus
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# External Secrets Operator configuration for Nessus admin credentials
|
||||||
|
# Pulls Nessus admin username and password from Vault
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: nessus-admin-secret
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: nessus-admin-credentials
|
||||||
|
creationPolicy: Owner
|
||||||
|
template:
|
||||||
|
engineVersion: v2
|
||||||
|
data:
|
||||||
|
NESSUS_USERNAME: "{{ .username }}"
|
||||||
|
NESSUS_PASSWORD: "{{ .password }}"
|
||||||
|
data:
|
||||||
|
- secretKey: username
|
||||||
|
remoteRef:
|
||||||
|
key: secret/nessus
|
||||||
|
property: admin-username
|
||||||
|
- secretKey: password
|
||||||
|
remoteRef:
|
||||||
|
key: secret/nessus
|
||||||
|
property: admin-password
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: DestinationRule
|
||||||
|
metadata:
|
||||||
|
name: nessus
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
host: nessus.nessus.svc.cluster.local
|
||||||
|
trafficPolicy:
|
||||||
|
tls:
|
||||||
|
mode: SIMPLE
|
||||||
|
sni: nessus.nessus.svc.cluster.local
|
||||||
|
insecureSkipVerify: true
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: nessus
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- nessus.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: nessus.nessus.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8834
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# PersistentVolumeClaim for Nessus scan data and plugin storage
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: nessus-data
|
||||||
|
namespace: nessus
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: rook-ceph-block
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: nextcloud
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- nextcloud.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: nextcloud
|
||||||
|
port: 8080
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# kubernetes/apps/nextcloud/external-secret.yaml
|
||||||
|
# ExternalSecrets for Nextcloud - pulls OAuth credentials from Vault
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: nextcloud-oauth
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: nextcloud-oauth-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: client-id
|
||||||
|
remoteRef:
|
||||||
|
key: nextcloud-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client-secret
|
||||||
|
remoteRef:
|
||||||
|
key: nextcloud-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: nextcloud
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- nextcloud.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- timeout: 3600s
|
||||||
|
route:
|
||||||
|
- destination:
|
||||||
|
host: nextcloud.nextcloud.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 8080
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mariadb-nextcloud
|
||||||
|
namespace: nextcloud
|
||||||
|
labels:
|
||||||
|
app: mariadb-nextcloud
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mariadb-nextcloud
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mariadb-nextcloud
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsGroup: 999
|
||||||
|
fsGroup: 999
|
||||||
|
containers:
|
||||||
|
- name: mariadb
|
||||||
|
image: mariadb:11.4
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 999
|
||||||
|
runAsGroup: 999
|
||||||
|
runAsNonRoot: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
args:
|
||||||
|
- --character-set-server=utf8mb4
|
||||||
|
- --collation-server=utf8mb4_unicode_ci
|
||||||
|
- --init-connect=SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci
|
||||||
|
env:
|
||||||
|
- name: MARIADB_ROOT_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mariadb-nextcloud
|
||||||
|
key: root-password
|
||||||
|
- name: MARIADB_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mariadb-nextcloud
|
||||||
|
key: password
|
||||||
|
- name: MARIADB_USER
|
||||||
|
value: nextcloud
|
||||||
|
- name: MARIADB_DATABASE
|
||||||
|
value: nextcloud
|
||||||
|
ports:
|
||||||
|
- containerPort: 3306
|
||||||
|
volumeMounts:
|
||||||
|
- name: mariadb-data
|
||||||
|
mountPath: /var/lib/mysql
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
- name: run-mysqld
|
||||||
|
mountPath: /run/mysqld
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
|
- name: run-mysqld
|
||||||
|
emptyDir: {}
|
||||||
|
- name: mariadb-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: mariadb-nextcloud-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mariadb-nextcloud
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mariadb-nextcloud
|
||||||
|
ports:
|
||||||
|
- port: 3306
|
||||||
|
targetPort: 3306
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: mariadb-nextcloud-pvc
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: rook-ceph-block
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
metadata:
|
||||||
|
name: nextcloud-mariadb-password
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
length: 32
|
||||||
|
digits: 5
|
||||||
|
symbols: 3
|
||||||
|
symbolCharacters: "-_$"
|
||||||
|
noUpper: false
|
||||||
|
allowRepeat: true
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: nextcloud-mariadb-secret
|
||||||
|
namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
refreshInterval: "24h"
|
||||||
|
target:
|
||||||
|
name: mariadb-nextcloud
|
||||||
|
creationPolicy: Owner
|
||||||
|
template:
|
||||||
|
data:
|
||||||
|
password: "{{ .password }}"
|
||||||
|
root-password: "{{ .password }}"
|
||||||
|
user: nextcloud
|
||||||
|
dataFrom:
|
||||||
|
- sourceRef:
|
||||||
|
generatorRef:
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
name: nextcloud-mariadb-password
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: nextcloud-nextcloud
|
||||||
|
namespace: nextcloud
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
app.kubernetes.io/name: nextcloud
|
||||||
|
app.kubernetes.io/instance: nextcloud
|
||||||
|
annotations:
|
||||||
|
meta.helm.sh/release-name: nextcloud
|
||||||
|
meta.helm.sh/release-namespace: nextcloud
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
storageClassName: rook-ceph-block # Rook-Ceph block storage
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 50Gi # whatever size you want
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
# values/nextcloud.values.yaml
|
||||||
|
#
|
||||||
|
# For chart: nextcloud/nextcloud
|
||||||
|
# Repo: https://nextcloud.github.io/helm/
|
||||||
|
#
|
||||||
|
# Optimized for large file uploads over 1Gbps link
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
nextcloud:
|
||||||
|
host: nextcloud.kube.huskypup.net
|
||||||
|
username: ""
|
||||||
|
password: ""
|
||||||
|
|
||||||
|
# PHP configuration for large uploads
|
||||||
|
# Use /var/www/tmp (on Ceph PVC) instead of /tmp (on root overlay)
|
||||||
|
phpConfigs:
|
||||||
|
upload.ini: |
|
||||||
|
upload_tmp_dir = /var/www/tmp
|
||||||
|
sys_temp_dir = /var/www/tmp
|
||||||
|
|
||||||
|
# Environment variables for PHP
|
||||||
|
extraEnv:
|
||||||
|
- name: TMPDIR
|
||||||
|
value: /var/www/tmp
|
||||||
|
- name: PHP_MEMORY_LIMIT
|
||||||
|
value: "2G"
|
||||||
|
- name: PHP_UPLOAD_LIMIT
|
||||||
|
value: "10G"
|
||||||
|
|
||||||
|
configs:
|
||||||
|
oidc.config.php: |-
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'oidc_login_provider_url' => 'https://auth.kube.huskypup.net/application/o/nextcloud/',
|
||||||
|
'oidc_login_client_id' => '',
|
||||||
|
'oidc_login_client_secret' => '',
|
||||||
|
'oidc_login_button_text' => 'Log in with Authentik',
|
||||||
|
'oidc_login_auto_redirect' => false,
|
||||||
|
'oidc_login_hide_password_form' => false,
|
||||||
|
'oidc_login_verify_ssl' => false,
|
||||||
|
'user_oidc' => array(
|
||||||
|
'httpclient.allowselfsigned' => true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
proxy.config.php: |-
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'trusted_proxies' => array(
|
||||||
|
0 => '10.0.0.0/8',
|
||||||
|
1 => '172.16.0.0/12',
|
||||||
|
),
|
||||||
|
'overwriteprotocol' => 'https',
|
||||||
|
'overwrite.cli.url' => 'https://nextcloud.kube.huskypup.net',
|
||||||
|
'allow_local_remote_servers' => true,
|
||||||
|
);
|
||||||
|
# Use Ceph-backed temp directory for large uploads
|
||||||
|
temp.config.php: |-
|
||||||
|
<?php
|
||||||
|
$CONFIG = array (
|
||||||
|
'tempdirectory' => '/var/www/tmp',
|
||||||
|
);
|
||||||
|
|
||||||
|
existingSecret:
|
||||||
|
enabled: true
|
||||||
|
secretName: nextcloud-admin-secret
|
||||||
|
usernameKey: username
|
||||||
|
passwordKey: password
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualService handles routing
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
externalDatabase:
|
||||||
|
enabled: true
|
||||||
|
type: mysql
|
||||||
|
host: mariadb-nextcloud
|
||||||
|
port: 3306
|
||||||
|
user: nextcloud
|
||||||
|
database: nextcloud
|
||||||
|
existingSecret:
|
||||||
|
enabled: true
|
||||||
|
secretName: mariadb-nextcloud
|
||||||
|
passwordKey: password
|
||||||
|
usernameKey: user
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
accessMode: ReadWriteOnce
|
||||||
|
size: 50Gi
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: 1000m
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
enabled: false
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: rancher-oauth
|
||||||
|
namespace: cattle-system
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
name: vault-backend
|
||||||
|
target:
|
||||||
|
name: rancher-oauth-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: client-id
|
||||||
|
remoteRef:
|
||||||
|
key: secret/rancher-oauth
|
||||||
|
property: client-id
|
||||||
|
- secretKey: client-secret
|
||||||
|
remoteRef:
|
||||||
|
key: secret/rancher-oauth
|
||||||
|
property: client-secret
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: rancher
|
||||||
|
namespace: cattle-system
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- rancher.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: rancher.cattle-system.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# apps/rancher/values.yaml
|
||||||
|
# Rancher - Kubernetes Management Platform with Authentik SSO
|
||||||
|
|
||||||
|
hostname: rancher.kube.huskypup.net
|
||||||
|
|
||||||
|
# Exposed via Istio edge Gateway + VirtualService (apps/rancher/istio-virtualservice.yaml)
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# TLS terminates at Istio ingressgateway
|
||||||
|
tls: external
|
||||||
|
|
||||||
|
# Single replica for homelab (scale up if needed)
|
||||||
|
replicas: 1
|
||||||
|
|
||||||
|
# Storage class for Rancher's internal state
|
||||||
|
# Note: Rancher itself is mostly stateless; state is in etcd/k8s
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
# Allow Rancher to manage the local cluster
|
||||||
|
addLocal: "true"
|
||||||
|
|
||||||
|
# Audit logging
|
||||||
|
auditLog:
|
||||||
|
level: 1
|
||||||
|
maxAge: 7
|
||||||
|
maxBackup: 3
|
||||||
|
maxSize: 100
|
||||||
|
|
||||||
|
# Bootstrap password - will be rotated post-deploy via Authentik SSO
|
||||||
|
# This is used only for initial access before SSO is configured
|
||||||
|
bootstrapPassword: "ChangeMe-BootstrapOnly"
|
||||||
|
|
||||||
|
# Extra environment variables (not used for OIDC - configured via AuthConfig CRD post-deploy)
|
||||||
|
extraEnv: []
|
||||||
|
|
||||||
|
# Disable Rancher's bundled cert-manager (we already have it)
|
||||||
|
certmanager:
|
||||||
|
version: ""
|
||||||
|
|
||||||
|
# Feature flags
|
||||||
|
features: "multi-cluster-management=true"
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: pg-teslamate
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
imageName: ghcr.io/cloudnative-pg/postgresql:16
|
||||||
|
instances: 2
|
||||||
|
|
||||||
|
# Resource limits to prevent OOM
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "25m"
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
cpu: "250m"
|
||||||
|
|
||||||
|
# Spread replicas across different nodes
|
||||||
|
affinity:
|
||||||
|
topologyKey: kubernetes.io/hostname
|
||||||
|
|
||||||
|
storage:
|
||||||
|
size: 10Gi
|
||||||
|
storageClass: rook-ceph-block
|
||||||
|
|
||||||
|
primaryUpdateStrategy: unsupervised
|
||||||
|
|
||||||
|
# PostgreSQL configuration for better performance
|
||||||
|
postgresql:
|
||||||
|
parameters:
|
||||||
|
max_connections: "200"
|
||||||
|
shared_buffers: "512MB"
|
||||||
|
effective_cache_size: "1536MB"
|
||||||
|
maintenance_work_mem: "128MB"
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: "16MB"
|
||||||
|
default_statistics_target: "100"
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
work_mem: "2621kB"
|
||||||
|
min_wal_size: "1GB"
|
||||||
|
max_wal_size: "4GB"
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: teslamate
|
||||||
|
owner: teslamate
|
||||||
|
postInitSQL:
|
||||||
|
- ALTER USER teslamate WITH SUPERUSER
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS cube
|
||||||
|
- CREATE EXTENSION IF NOT EXISTS earthdistance
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enablePodMonitor: true
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
metadata:
|
||||||
|
name: teslamate-cnpg-secret
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
length: 42
|
||||||
|
digits: 5
|
||||||
|
symbols: 5
|
||||||
|
symbolCharacters: "-_$@"
|
||||||
|
noUpper: false
|
||||||
|
allowRepeat: true
|
||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: teslamate-cnpg-secret
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
# how often to rotate the DB password
|
||||||
|
refreshInterval: "24h"
|
||||||
|
target:
|
||||||
|
# This will merge the generated password into the existing pg-teslamate-app secret
|
||||||
|
name: pg-teslamate-app
|
||||||
|
creationPolicy: Merge
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
cnpg.io/reload: "true"
|
||||||
|
data:
|
||||||
|
# Override the password field with our ESO-generated password
|
||||||
|
password: "{{ .password }}"
|
||||||
|
dataFrom:
|
||||||
|
- sourceRef:
|
||||||
|
generatorRef:
|
||||||
|
apiVersion: generators.external-secrets.io/v1alpha1
|
||||||
|
kind: Password
|
||||||
|
name: teslamate-cnpg-secret
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: teslamate
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
- name: edge
|
||||||
|
namespace: gateway
|
||||||
|
sectionName: https
|
||||||
|
hostnames:
|
||||||
|
- teslamate.kube.huskypup.net
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: teslamate
|
||||||
|
port: 4000
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: teslamate-config
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
refreshInterval: 1h
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: teslamate-config-secret
|
||||||
|
creationPolicy: Owner
|
||||||
|
data:
|
||||||
|
- secretKey: encryption-key
|
||||||
|
remoteRef:
|
||||||
|
key: teslamate/config
|
||||||
|
property: encryption_key
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: networking.istio.io/v1beta1
|
||||||
|
kind: VirtualService
|
||||||
|
metadata:
|
||||||
|
name: teslamate
|
||||||
|
namespace: teslamate
|
||||||
|
spec:
|
||||||
|
hosts:
|
||||||
|
- teslamate.kube.huskypup.net
|
||||||
|
gateways:
|
||||||
|
- istio-system/edge
|
||||||
|
http:
|
||||||
|
- route:
|
||||||
|
- destination:
|
||||||
|
host: teslamate.teslamate.svc.cluster.local
|
||||||
|
port:
|
||||||
|
number: 4000
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
# Teslamate - Tesla data logger
|
||||||
|
# Uses CNPG PostgreSQL with auto-rotating passwords via ESO
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: teslamate/teslamate
|
||||||
|
tag: 1.30.1
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
env:
|
||||||
|
TZ: America/Chicago
|
||||||
|
|
||||||
|
# PostgreSQL configuration (uses CNPG-managed database)
|
||||||
|
DATABASE_HOST: pg-teslamate-rw.teslamate.svc
|
||||||
|
DATABASE_USER: teslamate
|
||||||
|
DATABASE_NAME: teslamate
|
||||||
|
|
||||||
|
# Database password from CNPG-generated secret
|
||||||
|
DATABASE_PASS:
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: pg-teslamate-app
|
||||||
|
key: password
|
||||||
|
|
||||||
|
# Encryption key from Vault
|
||||||
|
ENCRYPTION_KEY:
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: teslamate-config-secret
|
||||||
|
key: encryption-key
|
||||||
|
|
||||||
|
# MQTT settings (disabled by default, can enable later)
|
||||||
|
DISABLE_MQTT: "true"
|
||||||
|
|
||||||
|
# Virtual host for proper URL generation
|
||||||
|
VIRTUAL_HOST: teslamate.kube.huskypup.net
|
||||||
|
|
||||||
|
# Port configuration
|
||||||
|
PORT: "4000"
|
||||||
|
|
||||||
|
service:
|
||||||
|
main:
|
||||||
|
ports:
|
||||||
|
http:
|
||||||
|
port: 4000
|
||||||
|
|
||||||
|
# Ingress disabled - Istio VirtualService handles routing
|
||||||
|
ingress:
|
||||||
|
main:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
import:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Disable built-in postgresql (we use CNPG)
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
|
||||||
|
# Resource limits
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
cpu: "500m"
|
||||||
|
memory: "512Mi"
|
||||||
|
|
||||||
|
# Health probes
|
||||||
|
probes:
|
||||||
|
liveness:
|
||||||
|
enabled: true
|
||||||
|
custom: true
|
||||||
|
spec:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 4000
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readiness:
|
||||||
|
enabled: true
|
||||||
|
custom: true
|
||||||
|
spec:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 4000
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 2
|
||||||
|
startup:
|
||||||
|
enabled: true
|
||||||
|
custom: true
|
||||||
|
spec:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 4000
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 12
|
||||||
|
|
||||||
|
# Reloader annotations for auto-restart on secret changes
|
||||||
|
podAnnotations:
|
||||||
|
secret.reloader.stakater.com/reload: "pg-teslamate-app,teslamate-config-secret"
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: argocd
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "50"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://argoproj.github.io/argo-helm
|
||||||
|
chart: argo-cd
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/argocd/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/argocd/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: argocd
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: esphome
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://charts.gabe565.com
|
||||||
|
chart: esphome
|
||||||
|
targetRevision: 0.15.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/home-assistant/esphome/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: home-assistant
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: frigate
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://blakeblackshear.github.io/blakeshome-charts
|
||||||
|
chart: frigate
|
||||||
|
targetRevision: 7.8.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/frigate/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/frigate/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: frigate
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: gitlab
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "50"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://charts.gitlab.io
|
||||||
|
chart: gitlab
|
||||||
|
targetRevision: 7.7.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/gitlab/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/gitlab/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: gitlab
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: guacamole
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/guacamole/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: guacamole
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: home-assistant
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://geek-cookbook.github.io/charts/
|
||||||
|
chart: home-assistant
|
||||||
|
targetRevision: 13.5.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/home-assistant/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/home-assistant/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: home-assistant
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-app-routes
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "52"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/istio/manifests/apps
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: n8n
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "50"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://riatlas.github.io/chart__n8n
|
||||||
|
chart: n8n
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/n8n/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/n8n/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: n8n
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: nessus
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/nessus/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: nessus
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: nextcloud
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "50"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://nextcloud.github.io/helm/
|
||||||
|
chart: nextcloud
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/nextcloud/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/nextcloud/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: nextcloud
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: rancher
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "51"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://releases.rancher.com/server-charts/stable
|
||||||
|
chart: rancher
|
||||||
|
targetRevision: 2.13.2
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/rancher/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/rancher/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: cattle-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: teslamate
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "50"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: applications
|
||||||
|
sources:
|
||||||
|
- repoURL: https://geek-cookbook.github.io/charts/
|
||||||
|
chart: teslamate
|
||||||
|
targetRevision: 7.2.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/apps/teslamate/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/teslamate/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: teslamate
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: argocd-hook-sa
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-5"
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: argocd-hook-sa-admin
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "-5"
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: cluster-admin
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: argocd-hook-sa
|
||||||
|
namespace: argocd
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: authentik
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "23"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://charts.goauthentik.io
|
||||||
|
chart: authentik
|
||||||
|
targetRevision: 2026.2.1
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/authentik/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/authentik/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: authentik
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: cert-manager
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "2"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://charts.jetstack.io
|
||||||
|
chart: cert-manager
|
||||||
|
targetRevision: v1.13.2
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/cert-manager/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/cert-manager/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: cert-manager
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: checkov-scanner
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "43"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/checkov/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: checkov
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: cilium
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://helm.cilium.io
|
||||||
|
chart: cilium
|
||||||
|
targetRevision: 1.17.1
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/cilium/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/cilium/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kube-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: cnpg
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "12"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: https://cloudnative-pg.github.io/charts
|
||||||
|
chart: cloudnative-pg
|
||||||
|
targetRevision: "*"
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: cnpg-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: crowdsec
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "22"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://crowdsecurity.github.io/helm-charts
|
||||||
|
chart: crowdsec
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/crowdsec/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/crowdsec/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: crowdsec
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: envoy-edge
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "7"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/envoy-gateway/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: gateway
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: envoy-gateway
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "6"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://gateway.envoyproxy.io/charts
|
||||||
|
chart: gateway-helm
|
||||||
|
targetRevision: v1.6.3
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/envoy-gateway/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: envoy-gateway-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: external-dns
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "30"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://kubernetes-sigs.github.io/external-dns/
|
||||||
|
chart: external-dns
|
||||||
|
targetRevision: 1.20.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/external-dns/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/external-dns/manifests
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: external-dns
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: external-secrets
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "21"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://charts.external-secrets.io
|
||||||
|
chart: external-secrets
|
||||||
|
targetRevision: 0.20.4
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/external-secrets/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: external-secrets
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: grafana
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "41"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://grafana.github.io/helm-charts
|
||||||
|
chart: grafana
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/grafana/values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/grafana/manifests
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/grafana/dashboards
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: grafana
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-base
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "2"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: https://istio-release.storage.googleapis.com/charts
|
||||||
|
chart: base
|
||||||
|
targetRevision: 1.28.3
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-cni
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "3"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://istio-release.storage.googleapis.com/charts
|
||||||
|
chart: cni
|
||||||
|
targetRevision: 1.29.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/istio/cni-values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kube-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-edge
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "6"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/istio/manifests/edge
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-ingressgateway
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "5"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://istio-release.storage.googleapis.com/charts
|
||||||
|
chart: gateway
|
||||||
|
targetRevision: 1.29.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/istio/ingressgateway-values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istio-mesh-config
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "42"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
source:
|
||||||
|
repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
path: infrastructure/istio/manifests/mesh
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: istiod
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "4"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://istio-release.storage.googleapis.com/charts
|
||||||
|
chart: istiod
|
||||||
|
targetRevision: 1.29.0
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/istio/istiod-values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: istio-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: kiali-operator
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "42"
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: infrastructure
|
||||||
|
sources:
|
||||||
|
- repoURL: https://kiali.org/helm-charts
|
||||||
|
chart: kiali-operator
|
||||||
|
targetRevision: "*"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/infrastructure/kiali/operator-values.yaml
|
||||||
|
- repoURL: <GIT_REPO_URL>
|
||||||
|
targetRevision: main
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: kiali-operator
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user