Compare commits

...

44 Commits

Author SHA1 Message Date
Gitea Actions Bot f43e31a396 Auto-update README with current k8s applications
Keycloak Terraform / Terraform (pull_request) Successful in 13s
Generated by CI/CD workflow on 2026-05-19 12:45:51

This PR updates the README.md file with the current list of applications found in the k8s/ directory structure.
2026-05-19 12:45:51 +00:00
ab 4f82e5d15f Update k8s/core/postgresql/external-secrets.yaml
Check with kubeconform / lint (push) Successful in 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Auto-update README / Generate README and Create MR (push) Successful in 12s
2026-05-19 12:45:30 +00:00
ab 1366bba042 Update terraform/keycloak/terraform.tfvars
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 7s
Keycloak Terraform / Terraform (push) Successful in 20s
2026-05-19 12:40:51 +00:00
ab bdfa5349cf Disabled shitty keycloak theme
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
Keycloak Terraform / Terraform (push) Successful in 21s
2026-05-19 03:04:02 +03:00
ab 0cb0cf9291 Added keycloak theme
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 9s
Keycloak Terraform / Terraform (push) Failing after 14s
Check with kubeconform / lint (push) Successful in 8s
Auto-update README / Generate README and Create MR (push) Successful in 23s
2026-05-19 02:57:24 +03:00
ab 2cca415c2a Added keycloak theme 2026-05-19 02:57:18 +03:00
ab b5a033c043 Added WebAuth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Keycloak Terraform / Terraform (push) Successful in 17s
2026-05-19 02:36:05 +03:00
ab 11357657bb Added WebAuth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 13s
Keycloak Terraform / Terraform (push) Successful in 20s
2026-05-19 02:13:37 +03:00
ab 49e7b3b415 Added WebAuth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Keycloak Terraform / Terraform (push) Successful in 15s
2026-05-19 01:57:33 +03:00
ab 555969120e Added WebAuth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 10s
Keycloak Terraform / Terraform (push) Successful in 14s
2026-05-19 01:55:50 +03:00
ab 0b95b936ec Added WebAuth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Keycloak Terraform / Terraform (push) Successful in 18s
2026-05-19 01:54:42 +03:00
ab af4242950e Added OIDC auth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
Keycloak Terraform / Terraform (push) Successful in 16s
2026-05-19 00:40:43 +03:00
ab d9d2143a7c Added OIDC auth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
Keycloak Terraform / Terraform (push) Successful in 13s
2026-05-19 00:00:46 +03:00
ab d3d7810585 Added OIDC auth
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Keycloak Terraform / Terraform (push) Successful in 21s
2026-05-18 23:59:00 +03:00
ab 2afd3807d2 Added web-petting
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 5s
Keycloak Terraform / Terraform (push) Successful in 15s
2026-05-18 23:44:25 +03:00
ab 8749818a9c Added keycloak TF
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 9s
Keycloak Terraform / Terraform (push) Successful in 28s
2026-05-18 23:38:48 +03:00
ab cad267b8cd gitea test
Auto-update README / Generate README and Create MR (push) Successful in 22s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Failing after 37s
Check with kubeconform / lint (push) Failing after 10m44s
2026-05-18 23:00:20 +03:00
ab c340ad4be5 Merge branch 'main' of ssh://gt.hexor.cy:30022/ab/homelab
Auto-update README / Generate README and Create MR (push) Failing after 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Failing after 40s
Check with kubeconform / lint (push) Failing after 11m28s
2026-05-18 22:44:28 +03:00
ab 15cb85b11a gitea test 2026-05-18 22:44:10 +03:00
Ultradesu 0ae912c478 Moved web-petting to master
Check with kubeconform / lint (push) Successful in 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 10s
Auto-update README / Generate README and Create MR (push) Successful in 11s
2026-05-18 14:58:49 +03:00
Ultradesu 374a825514 Moved web-petting to spb
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 11s
Check with kubeconform / lint (push) Successful in 8s
Auto-update README / Generate README and Create MR (push) Successful in 11s
2026-05-18 14:56:21 +03:00
Ultradesu 790ba2c3de Moved argocd to keycloac 2026-05-18 14:54:51 +03:00
ab 4240cd61ad Update k8s/apps/pasarguard/deployment.yaml
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 8s
Check with kubeconform / lint (push) Successful in 7s
Auto-update README / Generate README and Create MR (push) Successful in 16s
2026-05-17 10:41:15 +00:00
ab a9f9c29679 Added recreate to web-petting
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 18s
Check with kubeconform / lint (push) Successful in 13s
Auto-update README / Generate README and Create MR (push) Successful in 9s
2026-05-14 16:18:55 +03:00
ab 70bb07529f Update k8s/apps/web-petting/deployment.yaml
Check with kubeconform / lint (push) Successful in 7s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 12s
Auto-update README / Generate README and Create MR (push) Successful in 11s
2026-05-14 13:15:20 +00:00
ab a4f6f4b06e Update k8s/apps/web-petting/deployment.yaml
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 13s
Check with kubeconform / lint (push) Successful in 7s
Auto-update README / Generate README and Create MR (push) Successful in 13s
2026-05-13 14:21:17 +00:00
Ultradesu 688a91d04f Enabled dex for argocd
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 18s
Check with kubeconform / lint (push) Successful in 6s
Auto-update README / Generate README and Create MR (push) Successful in 18s
2026-05-13 14:23:56 +01:00
Ultradesu 4212cdc26e Added мурняня.рф
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 11s
Check with kubeconform / lint (push) Successful in 9s
Auto-update README / Generate README and Create MR (push) Successful in 22s
2026-05-13 14:07:58 +01:00
Ultradesu f33de7c78c fix 2026-05-13 14:06:09 +01:00
ab d0d76fcfd2 Update k8s/apps/web-petting/deployment.yaml
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 12s
Check with kubeconform / lint (push) Successful in 10s
Auto-update README / Generate README and Create MR (push) Successful in 15s
2026-05-12 13:49:01 +00:00
ab ec649d8ffd Update k8s/apps/web-petting/deployment.yaml
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 10s
Check with kubeconform / lint (push) Successful in 8s
Auto-update README / Generate README and Create MR (push) Successful in 13s
2026-05-11 12:48:25 +00:00
ab 84a3d1880b Update k8s/apps/web-petting/deployment.yaml
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 7s
Check with kubeconform / lint (push) Successful in 8s
Auto-update README / Generate README and Create MR (push) Successful in 23s
2026-05-11 12:32:18 +00:00
ab 9956a87818 Update k8s/apps/web-petting/deployment.yaml
Check with kubeconform / lint (push) Successful in 11s
Auto-update README / Generate README and Create MR (push) Successful in 27s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Failing after 12m28s
2026-05-11 11:57:19 +00:00
ab 323bc0f31b Update k8s/apps/web-petting/deployment.yaml
Check with kubeconform / lint (push) Successful in 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 17s
Auto-update README / Generate README and Create MR (push) Successful in 18s
2026-05-11 10:43:22 +00:00
ab 64d8b027e9 Update k8s/apps/web-petting/deployment.yaml
Check with kubeconform / lint (push) Successful in 16s
Auto-update README / Generate README and Create MR (push) Successful in 23s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Failing after 12m17s
2026-05-11 10:42:28 +00:00
ab 6c13aec9c1 Disable authentik CI
Terraform / Terraform (push) Has been skipped
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
2026-05-06 10:13:27 +01:00
Ultradesu f04c8d7359 fix grafana
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 7s
Check with kubeconform / lint (push) Successful in 7s
Auto-update README / Generate README and Create MR (push) Successful in 13s
2026-05-05 19:40:00 +01:00
Ultradesu b5906b613a fix grafana
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 7s
Check with kubeconform / lint (push) Successful in 7s
Auto-update README / Generate README and Create MR (push) Successful in 10s
2026-05-05 19:33:41 +01:00
Ultradesu c0f3d2f7d6 Added grafana to keycloak. clean up prom-stak
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
Check with kubeconform / lint (push) Successful in 11s
Auto-update README / Generate README and Create MR (push) Successful in 7s
2026-05-05 19:28:33 +01:00
ab 73ce3ae97f Update k8s/core/prom-stack/prom-values.yaml
Check with kubeconform / lint (push) Successful in 7s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 11s
Auto-update README / Generate README and Create MR (push) Successful in 11s
2026-05-05 18:13:34 +00:00
Ultradesu 2778f6582c Added grafana to keycloak. clean up prom-stak
Check with kubeconform / lint (push) Successful in 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 12s
Auto-update README / Generate README and Create MR (push) Successful in 9s
2026-05-05 19:06:01 +01:00
Ultradesu 5f94563038 Fixed promstak version
Check with kubeconform / lint (push) Successful in 6s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 6s
Auto-update README / Generate README and Create MR (push) Successful in 10s
2026-05-05 18:59:19 +01:00
Ultradesu cd45c64457 added auth-proxy dashboard
Check with kubeconform / lint (push) Successful in 8s
Update Kubernetes Services Wiki / Generate and Update K8s Wiki (push) Successful in 13s
Auto-update README / Generate README and Create MR (push) Successful in 11s
2026-05-05 18:57:05 +01:00
Ultradesu cdf836afd3 added auth-proxy dashboard 2026-05-05 18:57:02 +01:00
26 changed files with 1452 additions and 84877 deletions
+14 -108
View File
@@ -1,10 +1,10 @@
name: 'Terraform'
name: 'Keycloak Terraform'
on:
push:
branches: [ "main" ]
paths:
- 'terraform/authentik/**'
- 'terraform/keycloak/**'
pull_request:
permissions:
@@ -29,119 +29,25 @@ jobs:
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
- name: Setup kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBECONFIG }}" > ~/.kube/config
chmod 600 ~/.kube/config
- name: Terraform Init
env:
TF_VAR_authentik_token: ${{ secrets.AUTHENTIK_TOKEN }}
run: terraform init
working-directory: ./terraform/authentik
working-directory: ./terraform/keycloak
- name: Terraform Format
env:
TF_VAR_authentik_token: ${{ secrets.AUTHENTIK_TOKEN }}
run: terraform fmt -check
continue-on-error: true
working-directory: ./terraform/authentik
working-directory: ./terraform/keycloak
- name: Terraform Apply
env:
TF_VAR_authentik_token: ${{ secrets.AUTHENTIK_TOKEN }}
TF_VAR_keycloak_client_secret: ${{ secrets.KEYCLOAK_CLIENT_SECRET }}
TF_VAR_google_client_id: ${{ secrets.GOOGLE_CLIENT_ID }}
TF_VAR_google_client_secret: ${{ secrets.GOOGLE_CLIENT_SECRET }}
run: terraform apply -input=false -auto-approve -parallelism=100
working-directory: ./terraform/authentik
- name: Generate Wiki Content
if: success()
continue-on-error: true
env:
TF_VAR_authentik_token: ${{ secrets.AUTHENTIK_TOKEN }}
run: |
echo "📋 Starting Wiki generation..."
cd ./terraform/authentik
# Get terraform output
echo "🔍 Generating Terraform output..."
terraform output -json applications_for_wiki > terraform-raw-output.json 2>&1
# Process output to extract clean JSON
echo "📤 Processing Terraform output..."
python3 ../../.gitea/scripts/process-terraform-output.py terraform-raw-output.json terraform-output.json
# Run wiki generation
echo "📊 Running wiki generation script..."
if python3 ../../.gitea/scripts/generate-apps-wiki.py terraform-output.json; then
echo "✅ Wiki content generated successfully"
else
echo "⚠️ Wiki generation failed, retrying with debug..."
python3 ../../.gitea/scripts/generate-apps-wiki.py terraform-output.json --debug || echo "⚠️ Wiki generation failed"
fi
# Check results
if [ -f "Applications.md" ]; then
echo "✅ Wiki file created: $(wc -l < Applications.md) lines"
else
echo "⚠️ Wiki content not generated"
exit 0
fi
working-directory: ./
- name: Upload Wiki to Gitea
if: success()
continue-on-error: true
run: |
cd ./terraform/authentik
# Set variables
GITEA_URL="${{ secrets.GT_URL }}"
GITEA_TOKEN="${{ secrets.GT_WIKI_TOKEN }}"
GITEA_OWNER="${{ secrets.GT_OWNER }}"
GITEA_REPO="${{ secrets.GT_REPO }}"
# Debug variables (without exposing token)
echo "🔍 Checking variables..."
echo "GITEA_URL: ${GITEA_URL:-NOT SET}"
echo "GITEA_OWNER: ${GITEA_OWNER:-NOT SET}"
echo "GITEA_REPO: ${GITEA_REPO:-NOT SET}"
echo "GITEA_TOKEN: $(if [ -n "$GITEA_TOKEN" ]; then echo "SET"; else echo "NOT SET"; fi)"
# Check if file exists
if [ ! -f "Applications.md" ]; then
echo "⚠️ Applications.md not found, skipping wiki update"
exit 0
fi
echo "📤 Uploading to Gitea Wiki..."
# Encode content to base64
CONTENT=$(base64 -w 0 Applications.md)
# Check if wiki page exists
WIKI_PAGE_EXISTS=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: token $GITEA_TOKEN" \
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Applications" || echo "000")
if [ "$WIKI_PAGE_EXISTS" = "200" ]; then
echo "📝 Updating existing wiki page..."
curl -X PATCH \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Applications\",
\"content_base64\": \"$CONTENT\",
\"message\": \"Update applications list from CI/CD [$(date)]\"
}" \
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/page/Applications" || echo "⚠️ Wiki update failed"
else
echo "📄 Creating new wiki page..."
curl -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"Applications\",
\"content_base64\": \"$CONTENT\",
\"message\": \"Create applications list from CI/CD [$(date)]\"
}" \
"$GITEA_URL/api/v1/repos/$GITEA_OWNER/$GITEA_REPO/wiki/new" || echo "⚠️ Wiki creation failed"
fi
echo "✅ Wiki update process completed"
working-directory: ./
working-directory: ./terraform/keycloak
+6
View File
@@ -13,10 +13,13 @@ ArgoCD homelab project
| Application | Status |
| :--- | :---: |
| **argocd** | [![argocd](https://ag.hexor.cy/api/badge?name=argocd&revision=true)](https://ag.hexor.cy/applications/argocd/argocd) |
| **auth-proxy** | [![auth-proxy](https://ag.hexor.cy/api/badge?name=auth-proxy&revision=true)](https://ag.hexor.cy/applications/argocd/auth-proxy) |
| **authentik** | [![authentik](https://ag.hexor.cy/api/badge?name=authentik&revision=true)](https://ag.hexor.cy/applications/argocd/authentik) |
| **cert-manager** | [![cert-manager](https://ag.hexor.cy/api/badge?name=cert-manager&revision=true)](https://ag.hexor.cy/applications/argocd/cert-manager) |
| **external-secrets** | [![external-secrets](https://ag.hexor.cy/api/badge?name=external-secrets&revision=true)](https://ag.hexor.cy/applications/argocd/external-secrets) |
| **gpu** | [![gpu](https://ag.hexor.cy/api/badge?name=gpu&revision=true)](https://ag.hexor.cy/applications/argocd/gpu) |
| **kanidm** | [![kanidm](https://ag.hexor.cy/api/badge?name=kanidm&revision=true)](https://ag.hexor.cy/applications/argocd/kanidm) |
| **keycloak** | [![keycloak](https://ag.hexor.cy/api/badge?name=keycloak&revision=true)](https://ag.hexor.cy/applications/argocd/keycloak) |
| **kube-system-custom** | [![kube-system-custom](https://ag.hexor.cy/api/badge?name=kube-system-custom&revision=true)](https://ag.hexor.cy/applications/argocd/kube-system-custom) |
| **kubernetes-dashboard** | [![kubernetes-dashboard](https://ag.hexor.cy/api/badge?name=kubernetes-dashboard&revision=true)](https://ag.hexor.cy/applications/argocd/kubernetes-dashboard) |
| **longhorn** | [![longhorn](https://ag.hexor.cy/api/badge?name=longhorn&revision=true)](https://ag.hexor.cy/applications/argocd/longhorn) |
@@ -62,9 +65,12 @@ ArgoCD homelab project
| **sonarr-stack** | [![sonarr-stack](https://ag.hexor.cy/api/badge?name=sonarr-stack&revision=true)](https://ag.hexor.cy/applications/argocd/sonarr-stack) |
| **stirling-pdf** | [![stirling-pdf](https://ag.hexor.cy/api/badge?name=stirling-pdf&revision=true)](https://ag.hexor.cy/applications/argocd/stirling-pdf) |
| **syncthing** | [![syncthing](https://ag.hexor.cy/api/badge?name=syncthing&revision=true)](https://ag.hexor.cy/applications/argocd/syncthing) |
| **teamspeak** | [![teamspeak](https://ag.hexor.cy/api/badge?name=teamspeak&revision=true)](https://ag.hexor.cy/applications/argocd/teamspeak) |
| **tg-bots** | [![tg-bots](https://ag.hexor.cy/api/badge?name=tg-bots&revision=true)](https://ag.hexor.cy/applications/argocd/tg-bots) |
| **vaultwarden** | [![vaultwarden](https://ag.hexor.cy/api/badge?name=vaultwarden&revision=true)](https://ag.hexor.cy/applications/argocd/vaultwarden) |
| **vpn** | [![vpn](https://ag.hexor.cy/api/badge?name=vpn&revision=true)](https://ag.hexor.cy/applications/argocd/vpn) |
| **web-petting** | [![web-petting](https://ag.hexor.cy/api/badge?name=web-petting&revision=true)](https://ag.hexor.cy/applications/argocd/web-petting) |
| **wedding** | [![wedding](https://ag.hexor.cy/api/badge?name=wedding&revision=true)](https://ag.hexor.cy/applications/argocd/wedding) |
| **xandikos** | [![xandikos](https://ag.hexor.cy/api/badge?name=xandikos&revision=true)](https://ag.hexor.cy/applications/argocd/xandikos) |
</td>
+1 -1
View File
@@ -1,5 +1,5 @@
---
image: &image 'pasarguard/panel:v3.1.0'
image: &image 'pasarguard/panel:v4.0.2'
apiVersion: apps/v1
kind: Deployment
metadata:
+4 -1
View File
@@ -6,6 +6,8 @@ metadata:
app: web-petting
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: web-petting
@@ -16,13 +18,14 @@ spec:
spec:
nodeSelector:
kubernetes.io/os: linux
kubernetes.io/hostname: master.tail2fe2d.ts.net
volumes:
- name: data
persistentVolumeClaim:
claimName: web-petting-data
containers:
- name: web-petting
image: ultradesu/web-petting:0.1.0
image: ultradesu/web-petting:latest
imagePullPolicy: Always
args:
# - "tail"
+13
View File
@@ -20,8 +20,21 @@ spec:
name: web-petting
port:
number: 80
- host: xn--l1acako8eb.xn--p1ai
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-petting
port:
number: 80
tls:
- secretName: web-petting-tls
hosts:
- pet.hexor.cy
- secretName: web-petting-murnyanya-tls
hosts:
- xn--l1acako8eb.xn--p1ai
+17 -9
View File
@@ -23,14 +23,22 @@ configs:
admin.enabled: false
statusbadge.enabled: true
timeout.reconciliation: 60s
oidc.config: |
name: Keycloak
issuer: https://auth.hexor.cy/auth/realms/hexor
clientID: $oidc-creds:id
clientSecret: $oidc-creds:secret
requestedScopes: ["openid", "profile", "email", "offline_access"]
requestedIDTokenClaims: {"groups": {"essential": true}}
refreshTokenThreshold: 2m
dex.config: |
connectors:
- type: oidc
id: keycloak
name: Keycloak
config:
issuer: https://auth.hexor.cy/auth/realms/hexor
clientID: $oidc-creds:id
clientSecret: $oidc-creds:secret
insecureEnableGroups: true
scopes:
- openid
- profile
- email
- offline_access
getUserInfo: true
rbac:
create: true
policy.default: ""
@@ -64,7 +72,7 @@ dex:
replicas: 1
nodeSelector:
<<: *nodeSelector
enabled: false
enabled: true
# Standard Redis disabled because Redis HA is enabled
redis:
+2
View File
@@ -35,4 +35,6 @@ spec:
dnsZones:
- "*.hexor.cy"
- "hexor.cy"
- "*.xn--l1acako8eb.xn--p1ai"
- "xn--l1acako8eb.xn--p1ai"
@@ -0,0 +1,366 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: keycloak-hacker-theme
namespace: keycloak
data:
theme.properties: |
parent=keycloak.v2
import=common/keycloak
styles=css/hacker.css
hacker.css: |
/* ============================================================
HEXOR — Hacker Terminal Theme for Keycloak
============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&display=swap');
:root {
--hk-bg: #0a0a0a;
--hk-panel: #0d0d0d;
--hk-border: #00ff4180;
--hk-green: #00ff41;
--hk-green-dim: #00cc33;
--hk-green-glow: rgba(0, 255, 65, 0.15);
--hk-green-glow-strong: rgba(0, 255, 65, 0.35);
--hk-cyan: #00e5ff;
--hk-red: #ff3333;
--hk-text: #b0ffb0;
--hk-text-dim: #5a8a5a;
--hk-input-bg: #050505;
--hk-font: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace;
}
/* -- Force dark always --------------------------------------------------- */
html.login-pf,
html.login-pf.pf-v5-theme-dark {
color-scheme: dark;
}
/* -- Background: scanlines + CRT ---------------------------------------- */
body#keycloak-bg {
font-family: var(--hk-font) !important;
background: var(--hk-bg) !important;
color: var(--hk-text) !important;
min-height: 100vh;
position: relative;
}
body#keycloak-bg::before {
content: '';
position: fixed;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 255, 65, 0.03) 2px,
rgba(0, 255, 65, 0.03) 4px
);
pointer-events: none;
z-index: 9999;
}
/* -- Login container ----------------------------------------------------- */
.pf-v5-c-login {
background: transparent !important;
}
.pf-v5-c-login__container {
max-width: 480px !important;
}
/* -- Header / Brand ------------------------------------------------------ */
#kc-header-wrapper {
font-family: var(--hk-font) !important;
color: var(--hk-green) !important;
text-shadow: 0 0 10px var(--hk-green), 0 0 30px var(--hk-green-glow);
font-size: 1.5rem !important;
letter-spacing: 0.15em;
text-transform: uppercase;
}
#kc-header-wrapper .kc-logo-text span::before {
content: '> ';
opacity: 0.6;
}
/* -- Main card ----------------------------------------------------------- */
.pf-v5-c-login__main {
background: var(--hk-panel) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
box-shadow:
0 0 15px var(--hk-green-glow),
inset 0 0 30px rgba(0, 0, 0, 0.5) !important;
}
/* -- Title --------------------------------------------------------------- */
h1#kc-page-title,
.pf-v5-c-title {
font-family: var(--hk-font) !important;
color: var(--hk-green) !important;
text-shadow: 0 0 8px var(--hk-green-glow);
font-weight: 600 !important;
font-size: 1.25rem !important;
letter-spacing: 0.05em;
}
/* -- Labels -------------------------------------------------------------- */
.pf-v5-c-form__label-text {
font-family: var(--hk-font) !important;
color: var(--hk-green-dim) !important;
font-size: 0.85rem !important;
text-transform: uppercase;
letter-spacing: 0.08em;
}
/* -- Input fields -------------------------------------------------------- */
.pf-v5-c-form-control {
background-color: var(--hk-input-bg) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
font-size: 0.9rem !important;
caret-color: var(--hk-green);
transition: border-color 0.2s, box-shadow 0.2s;
}
.pf-v5-c-form-control:focus-within,
.pf-v5-c-form-control:focus {
border-color: var(--hk-green) !important;
box-shadow: 0 0 8px var(--hk-green-glow), inset 0 0 4px var(--hk-green-glow) !important;
outline: none !important;
}
.pf-v5-c-form-control input {
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-form-control input::placeholder {
color: var(--hk-text-dim) !important;
}
/* -- Primary button (Sign In) -------------------------------------------- */
.pf-v5-c-button.pf-m-primary {
background: transparent !important;
border: 1px solid var(--hk-green) !important;
border-radius: 0 !important;
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
font-weight: 600 !important;
text-transform: uppercase;
letter-spacing: 0.12em;
font-size: 0.9rem !important;
transition: all 0.2s;
position: relative;
overflow: hidden;
}
.pf-v5-c-button.pf-m-primary:hover {
background: var(--hk-green-glow) !important;
box-shadow: 0 0 15px var(--hk-green-glow-strong), inset 0 0 15px var(--hk-green-glow) !important;
color: #fff !important;
text-shadow: 0 0 5px var(--hk-green);
}
/* -- Secondary button (Try Another Way, Passkey) ------------------------- */
.pf-v5-c-button.pf-m-secondary {
background: transparent !important;
border: 1px solid var(--hk-cyan) !important;
border-radius: 0 !important;
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
text-transform: uppercase;
letter-spacing: 0.1em;
font-size: 0.85rem !important;
transition: all 0.2s;
}
.pf-v5-c-button.pf-m-secondary:hover {
background: rgba(0, 229, 255, 0.1) !important;
box-shadow: 0 0 12px rgba(0, 229, 255, 0.3) !important;
color: #fff !important;
}
/* -- Passkey authenticate button ----------------------------------------- */
#authenticateWebAuthnButton {
background: transparent !important;
border: 1px solid var(--hk-cyan) !important;
border-radius: 0 !important;
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
text-transform: uppercase;
letter-spacing: 0.1em;
font-size: 0.85rem !important;
padding: 0.75rem 1rem;
display: block;
width: 100%;
text-align: center;
text-decoration: none;
transition: all 0.2s;
margin-top: 1rem;
}
#authenticateWebAuthnButton::before {
content: '\f084 ';
font-family: 'Font Awesome 6 Free', 'FontAwesome';
font-weight: 900;
}
#authenticateWebAuthnButton:hover {
background: rgba(0, 229, 255, 0.1) !important;
box-shadow: 0 0 15px rgba(0, 229, 255, 0.3), inset 0 0 10px rgba(0, 229, 255, 0.1) !important;
color: #fff !important;
text-shadow: 0 0 5px var(--hk-cyan);
}
/* -- Show password button ------------------------------------------------ */
.pf-v5-c-button.pf-m-control {
background: var(--hk-input-bg) !important;
border: 1px solid var(--hk-border) !important;
border-left: none !important;
border-radius: 0 !important;
color: var(--hk-text-dim) !important;
}
.pf-v5-c-button.pf-m-control:hover {
color: var(--hk-green) !important;
}
/* -- Social providers (Google, etc) -------------------------------------- */
.pf-v5-c-login__main-footer {
border-top: 1px solid var(--hk-border) !important;
}
.kc-social-section .pf-v5-c-button.pf-m-secondary {
border-color: var(--hk-text-dim) !important;
color: var(--hk-text) !important;
}
.kc-social-section .pf-v5-c-button.pf-m-secondary:hover {
border-color: var(--hk-green) !important;
color: var(--hk-green) !important;
box-shadow: 0 0 10px var(--hk-green-glow) !important;
}
/* -- Try another way link ------------------------------------------------ */
#try-another-way {
color: var(--hk-cyan) !important;
text-decoration: none !important;
font-family: var(--hk-font) !important;
}
#try-another-way:hover {
text-shadow: 0 0 8px rgba(0, 229, 255, 0.5);
}
/* -- Links --------------------------------------------------------------- */
a {
color: var(--hk-cyan) !important;
text-decoration: none;
transition: text-shadow 0.2s;
}
a:hover {
text-shadow: 0 0 6px rgba(0, 229, 255, 0.4);
}
/* -- Alerts / messages --------------------------------------------------- */
.pf-v5-c-alert {
background: rgba(0, 255, 65, 0.05) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-alert.pf-m-danger {
border-color: var(--hk-red) !important;
background: rgba(255, 51, 51, 0.05) !important;
}
.pf-v5-c-alert__title {
color: var(--hk-text) !important;
font-family: var(--hk-font) !important;
}
/* -- Checkbox (Remember me) ---------------------------------------------- */
.pf-v5-c-check__label {
color: var(--hk-text-dim) !important;
font-family: var(--hk-font) !important;
font-size: 0.8rem !important;
}
/* -- Helper text (Forgot password, etc.) --------------------------------- */
.pf-v5-c-helper-text .pf-v5-c-button.pf-m-link {
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
font-size: 0.8rem !important;
}
/* -- Select auth list (Try another way options) -------------------------- */
.select-auth-container {
background: var(--hk-panel) !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-data-list__item {
border-color: var(--hk-border) !important;
background: transparent !important;
}
.pf-v5-c-data-list__item:hover {
background: var(--hk-green-glow) !important;
}
.select-auth-box-headline {
color: var(--hk-green) !important;
}
.select-auth-box-desc {
color: var(--hk-text-dim) !important;
}
/* -- Footer -------------------------------------------------------------- */
.pf-v5-c-login__main-footer-band {
background: transparent !important;
border-top: 1px solid var(--hk-border) !important;
}
/* -- Language selector --------------------------------------------------- */
select#login-select-toggle {
background: var(--hk-input-bg) !important;
color: var(--hk-green) !important;
border-color: var(--hk-border) !important;
font-family: var(--hk-font) !important;
}
/* -- Blinking cursor animation for header -------------------------------- */
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
#kc-header-wrapper::after {
content: '_';
animation: blink 1s step-end infinite;
color: var(--hk-green);
}
/* -- Subtle CRT flicker ------------------------------------------------- */
@keyframes flicker {
0% { opacity: 0.97; }
5% { opacity: 0.95; }
10% { opacity: 0.98; }
15% { opacity: 0.96; }
20% { opacity: 0.99; }
100% { opacity: 0.98; }
}
.pf-v5-c-login__main {
animation: flicker 4s infinite;
}
+1
View File
@@ -4,6 +4,7 @@ kind: Kustomization
resources:
- app.yaml
- external-secrets.yaml
- hacker-theme-configmap.yaml
helmCharts:
- name: keycloakx
@@ -0,0 +1,353 @@
/* ============================================================
HEXOR — Hacker Terminal Theme for Keycloak
============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&display=swap');
:root {
--hk-bg: #0a0a0a;
--hk-panel: #0d0d0d;
--hk-border: #00ff4180;
--hk-green: #00ff41;
--hk-green-dim: #00cc33;
--hk-green-glow: rgba(0, 255, 65, 0.15);
--hk-green-glow-strong: rgba(0, 255, 65, 0.35);
--hk-cyan: #00e5ff;
--hk-red: #ff3333;
--hk-text: #b0ffb0;
--hk-text-dim: #5a8a5a;
--hk-input-bg: #050505;
--hk-font: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace;
}
/* -- Force dark always --------------------------------------------------- */
html.login-pf,
html.login-pf.pf-v5-theme-dark {
color-scheme: dark;
}
/* -- Background: scanlines + CRT ---------------------------------------- */
body#keycloak-bg {
font-family: var(--hk-font) !important;
background: var(--hk-bg) !important;
color: var(--hk-text) !important;
min-height: 100vh;
position: relative;
}
body#keycloak-bg::before {
content: '';
position: fixed;
inset: 0;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0, 255, 65, 0.03) 2px,
rgba(0, 255, 65, 0.03) 4px
);
pointer-events: none;
z-index: 9999;
}
/* -- Login container ----------------------------------------------------- */
.pf-v5-c-login {
background: transparent !important;
}
.pf-v5-c-login__container {
max-width: 480px !important;
}
/* -- Header / Brand ------------------------------------------------------ */
#kc-header-wrapper {
font-family: var(--hk-font) !important;
color: var(--hk-green) !important;
text-shadow: 0 0 10px var(--hk-green), 0 0 30px var(--hk-green-glow);
font-size: 1.5rem !important;
letter-spacing: 0.15em;
text-transform: uppercase;
}
#kc-header-wrapper .kc-logo-text span::before {
content: '> ';
opacity: 0.6;
}
/* -- Main card ----------------------------------------------------------- */
.pf-v5-c-login__main {
background: var(--hk-panel) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
box-shadow:
0 0 15px var(--hk-green-glow),
inset 0 0 30px rgba(0, 0, 0, 0.5) !important;
}
/* -- Title --------------------------------------------------------------- */
h1#kc-page-title,
.pf-v5-c-title {
font-family: var(--hk-font) !important;
color: var(--hk-green) !important;
text-shadow: 0 0 8px var(--hk-green-glow);
font-weight: 600 !important;
font-size: 1.25rem !important;
letter-spacing: 0.05em;
}
/* -- Labels -------------------------------------------------------------- */
.pf-v5-c-form__label-text {
font-family: var(--hk-font) !important;
color: var(--hk-green-dim) !important;
font-size: 0.85rem !important;
text-transform: uppercase;
letter-spacing: 0.08em;
}
/* -- Input fields -------------------------------------------------------- */
.pf-v5-c-form-control {
background-color: var(--hk-input-bg) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
font-size: 0.9rem !important;
caret-color: var(--hk-green);
transition: border-color 0.2s, box-shadow 0.2s;
}
.pf-v5-c-form-control:focus-within,
.pf-v5-c-form-control:focus {
border-color: var(--hk-green) !important;
box-shadow: 0 0 8px var(--hk-green-glow), inset 0 0 4px var(--hk-green-glow) !important;
outline: none !important;
}
.pf-v5-c-form-control input {
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-form-control input::placeholder {
color: var(--hk-text-dim) !important;
}
/* -- Primary button (Sign In) -------------------------------------------- */
.pf-v5-c-button.pf-m-primary {
background: transparent !important;
border: 1px solid var(--hk-green) !important;
border-radius: 0 !important;
color: var(--hk-green) !important;
font-family: var(--hk-font) !important;
font-weight: 600 !important;
text-transform: uppercase;
letter-spacing: 0.12em;
font-size: 0.9rem !important;
transition: all 0.2s;
position: relative;
overflow: hidden;
}
.pf-v5-c-button.pf-m-primary:hover {
background: var(--hk-green-glow) !important;
box-shadow: 0 0 15px var(--hk-green-glow-strong), inset 0 0 15px var(--hk-green-glow) !important;
color: #fff !important;
text-shadow: 0 0 5px var(--hk-green);
}
/* -- Secondary button (Try Another Way, Passkey) ------------------------- */
.pf-v5-c-button.pf-m-secondary {
background: transparent !important;
border: 1px solid var(--hk-cyan) !important;
border-radius: 0 !important;
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
text-transform: uppercase;
letter-spacing: 0.1em;
font-size: 0.85rem !important;
transition: all 0.2s;
}
.pf-v5-c-button.pf-m-secondary:hover {
background: rgba(0, 229, 255, 0.1) !important;
box-shadow: 0 0 12px rgba(0, 229, 255, 0.3) !important;
color: #fff !important;
}
/* -- Passkey authenticate button ----------------------------------------- */
#authenticateWebAuthnButton {
background: transparent !important;
border: 1px solid var(--hk-cyan) !important;
border-radius: 0 !important;
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
text-transform: uppercase;
letter-spacing: 0.1em;
font-size: 0.85rem !important;
padding: 0.75rem 1rem;
display: block;
width: 100%;
text-align: center;
text-decoration: none;
transition: all 0.2s;
margin-top: 1rem;
}
#authenticateWebAuthnButton::before {
content: '\f084 ';
font-family: 'Font Awesome 6 Free', 'FontAwesome';
font-weight: 900;
}
#authenticateWebAuthnButton:hover {
background: rgba(0, 229, 255, 0.1) !important;
box-shadow: 0 0 15px rgba(0, 229, 255, 0.3), inset 0 0 10px rgba(0, 229, 255, 0.1) !important;
color: #fff !important;
text-shadow: 0 0 5px var(--hk-cyan);
}
/* -- Show password button ------------------------------------------------ */
.pf-v5-c-button.pf-m-control {
background: var(--hk-input-bg) !important;
border: 1px solid var(--hk-border) !important;
border-left: none !important;
border-radius: 0 !important;
color: var(--hk-text-dim) !important;
}
.pf-v5-c-button.pf-m-control:hover {
color: var(--hk-green) !important;
}
/* -- Social providers (Google, etc) -------------------------------------- */
.pf-v5-c-login__main-footer {
border-top: 1px solid var(--hk-border) !important;
}
.kc-social-section .pf-v5-c-button.pf-m-secondary {
border-color: var(--hk-text-dim) !important;
color: var(--hk-text) !important;
}
.kc-social-section .pf-v5-c-button.pf-m-secondary:hover {
border-color: var(--hk-green) !important;
color: var(--hk-green) !important;
box-shadow: 0 0 10px var(--hk-green-glow) !important;
}
/* -- Try another way link ------------------------------------------------ */
#try-another-way {
color: var(--hk-cyan) !important;
text-decoration: none !important;
font-family: var(--hk-font) !important;
}
#try-another-way:hover {
text-shadow: 0 0 8px rgba(0, 229, 255, 0.5);
}
/* -- Links --------------------------------------------------------------- */
a {
color: var(--hk-cyan) !important;
text-decoration: none;
transition: text-shadow 0.2s;
}
a:hover {
text-shadow: 0 0 6px rgba(0, 229, 255, 0.4);
}
/* -- Alerts / messages --------------------------------------------------- */
.pf-v5-c-alert {
background: rgba(0, 255, 65, 0.05) !important;
border: 1px solid var(--hk-border) !important;
border-radius: 0 !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-alert.pf-m-danger {
border-color: var(--hk-red) !important;
background: rgba(255, 51, 51, 0.05) !important;
}
.pf-v5-c-alert__title {
color: var(--hk-text) !important;
font-family: var(--hk-font) !important;
}
/* -- Checkbox (Remember me) ---------------------------------------------- */
.pf-v5-c-check__label {
color: var(--hk-text-dim) !important;
font-family: var(--hk-font) !important;
font-size: 0.8rem !important;
}
/* -- Helper text (Forgot password, etc.) --------------------------------- */
.pf-v5-c-helper-text .pf-v5-c-button.pf-m-link {
color: var(--hk-cyan) !important;
font-family: var(--hk-font) !important;
font-size: 0.8rem !important;
}
/* -- Select auth list (Try another way options) -------------------------- */
.select-auth-container {
background: var(--hk-panel) !important;
font-family: var(--hk-font) !important;
}
.pf-v5-c-data-list__item {
border-color: var(--hk-border) !important;
background: transparent !important;
}
.pf-v5-c-data-list__item:hover {
background: var(--hk-green-glow) !important;
}
.select-auth-box-headline {
color: var(--hk-green) !important;
}
.select-auth-box-desc {
color: var(--hk-text-dim) !important;
}
/* -- Footer -------------------------------------------------------------- */
.pf-v5-c-login__main-footer-band {
background: transparent !important;
border-top: 1px solid var(--hk-border) !important;
}
/* -- Language selector --------------------------------------------------- */
select#login-select-toggle {
background: var(--hk-input-bg) !important;
color: var(--hk-green) !important;
border-color: var(--hk-border) !important;
font-family: var(--hk-font) !important;
}
/* -- Blinking cursor animation for header -------------------------------- */
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
#kc-header-wrapper::after {
content: '_';
animation: blink 1s step-end infinite;
color: var(--hk-green);
}
/* -- Subtle CRT flicker ------------------------------------------------- */
@keyframes flicker {
0% { opacity: 0.97; }
5% { opacity: 0.95; }
10% { opacity: 0.98; }
15% { opacity: 0.96; }
20% { opacity: 0.99; }
100% { opacity: 0.98; }
}
.pf-v5-c-login__main {
animation: flicker 4s infinite;
}
@@ -0,0 +1,4 @@
parent=keycloak.v2
import=common/keycloak
styles=css/hacker.css
+13
View File
@@ -21,6 +21,19 @@ extraEnv: |
- name: JAVA_OPTS_APPEND
value: "-Djgroups.dns.query=keycloak-headless.keycloak.svc"
extraVolumes: |
- name: hacker-theme
configMap:
name: keycloak-hacker-theme
extraVolumeMounts: |
- name: hacker-theme
mountPath: /opt/keycloak/themes/hacker/login/theme.properties
subPath: theme.properties
- name: hacker-theme
mountPath: /opt/keycloak/themes/hacker/login/css/hacker.css
subPath: hacker.css
dbchecker:
enabled: true
+18 -15
View File
@@ -17,20 +17,23 @@ spec:
PGADMIN_CONFIG_OAUTH2_CONFIG: |-
[
{
'OAUTH2_NAME': 'Authentik',
'OAUTH2_DISPLAY_NAME': 'Authentik',
'OAUTH2_CLIENT_ID': '{{ .client_id }}',
'OAUTH2_CLIENT_SECRET': '{{ .client_secret }}',
'OAUTH2_TOKEN_URL': '{{ .pgadmin_url }}/application/o/token/',
'OAUTH2_AUTHORIZATION_URL': '{{ .pgadmin_url }}/application/o/authorize/',
'OAUTH2_SERVER_METADATA_URL': '{{ .pgadmin_url }}/application/o/pgadmin/.well-known/openid-configuration',
'OAUTH2_API_BASE_URL': '{{ .pgadmin_url }}',
'OAUTH2_USERINFO_ENDPOINT': '{{ .pgadmin_url }}/application/o/userinfo/',
'OAUTH2_SCOPE': 'openid profile email',
'OAUTH2_USERNAME_CLAIM': 'email',
'OAUTH2_BUTTON_COLOR': '#000000',
'OAUTH2_SSL_CERT_VERIFICATION': False,
'OAUTH2_LOGOUT_URL': '{{ .pgadmin_url }}/application/o/pgadmin/end-session/'
'OAUTH2_NAME': 'Keycloak',
'OAUTH2_DISPLAY_NAME': 'Keycloak',
'OAUTH2_CLIENT_ID': '{{ .client_id }}',
'OAUTH2_CLIENT_SECRET': '{{ .client_secret }}',
'OAUTH2_TOKEN_URL': '{{ .keycloak_url }}/realms/hexor/protocol/openid-connect/token',
'OAUTH2_AUTHORIZATION_URL': '{{ .keycloak_url }}/realms/hexor/protocol/openid-connect/auth',
'OAUTH2_SERVER_METADATA_URL': '{{ .keycloak_url }}/realms/hexor/.well-known/openid-configuration',
'OAUTH2_API_BASE_URL': '{{ .keycloak_url }}',
'OAUTH2_USERINFO_ENDPOINT': '{{ .keycloak_url }}/realms/hexor/protocol/openid-connect/userinfo',
'OAUTH2_SCOPE': 'openid profile email',
'OAUTH2_USERNAME_CLAIM': 'email',
'OAUTH2_BUTTON_COLOR': '#000000',
'OAUTH2_SSL_CERT_VERIFICATION': False,
'OAUTH2_LOGOUT_URL': '{{ .keycloak_url }}/realms/hexor/protocol/openid-connect/logout',
}
]
data:
@@ -78,7 +81,7 @@ spec:
metadataPolicy: None
key: 832042b9-7edb-4f4c-9254-3c8884ba9733
property: fields[1].value
- secretKey: pgadmin_url
- secretKey: keycloak_url
sourceRef:
storeRef:
name: vaultwarden-login
@@ -0,0 +1,367 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: auth-proxy-dashboard
labels:
grafana_dashboard: "1"
data:
auth-proxy.json: |-
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 0 },
"id": 1,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calc": "lastNotNull", "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "routes_loaded_total",
"refId": "A"
}
],
"title": "Loaded Routes",
"type": "stat"
},
{
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 0 },
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calc": "lastNotNull", "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "sum(increase(auth_requests_total[$__rate_interval]))",
"refId": "A"
}
],
"title": "Auth Requests (total)",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null }
]
}
},
"overrides": []
}
},
{
"gridPos": { "h": 4, "w": 6, "x": 12, "y": 0 },
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calc": "lastNotNull", "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "sum(increase(auth_requests_total{status=\"403\"}[$__rate_interval]))",
"refId": "A"
}
],
"title": "Forbidden (403)",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "red", "value": 1 }
]
}
},
"overrides": []
}
},
{
"gridPos": { "h": 4, "w": 6, "x": 18, "y": 0 },
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": { "calc": "lastNotNull", "fields": "", "values": false },
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "sum(increase(callback_requests_total{result=\"success\"}[$__rate_interval]))",
"refId": "A"
}
],
"title": "Successful Logins",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null }
]
}
},
"overrides": []
}
},
{
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 4 },
"id": 5,
"options": {
"legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true },
"tooltip": { "mode": "single", "sort": "none" }
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "sum by (status) (rate(auth_requests_total[$__rate_interval]))",
"legendFormat": "{{status}}",
"refId": "A"
}
],
"title": "Auth Request Rate by Status",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "auto",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [ { "color": "green", "value": null } ]
},
"unit": "reqps"
},
"overrides": []
}
},
{
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 4 },
"id": 6,
"options": {
"legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true },
"tooltip": { "mode": "single", "sort": "none" }
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "auth_request_duration_seconds{quantile=\"0.5\"}",
"legendFormat": "p50",
"refId": "A"
},
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "auth_request_duration_seconds{quantile=\"0.95\"}",
"legendFormat": "p95",
"refId": "B"
},
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "auth_request_duration_seconds{quantile=\"0.99\"}",
"legendFormat": "p99",
"refId": "C"
}
],
"title": "Auth Request Duration (p50, p95, p99)",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "auto",
"spanNulls": false,
"stacking": { "group": "A", "mode": "none" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [ { "color": "green", "value": null } ]
},
"unit": "s"
},
"overrides": []
}
},
{
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 12 },
"id": 7,
"options": {
"legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true },
"tooltip": { "mode": "single", "sort": "none" }
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": { "type": "prometheus", "uid": "${datasource}" },
"expr": "sum by (result) (rate(callback_requests_total[$__rate_interval]))",
"legendFormat": "{{result}}",
"refId": "A"
}
],
"title": "OIDC Callback Rate by Result",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": { "mode": "palette-classic" },
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "bars",
"fillOpacity": 50,
"gradientMode": "none",
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": { "type": "linear" },
"showPoints": "auto",
"spanNulls": false,
"stacking": { "group": "A", "mode": "normal" },
"thresholdsStyle": { "mode": "off" }
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [ { "color": "green", "value": null } ]
},
"unit": "reqps"
},
"overrides": []
}
}
],
"refresh": "30s",
"schemaVersion": 38,
"style": "dark",
"tags": [
"auth-proxy",
"rsauth2-proxy"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "Prometheus",
"value": "Prometheus"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "datasource",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Auth Proxy (rsauth2-proxy)",
"uid": "auth-proxy-metrics",
"version": 1
}
@@ -1,669 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: furumi-server-dashboard
labels:
grafana_dashboard: "1"
data:
furumi-server.json: |-
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"gridPos": {
"h": 4,
"w": 6,
"x": 0,
"y": 0
},
"id": 1,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calc": "lastNotNull",
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "sum(furumi_active_streams)",
"refId": "A"
}
],
"title": "Active Streams",
"type": "stat"
},
{
"gridPos": {
"h": 4,
"w": 6,
"x": 6,
"y": 0
},
"id": 2,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calc": "rate",
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "sum(rate(furumi_bytes_read_total[$__rate_interval]))",
"refId": "A"
}
],
"title": "Bytes Read / Sec",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "Bps"
},
"overrides": []
}
},
{
"gridPos": {
"h": 4,
"w": 6,
"x": 12,
"y": 0
},
"id": 3,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calc": "lastNotNull",
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "sum(increase(furumi_file_open_errors_total[$__rate_interval]))",
"refId": "A"
}
],
"title": "File Open Errors (Rate)",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "red", "value": 1 }
]
}
},
"overrides": []
}
},
{
"gridPos": {
"h": 4,
"w": 6,
"x": 18,
"y": 0
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calc": "lastNotNull",
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "sum(increase(furumi_auth_failures_total[$__rate_interval]))",
"refId": "A"
}
],
"title": "Auth Failures (Rate)",
"type": "stat",
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "red", "value": 1 }
]
}
},
"overrides": []
}
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 4
},
"id": 5,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "sum by (method, status) (rate(furumi_grpc_requests_total[$__rate_interval]))",
"legendFormat": "{{method}} - {{status}}",
"refId": "A"
}
],
"title": "gRPC Request Rate by Method & Status",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "reqps"
},
"overrides": []
}
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 4
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "histogram_quantile(0.95, sum(rate(furumi_grpc_request_duration_seconds_bucket[$__rate_interval])) by (le, method))",
"legendFormat": "p95 {{method}}",
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "histogram_quantile(0.99, sum(rate(furumi_grpc_request_duration_seconds_bucket[$__rate_interval])) by (le, method))",
"legendFormat": "p99 {{method}}",
"refId": "B"
}
],
"title": "gRPC Request Duration (p95, p99)",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "s"
},
"overrides": []
}
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 12
},
"id": 99,
"panels": [
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 13
},
"id": 7,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "process_resident_memory_bytes / 1024 / 1024",
"legendFormat": "Resident Memory",
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "process_virtual_memory_bytes / 1024 / 1024",
"legendFormat": "Virtual Memory",
"refId": "B"
}
],
"title": "Process Memory Usage",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 15,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null }
]
},
"unit": "megbytes"
},
"overrides": []
}
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 13
},
"id": 8,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "10.0.0",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "process_open_fds",
"legendFormat": "Open FDs",
"refId": "A"
},
{
"datasource": {
"type": "prometheus",
"uid": "${datasource}"
},
"expr": "process_max_fds",
"legendFormat": "Max FDs",
"refId": "B"
}
],
"title": "Process File Descriptors",
"type": "timeseries",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null }
]
},
"unit": "short"
},
"overrides": []
}
}
],
"title": "Process Metrics (Memory, FDs)",
"type": "row"
}
],
"refresh": "10s",
"schemaVersion": 38,
"style": "dark",
"tags": [
"furumi-server",
"grpc"
],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "Prometheus",
"value": "Prometheus"
},
"hide": 0,
"includeAll": false,
"multi": false,
"name": "datasource",
"options": [],
"query": "prometheus",
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"type": "datasource"
}
]
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Furumi Server Metrics",
"uid": "furumi-metrics",
"version": 1
}
+3 -3
View File
@@ -6,13 +6,13 @@ resources:
- external-secrets.yaml
- grafana-alerting-configmap.yaml
- alertmanager-config.yaml
- furumi-dashboard-cm.yaml
- telemt-dashboard-cm.yaml
- dashboards/telemt-dashboard-cm.yaml
- dashboards/auth-proxy-dashboard-cm.yaml
helmCharts:
- name: kube-prometheus-stack
repo: https://prometheus-community.github.io/helm-charts
version: 82.10.3
version: 84.3.0
releaseName: prometheus
namespace: prometheus
valuesFile: prom-values.yaml
File diff suppressed because it is too large Load Diff
+17 -9
View File
@@ -1,5 +1,4 @@
alertmanager:
config:
global:
@@ -109,18 +108,27 @@ grafana:
grafana.ini:
auth:
signout_redirect_url: https://idm.hexor.cy/application/o/grafana/end-session/
signout_redirect_url: https://auth.hexor.cy/auth/realms/hexor/protocol/openid-connect/logout?post_logout_redirect_uri=https%3A%2F%2Fgf.hexor.cy%2Flogin&client_id=Grafana
oauth_allow_insecure_email_lookup: true
auth.generic_oauth:
name: authentik
name: Keycloak
enabled: true
scopes: "openid profile email"
auth_url: https://idm.hexor.cy/application/o/authorize/
token_url: https://idm.hexor.cy/application/o/token/
api_url: https://idm.hexor.cy/application/o/userinfo/
allow_sign_up: true
auth_url: https://auth.hexor.cy/auth/realms/hexor/protocol/openid-connect/auth
token_url: https://auth.hexor.cy/auth/realms/hexor/protocol/openid-connect/token
api_url: https://auth.hexor.cy/auth/realms/hexor/protocol/openid-connect/userinfo
email_attribute_path: email
login_attribute_path: preferred_username
name_attribute_path: name
role_attribute_path: >-
contains(groups, 'Grafana Admin') && 'Admin' ||
contains(groups, 'Grafana Editors') && 'Editor' ||
contains(groups, 'Grafana Viewer') && 'Viewer'
contains(groups[*], 'hexor-admin') && 'Admin' ||
contains(groups[*], 'hexor-guest') && 'Viewer' ||
'Viewer'
role_attribute_strict: false
log:
level: debug
filters: "oauth.generic_oauth:debug"
database:
type: postgres
host: psql.psql.svc:5432
@@ -43,23 +43,6 @@ proxy_applications = {
access_groups = ["admins"]
}
"kubernetes-secrets" = {
name = "kubernetes-secrets"
slug = "k8s-secret"
group = "Core"
external_host = "https://pass.hexor.cy"
internal_host = "http://secret-reader.k8s-secret.svc:80"
internal_host_ssl_validation = false
meta_description = ""
skip_path_regex = <<-EOT
/webhook
EOT
meta_icon = "https://img.icons8.com/ios-filled/50/password.png"
mode = "proxy"
outpost = "kubernetes-outpost"
create_group = true
access_groups = ["admins"]
}
"mtproxy-links" = {
name = "mtproxy-links"
slug = "mtproxy-links"
+2
View File
@@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/kubernetes" {
constraints = ">= 2.0.0"
hashes = [
"h1:G9QqKNpcztBRqrywtlNylFJSpGzDfRFtO8hcWLdkvRY=",
"h1:iDIPyL9K9FXc8ievR5vRmXsgT1/I9Vq9CFDKm1Zo8bQ=",
"zh:0215c5c60be62028c09a2f22458e89cda3ef5830a632299f1d401eb3538874b0",
"zh:09ebb9f442431e278a310a9423f32caf467cb4b3cad3fe59573ca71fa7b14e20",
"zh:0c4e5912f83bb35846ae0a9ae54fc320706ee61894cd21cc6b4181b1c5a2fa5c",
@@ -26,6 +27,7 @@ provider "registry.terraform.io/keycloak/keycloak" {
constraints = ">= 5.0.0"
hashes = [
"h1:3DuKdVeOxwULh7l6bvJKWZvsgSZo92rtnrdvyp+X2Lc=",
"h1:reFEBcuBZf2SVqDa1YIaNLuIW72uEVsOu5hHhQgfHi0=",
"zh:19be4505b17e4818db121a82917cb6723019cf379cfb82b720eaa2886f15bede",
"zh:2bd1565ed22db6a9fb50d60626e22c277f3b034a71f65e6c0011e42f56cad2bb",
"zh:34a9e2dfb06331dc6146491c4a0721001195c6a769cdc2d4546edb2acf2b39bd",
+180 -45
View File
@@ -8,7 +8,7 @@ resource "keycloak_realm" "hexor" {
display_name = "Hexor"
login_theme = "keycloak"
login_theme = "keycloak.v2"
account_theme = "keycloak.v3"
registration_allowed = false
@@ -19,6 +19,119 @@ resource "keycloak_realm" "hexor" {
duplicate_emails_allowed = false
ssl_required = "external"
web_authn_passwordless_policy {
relying_party_entity_name = "Hexor"
relying_party_id = "hexor.cy"
signature_algorithms = ["ES256", "RS256"]
user_verification_requirement = "required"
require_resident_key = "Yes"
attestation_conveyance_preference = "none"
}
}
# =============================================================================
# Passkey (WebAuthn Passwordless) — required action
# =============================================================================
resource "keycloak_required_action" "webauthn_register_passwordless" {
realm_id = keycloak_realm.hexor.id
alias = "webauthn-register-passwordless"
name = "Webauthn Register Passwordless"
enabled = true
default_action = false
}
# =============================================================================
# Browser flow with Passkey support
# =============================================================================
resource "keycloak_authentication_flow" "browser_with_passkey" {
realm_id = keycloak_realm.hexor.id
alias = "browser-with-passkey"
description = "Browser flow with passkey/password alternatives"
provider_id = "basic-flow"
}
# --- Cookie (re-use existing session) ---
resource "keycloak_authentication_execution" "cookie" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_flow.browser_with_passkey.alias
authenticator = "auth-cookie"
requirement = "ALTERNATIVE"
priority = 10
}
# --- Identity Provider Redirector ---
resource "keycloak_authentication_execution" "idp_redirector" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_flow.browser_with_passkey.alias
authenticator = "identity-provider-redirector"
requirement = "ALTERNATIVE"
priority = 20
}
# --- Passkey (WebAuthn Passwordless) ---
resource "keycloak_authentication_execution" "passkey" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_flow.browser_with_passkey.alias
authenticator = "webauthn-authenticator-passwordless"
requirement = "ALTERNATIVE"
priority = 30
}
# --- Username/Password + optional 2FA subflow ---
resource "keycloak_authentication_subflow" "forms" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_flow.browser_with_passkey.alias
alias = "browser-with-passkey-forms"
provider_id = "basic-flow"
requirement = "ALTERNATIVE"
priority = 40
}
resource "keycloak_authentication_execution" "username_password" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_subflow.forms.alias
authenticator = "auth-username-password-form"
requirement = "REQUIRED"
priority = 10
}
resource "keycloak_authentication_subflow" "conditional_2fa" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_subflow.forms.alias
alias = "browser-with-passkey-conditional-2fa"
provider_id = "basic-flow"
requirement = "CONDITIONAL"
priority = 20
}
resource "keycloak_authentication_execution" "condition_user_configured" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_subflow.conditional_2fa.alias
authenticator = "conditional-user-configured"
requirement = "REQUIRED"
priority = 10
}
resource "keycloak_authentication_execution" "otp_form" {
realm_id = keycloak_realm.hexor.id
parent_flow_alias = keycloak_authentication_subflow.conditional_2fa.alias
authenticator = "auth-otp-form"
requirement = "ALTERNATIVE"
priority = 20
}
# --- Bind the new flow as the browser flow ---
resource "keycloak_authentication_bindings" "browser" {
realm_id = keycloak_realm.hexor.id
browser_flow = keycloak_authentication_flow.browser_with_passkey.alias
}
# =============================================================================
@@ -86,49 +199,6 @@ resource "keycloak_openid_client_default_scopes" "rsauth2_proxy" {
client_id = keycloak_openid_client.rsauth2_proxy.id
default_scopes = [
"openid",
"profile",
"email",
]
}
# =============================================================================
# rsauth2-proxy client (localhost testing)
# =============================================================================
resource "keycloak_openid_client" "rsauth2_proxy_dev" {
realm_id = keycloak_realm.hexor.id
client_id = "rsauth2-proxy-dev"
name = "rsauth2-proxy (dev)"
enabled = true
access_type = "CONFIDENTIAL"
standard_flow_enabled = true
direct_access_grants_enabled = false
valid_redirect_uris = [
"http://localhost:8080/callback",
]
web_origins = [
"http://localhost:8080",
]
}
resource "keycloak_openid_group_membership_protocol_mapper" "rsauth2_proxy_dev_groups" {
realm_id = keycloak_realm.hexor.id
client_id = keycloak_openid_client.rsauth2_proxy_dev.id
name = "groups"
claim_name = "groups"
full_path = false
}
resource "keycloak_openid_client_default_scopes" "rsauth2_proxy_dev" {
realm_id = keycloak_realm.hexor.id
client_id = keycloak_openid_client.rsauth2_proxy_dev.id
default_scopes = [
"openid",
"profile",
"email",
]
@@ -154,7 +224,72 @@ locals {
}
}
resource "kubernetes_config_map" "auth_proxy_routes" {
# =============================================================================
# OAuth2 applications — full OIDC clients for apps that handle auth themselves
# =============================================================================
resource "keycloak_openid_client" "oauth2_app" {
for_each = var.oauth2_applications
realm_id = keycloak_realm.hexor.id
client_id = each.key
name = each.key
enabled = true
access_type = "CONFIDENTIAL"
standard_flow_enabled = true
direct_access_grants_enabled = false
valid_redirect_uris = each.value.redirect_uris
valid_post_logout_redirect_uris = each.value.post_logout_redirect_uris
web_origins = each.value.web_origins
}
resource "keycloak_openid_group_membership_protocol_mapper" "oauth2_app_groups" {
for_each = var.oauth2_applications
realm_id = keycloak_realm.hexor.id
client_id = keycloak_openid_client.oauth2_app[each.key].id
name = "groups"
claim_name = "groups"
full_path = false
}
resource "keycloak_openid_client_default_scopes" "oauth2_app" {
for_each = var.oauth2_applications
realm_id = keycloak_realm.hexor.id
client_id = keycloak_openid_client.oauth2_app[each.key].id
default_scopes = concat(
["profile", "email"],
each.value.extra_default_scopes
)
}
resource "keycloak_openid_client_optional_scopes" "oauth2_app" {
for_each = {
for k, v in var.oauth2_applications : k => v if length(v.extra_optional_scopes) > 0
}
realm_id = keycloak_realm.hexor.id
client_id = keycloak_openid_client.oauth2_app[each.key].id
optional_scopes = each.value.extra_optional_scopes
}
resource "keycloak_group" "oauth2_app" {
for_each = var.oauth2_applications
realm_id = keycloak_realm.hexor.id
name = "app-${each.key}"
}
# =============================================================================
# Proxy applications — routes ConfigMap
# =============================================================================
resource "kubernetes_config_map_v1" "auth_proxy_routes" {
metadata {
name = "auth-proxy-routes"
namespace = "auth-proxy"
+9 -9
View File
@@ -15,15 +15,6 @@ output "rsauth2_proxy_client_secret" {
sensitive = true
}
output "rsauth2_proxy_dev_client_id" {
value = keycloak_openid_client.rsauth2_proxy_dev.client_id
}
output "rsauth2_proxy_dev_client_secret" {
value = keycloak_openid_client.rsauth2_proxy_dev.client_secret
sensitive = true
}
output "standalone_groups" {
value = [for g in keycloak_group.standalone : g.name]
}
@@ -35,3 +26,12 @@ output "app_groups" {
output "app_allowed_groups" {
value = local.app_allowed_groups
}
output "oauth2_app_client_ids" {
value = { for k, c in keycloak_openid_client.oauth2_app : k => c.client_id }
}
output "oauth2_app_client_secrets" {
value = { for k, c in keycloak_openid_client.oauth2_app : k => c.client_secret }
sensitive = true
}
+1 -1
View File
@@ -19,5 +19,5 @@ provider "keycloak" {
}
provider "kubernetes" {
config_path = var.kubeconfig_path
config_path = "~/.kube/config"
}
+48
View File
@@ -0,0 +1,48 @@
groups = [
"hexor-admin",
"hexor-guest",
"game-servers-managers",
"argocd-admins",
"web-petting"
]
proxy_applications = {
secret-reader = {
domain = "secret-reader.hexor.cy"
allowed_groups = ["hexor-guest", "hexor-admin"]
}
pass = {
domain = "pass.hexor.cy"
allowed_groups = ["hexor-guest", "hexor-admin"]
}
}
oauth2_applications = {
gitea = {
redirect_uris = ["https://gt.hexor.cy/user/oauth2/Keycloak/callback"]
web_origins = ["https://gt.hexor.cy"]
post_logout_redirect_uris = ["https://gt.hexor.cy/*"]
}
ArgoCD = {
redirect_uris = ["https://ag.hexor.cy/api/dex/callback"]
web_origins = ["https://ag.hexor.cy"]
post_logout_redirect_uris = ["https://ag.hexor.cy/*"]
extra_optional_scopes = ["offline_access"]
}
PGAdmin = {
redirect_uris = ["https://pg.hexor.cy/oauth2/authorize"]
web_origins = ["https://pg.hexor.cy"]
post_logout_redirect_uris = ["https://pg.hexor.cy/*"]
}
Grafana = {
redirect_uris = ["https://gf.hexor.cy/login/generic_oauth"]
web_origins = ["https://gf.hexor.cy"]
post_logout_redirect_uris = ["https://gf.hexor.cy/*"]
}
Web-Petting = {
redirect_uris = ["https://pet.hexor.cy/admin/oidc/callback", "https://xn--l1acako8eb.xn--p1ai/admin/oidc/callback", "https://мурняня.рф/admin/oidc/callback", "http://127.0.0.1:3000/admin/oidc/callback"]
web_origins = ["https://pet.hexor.cy", "https://xn--l1acako8eb.xn--p1ai", "https://мурняня.рф", "http://127.0.0.1:3000"]
post_logout_redirect_uris = ["https://pet.hexor.cy/*", "https://xn--l1acako8eb.xn--p1ai/*", "https://мурняня.рф/*", "http://127.0.0.1:3000/*"]
}
}
+13 -6
View File
@@ -16,12 +16,6 @@ variable "keycloak_client_secret" {
sensitive = true
}
variable "kubeconfig_path" {
description = "Path to kubeconfig (set via TF_VAR_kubeconfig_path or KUBE_CONFIG_PATH)"
type = string
default = "~/.kube/config"
}
variable "google_client_id" {
description = "Google OAuth client ID (set via TF_VAR_google_client_id)"
type = string
@@ -47,3 +41,16 @@ variable "proxy_applications" {
}))
default = {}
}
variable "oauth2_applications" {
description = "OAuth2/OIDC applications that handle authentication themselves"
type = map(object({
redirect_uris = list(string)
post_logout_redirect_uris = optional(list(string), [])
web_origins = optional(list(string), [])
extra_default_scopes = optional(list(string), [])
extra_optional_scopes = optional(list(string), [])
allowed_groups = optional(list(string), [])
}))
default = {}
}