From f5c5e12fe12a334bf7201361b70d2d434eff77fd Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 16:57:57 +0530 Subject: [PATCH 1/9] feat(keycloak): keycloak setup for accepting prometheus scrapes --- modules/keycloak/deployment.tf | 14 +++++++++++++- modules/keycloak/networkpolicy.tf | 22 ++++++++++++++++++++++ modules/keycloak/variables.tf | 6 ++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/keycloak/deployment.tf b/modules/keycloak/deployment.tf index 1d7360a..39241be 100644 --- a/modules/keycloak/deployment.tf +++ b/modules/keycloak/deployment.tf @@ -9,7 +9,7 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { } } spec { - replicas = 3 + replicas = 1 service_name = "" // Stateful Set Pod Selector @@ -33,6 +33,13 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { "part-of" = "keycloak" "pg-access" = true } + + annotations = { + "prometheus.io/scrape" = "true" + "prometheus.io/path" = "/metrics" + "prometheus.io/port" = "9000" + "prometheus.io/scheme" = "https" + } } // Pod Spec @@ -103,6 +110,11 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { value = "postgres" } + env { + name = "KC_METRICS_ENABLED" + value = "true" + } + env { name = "KC_DB_USERNAME" value_from { diff --git a/modules/keycloak/networkpolicy.tf b/modules/keycloak/networkpolicy.tf index ae0bf7f..969b089 100644 --- a/modules/keycloak/networkpolicy.tf +++ b/modules/keycloak/networkpolicy.tf @@ -65,6 +65,28 @@ resource "kubernetes_network_policy" "keycloak_network_access_policy" { port = 57800 } } + + # Rule 3: Allow OpenTelemetry Collector to scrape Keycloak metrics + ingress { + from { + namespace_selector { + match_labels = { + "kubernetes.io/metadata.name" = var.observability_namespace + } + } + + pod_selector { + match_labels = { + "app.kubernetes.io/instance" = "otel-collector" + } + } + } + + ports { + protocol = "TCP" + port = 3903 + } + } # -------------- EGRESS RULES -------------- # # Rule 1: Allow egress to KubeDNS for DNS resolutions diff --git a/modules/keycloak/variables.tf b/modules/keycloak/variables.tf index ee8876d..b8a2f18 100644 --- a/modules/keycloak/variables.tf +++ b/modules/keycloak/variables.tf @@ -30,6 +30,12 @@ variable "postgres_namespace" { nullable = false } +variable "observability_namespace" { + description = "Namespace where all components for observability are deployed" + type = string + nullable = false +} + # --------------- DATABASE VARIABLES --------------- # variable "cluster_name" { description = "Database Cluster Name to allow Network Connections to" From 51b4c55be9ce201cbbdadf2812bc2e6a3a1d8eef Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 16:58:28 +0530 Subject: [PATCH 2/9] fix(observability): ignore self signed certs --- modules/observability/otel-collector.tf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/observability/otel-collector.tf b/modules/observability/otel-collector.tf index 1b2d05a..d5044dd 100644 --- a/modules/observability/otel-collector.tf +++ b/modules/observability/otel-collector.tf @@ -87,6 +87,12 @@ resource "helm_release" "otel_collector" { honor_labels = true scrape_interval = "30s" body_size_limit = "50MB" + + // Ignore Self Signed TLS errors while scraping HTTPS endpoints + tls_config = { + insecure_skip_verify = true + } + kubernetes_sd_configs = [ { role = "pod" @@ -132,6 +138,13 @@ resource "helm_release" "otel_collector" { source_labels = ["__meta_kubernetes_pod_name"] action = "replace" target_label = "pod" + }, + // Use HTTPS if the scheme asks for it + { + source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_scheme"] + action = "replace" + target_label = "__scheme__" + regex = "(https?)" } ] }, From 5463c95341cdf78ededaa66a212b84beb1982dc5 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 20:03:48 +0530 Subject: [PATCH 3/9] fix(observability): required permissions on role --- infrastructure/main.tf | 4 ++-- modules/observability/otel-collector.tf | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/infrastructure/main.tf b/infrastructure/main.tf index b84ff86..fbb6d48 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -22,7 +22,7 @@ module "cluster-issuer" { # Complete Observability Stack Deployment module "observability" { - source = "git::https://github.com/necro-cloud/modules//modules/observability?ref=main" + source = "git::https://github.com/necro-cloud/modules//modules/observability?ref=task/96/keycloak-dashboards" // Certificates Details cluster_issuer_name = module.cluster-issuer.cluster-issuer-name @@ -138,7 +138,7 @@ module "ferretdb" { # Keycloak Cluster Deployment for Identity Solution module "keycloak" { - source = "git::https://github.com/necro-cloud/modules//modules/keycloak?ref=main" + source = "git::https://github.com/necro-cloud/modules//modules/keycloak?ref=task/96/keycloak-dashboards" // PostgreSQL Database Details for database details cluster_issuer_name = module.cluster-issuer.cluster-issuer-name diff --git a/modules/observability/otel-collector.tf b/modules/observability/otel-collector.tf index d5044dd..313f69d 100644 --- a/modules/observability/otel-collector.tf +++ b/modules/observability/otel-collector.tf @@ -11,7 +11,22 @@ resource "helm_release" "otel_collector" { fullnameOverride = "otel-collector" mode = "daemonset" - + clusterRole = { + create = true + rules = [ + { + apiGroups = [""] + resources = ["nodes", "nodes/metrics", "nodes/stats", "nodes/proxy", "services", "endpoints", "pods"] + verbs = ["get", "list", "watch"] + }, + { + apiGroups = ["apps", "extensions"] + resources = ["replicasets"] + verbs = ["get", "list", "watch"] + } + ] + } + // Enable service creation for pushing logs and metrics service = { enabled = true From a2085b362cbe8749cd0a6c5c4f2c7a9f6d91b84d Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 20:05:11 +0530 Subject: [PATCH 4/9] fix(infrastructure): added observability namespace for keycloak --- infrastructure/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/infrastructure/main.tf b/infrastructure/main.tf index fbb6d48..9d946b3 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -153,6 +153,9 @@ module "keycloak" { cloudflare_email = var.cloudflare_email domain = var.domain + // Observability details + observability_namespace = module.observability.observability_namespace + // Realm Settings for auto configuration of required clients realm_settings = local.keycloak_realm_settings From 29c30a867e0d44892ff490cf55256c878b67802f Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 20:22:23 +0530 Subject: [PATCH 5/9] fix(keycloak): port 9000 allow for otel collector --- modules/keycloak/networkpolicy.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/keycloak/networkpolicy.tf b/modules/keycloak/networkpolicy.tf index 969b089..3fbae95 100644 --- a/modules/keycloak/networkpolicy.tf +++ b/modules/keycloak/networkpolicy.tf @@ -84,7 +84,7 @@ resource "kubernetes_network_policy" "keycloak_network_access_policy" { ports { protocol = "TCP" - port = 3903 + port = 9000 } } From 2b2647b05e305374270571bd29442154e53759df Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 20:48:20 +0530 Subject: [PATCH 6/9] feat(keycloak): user event metrics enabled --- modules/keycloak/deployment.tf | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/keycloak/deployment.tf b/modules/keycloak/deployment.tf index 39241be..aa2c12d 100644 --- a/modules/keycloak/deployment.tf +++ b/modules/keycloak/deployment.tf @@ -115,6 +115,16 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { value = "true" } + env { + name = "KC_EVENT_METRICS_USER_ENABLED" + value = "true" + } + + env { + name = "KC_EVENT_METRICS_USER_TAGS" + value = "realm,idp,clientId" + } + env { name = "KC_DB_USERNAME" value_from { From e2a70f9325635662f52f1cebc610803d2d8c0e6e Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 21:32:42 +0530 Subject: [PATCH 7/9] feat(observability): deploying keycloak dashboard in an automated fashion --- .../observability/dashboards/keycloak.json | 1548 +++++++++++++++++ modules/observability/grafana.tf | 16 + 2 files changed, 1564 insertions(+) create mode 100644 modules/observability/dashboards/keycloak.json diff --git a/modules/observability/dashboards/keycloak.json b/modules/observability/dashboards/keycloak.json new file mode 100644 index 0000000..b71e940 --- /dev/null +++ b/modules/observability/dashboards/keycloak.json @@ -0,0 +1,1548 @@ +{ + "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": 5, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "panels": [], + "title": "Golden Signals", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "max(base_jvm_uptime{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Keycloak Uptime", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum(base_memory_usedHeap_bytes{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Used Heap Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum(vendor_statistics_off_heap_memory_used{cache=\"authenticationSessions\", namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Active Authentication Sessions", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum(agroal_active_count{namespace=~\"$namespace\", pod=~\"$pod\", datasource=\"default\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Active Database Connections", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 6, + "panels": [], + "title": "Identity & Authentication", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(realm, client_id) (rate(keycloak_user_events_total{namespace=~\"$namespace\", pod=~\"$pod\", event=\"login\"}[5m]))", + "legendFormat": "{{client_id}} ({{realm}})", + "range": true, + "refId": "A" + } + ], + "title": "Successful Logins (TPS)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 18 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(realm) (rate(keycloak_user_events_total{namespace=~\"$namespace\", pod=~\"$pod\", event=\"register\"}[5m]))", + "legendFormat": "Registrations - {{realm}}", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "editorMode": "code", + "expr": "sum by(realm) (rate(keycloak_user_events_total{namespace=~\"$namespace\", pod=~\"$pod\", event=\"federated_identity_link\"}[5m]))", + "hide": false, + "instant": false, + "legendFormat": "IdP Links - {{realm}}", + "range": true, + "refId": "B" + } + ], + "title": "User Registrations & IdP Links", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 18 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(realm, client_id) (rate(keycloak_user_events_total{namespace=~\"$namespace\", pod=~\"$pod\", event=\"login_error\"}[5m]))", + "legendFormat": "{{client_id}} ({{realm}})", + "range": true, + "refId": "A" + } + ], + "title": "Failed Login Attempts", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 10, + "panels": [], + "title": "HTTP & Database Performance", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (status) (rate(http_server_requests_seconds_count{namespace=~\"$namespace\", pod=~\"$pod\"}[5m]))", + "legendFormat": "Status: {{status}}", + "range": true, + "refId": "A" + } + ], + "title": "HTTP Request Rate by Status Code", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 15, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "max(agroal_blocking_time_average_milliseconds{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Database Blocking Time", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 13, + "panels": [], + "title": "Infinispan Cache Health", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (cache) (rate(vendor_statistics_hit_times_seconds_count{namespace=~\"$namespace\", pod=~\"$pod\"}[5m]))", + "format": "time_series", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Cache Hits", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (cache) (rate(vendor_statistics_miss_times_seconds_count{namespace=~\"$namespace\", pod=~\"$pod\"}[5m]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Cache Misses", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "avg by(cache) (vendor_statistics_average_read_time{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Cache Read Latency", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 44 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "avg by(cache) (vendor_statistics_average_write_time{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Cache Write Latency", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 52 + }, + "id": 18, + "panels": [], + "title": "JVM & Worker Threads", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 53 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by (state) (jvm_threads_states_threads{namespace=~\"$namespace\", pod=~\"$pod\"})", + "legendFormat": "State: {{state}}", + "range": true, + "refId": "A" + } + ], + "title": "JVM Threads by State", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P4169E866C3094E38" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "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", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 53 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "editorMode": "code", + "expr": "sum by(gc) (rate(jvm_gc_pause_seconds_sum{namespace=~\"$namespace\", pod=~\"$pod\"}[5m]))", + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "Garbage Collection Pauses", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 61 + }, + "id": 21, + "panels": [], + "title": "Logging", + "type": "row" + }, + { + "datasource": { + "type": "victoriametrics-logs-datasource", + "uid": "PD775F2863313E6C7" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 24, + "x": 0, + "y": 62 + }, + "id": 22, + "options": { + "dedupStrategy": "none", + "enableInfiniteScrolling": false, + "enableLogDetails": true, + "prettifyLogMessage": false, + "showControls": true, + "showTime": false, + "sortOrder": "Descending", + "syntaxHighlighting": true, + "wrapLogMessage": true + }, + "pluginVersion": "12.3.3", + "targets": [ + { + "datasource": { + "type": "victoriametrics-logs-datasource", + "uid": "PD775F2863313E6C7" + }, + "direction": "desc", + "editorMode": "code", + "expr": "part-of: \"keycloak\" AND k8s.pod.name: $pod", + "queryType": "instant", + "refId": "A" + } + ], + "title": "Logging", + "type": "logs" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [ + { + "allowCustomValue": false, + "current": { + "text": [ + "keycloak" + ], + "value": [ + "keycloak" + ] + }, + "definition": "label_values(base_jvm_uptime,namespace)", + "description": "", + "includeAll": true, + "label": "Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(base_jvm_uptime,namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + }, + { + "allowCustomValue": false, + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "definition": "label_values(base_jvm_uptime{namespace=\"$namespace\"},pod)", + "includeAll": true, + "label": "Pod", + "multi": true, + "name": "pod", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(base_jvm_uptime{namespace=\"$namespace\"},pod)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Keycloak Identity Management Dashboard", + "uid": "obhkmtd", + "version": 1 +} \ No newline at end of file diff --git a/modules/observability/grafana.tf b/modules/observability/grafana.tf index 63a6fae..20e7495 100644 --- a/modules/observability/grafana.tf +++ b/modules/observability/grafana.tf @@ -126,6 +126,17 @@ resource "helm_release" "grafana" { options = { path = "/var/lib/grafana/dashboards/garage" }, + }, + { + name = "Keycloak Identity Management Dashboard" + orgId = 1 + folder = "Application Services Dashboards" + type = "file" + disableDeletion = false + editable = true + options = { + path = "/var/lib/grafana/dashboards/keycloak" + }, } ] } @@ -143,6 +154,11 @@ resource "helm_release" "grafana" { json = file("${path.module}/dashboards/garage.json") } } + keycloak = { + keycloak-dashboard = { + json = file("${path.module}/dashboards/keycloak.json") + } + } } affinity = { From d3b8bf54f2aca71f3473682966b26e4fd7571a91 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 22:15:31 +0530 Subject: [PATCH 8/9] feat(keycloak): variabalizing some stuff --- modules/keycloak/deployment.tf | 4 ++-- modules/keycloak/variables.tf | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/modules/keycloak/deployment.tf b/modules/keycloak/deployment.tf index aa2c12d..f90a298 100644 --- a/modules/keycloak/deployment.tf +++ b/modules/keycloak/deployment.tf @@ -9,7 +9,7 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { } } spec { - replicas = 1 + replicas = var.replicas service_name = "" // Stateful Set Pod Selector @@ -76,7 +76,7 @@ resource "kubernetes_stateful_set" "keycloak_cluster" { // Container Details container { name = "keycloak" - image = "quay.io/keycloak/keycloak:26.4.5" + image = "${var.repository}/${var.image}:${var.tag}" args = ["--verbose", "start", "--import-realm"] // Environment Variables diff --git a/modules/keycloak/variables.tf b/modules/keycloak/variables.tf index b8a2f18..59dfb59 100644 --- a/modules/keycloak/variables.tf +++ b/modules/keycloak/variables.tf @@ -123,7 +123,6 @@ variable "domain" { } # --------------- SECRET VARIABLES --------------- # - variable "database_credentials" { description = "Name of the secret which contains the database credentials for Keycloak" type = string @@ -155,6 +154,29 @@ variable "realm_settings" { } # --------------- CLUSTER VARIABLES --------------- # +variable "replicas" { + description = "Number of replicas to run for Keycloak cluster" + type = number + default = 1 +} + +variable "repository" { + description = "Repository to be used for deployment of Keycloak" + type = string + default = "quay.io/keycloak" +} + +variable "image" { + description = "Docker image to be used for deployment of Keycloak" + type = string + default = "keycloak" +} + +variable "tag" { + description = "Docker tag to be used for deployment of Keycloak" + type = string + default = "26.4.5" +} variable "keycloak_environment_variables" { default = [ From 8e4781ef1a6d3e234fb408d27ef68584561ca877 Mon Sep 17 00:00:00 2001 From: khatrivarun Date: Thu, 5 Mar 2026 23:10:20 +0530 Subject: [PATCH 9/9] [INF] All modules switch to main branch --- infrastructure/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/main.tf b/infrastructure/main.tf index 9d946b3..72227b9 100644 --- a/infrastructure/main.tf +++ b/infrastructure/main.tf @@ -22,7 +22,7 @@ module "cluster-issuer" { # Complete Observability Stack Deployment module "observability" { - source = "git::https://github.com/necro-cloud/modules//modules/observability?ref=task/96/keycloak-dashboards" + source = "git::https://github.com/necro-cloud/modules//modules/observability?ref=main" // Certificates Details cluster_issuer_name = module.cluster-issuer.cluster-issuer-name @@ -138,7 +138,7 @@ module "ferretdb" { # Keycloak Cluster Deployment for Identity Solution module "keycloak" { - source = "git::https://github.com/necro-cloud/modules//modules/keycloak?ref=task/96/keycloak-dashboards" + source = "git::https://github.com/necro-cloud/modules//modules/keycloak?ref=main" // PostgreSQL Database Details for database details cluster_issuer_name = module.cluster-issuer.cluster-issuer-name