diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index b422da6b..8a9fac30 100755 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -8,6 +8,7 @@ - **After updating any `.claude/` files**: Always commit them immediately (`git add .claude/ && git commit -m "[ci skip] update claude knowledge"`) to avoid building up unstaged changes. - **Skills available**: Check `.claude/skills/` directory for specialized workflows (e.g., `setup-project.md` for deploying new services) - **CRITICAL: All infrastructure changes must go through Terraform**. NEVER modify cluster resources directly (e.g., via kubectl apply/edit/patch, helm install, docker run). Always make changes in the Terraform `.tf` files and apply with `terraform apply`. The real cluster state must never deviate from what's defined in Terraform — if a manual change is unavoidable (e.g., containerd config on running nodes), document it and ensure the Terraform templates match so future provisioning is consistent. Use `kubectl` only for read-only operations (get, describe, logs) and ephemeral debugging (run --rm, delete stuck pods), never for persistent state changes. +- **CRITICAL: NEVER put sensitive data (API keys, passwords, tokens, credentials) into committed files** unless they are encrypted (e.g., via git-crypt). Secrets belong in `terraform.tfvars` (which is git-crypt encrypted) or in the `secrets/` directory. Never hardcode credentials in `.tf` files, scripts, `.claude/` files, or any other unencrypted committed file. Always pass secrets through the Terraform variable chain (`terraform.tfvars` → `main.tf` → module variables). ## Execution Environment - **File operations**: Read, Edit, Write, Glob, Grep tools diff --git a/main.tf b/main.tf index 4741fd48..1282d40d 100644 --- a/main.tf +++ b/main.tf @@ -59,6 +59,7 @@ variable "webhook_handler_fb_app_secret" {} variable "webhook_handler_git_user" {} variable "technitium_username" {} variable "technitium_password" {} +variable "technitium_db_password" {} variable "webhook_handler_git_token" {} variable "webhook_handler_ssh_key" {} variable "monitoring_idrac_username" {} @@ -154,6 +155,9 @@ variable "affine_postgresql_password" { type = string } variable "health_postgresql_password" { type = string } variable "health_secret_key" { type = string } variable "moltbot_ssh_key" { type = string } +variable "gemini_api_key" { type = string } +variable "llama_api_key" { type = string } +variable "brave_api_key" { type = string } variable "kube_config_path" { type = string @@ -605,8 +609,9 @@ module "kubernetes_cluster" { frigate_valchedrym_camera_credentials = var.frigate_valchedrym_camera_credentials // updating technitium records - technitium_username = var.technitium_username - technitium_password = var.technitium_password + technitium_username = var.technitium_username + technitium_password = var.technitium_password + technitium_db_password = var.technitium_db_password paperless_db_password = var.paperless_db_password @@ -690,6 +695,9 @@ module "kubernetes_cluster" { health_postgresql_password = var.health_postgresql_password health_secret_key = var.health_secret_key moltbot_ssh_key = var.moltbot_ssh_key + gemini_api_key = var.gemini_api_key + llama_api_key = var.llama_api_key + brave_api_key = var.brave_api_key } diff --git a/modules/kubernetes/main.tf b/modules/kubernetes/main.tf index c55ad15f..ee486040 100644 --- a/modules/kubernetes/main.tf +++ b/modules/kubernetes/main.tf @@ -37,6 +37,7 @@ variable "webhook_handler_git_token" {} variable "webhook_handler_ssh_key" {} variable "technitium_username" {} variable "technitium_password" {} +variable "technitium_db_password" {} variable "idrac_username" {} variable "idrac_password" {} variable "alertmanager_slack_api_url" {} @@ -125,6 +126,9 @@ variable "affine_postgresql_password" { type = string } variable "health_postgresql_password" { type = string } variable "health_secret_key" { type = string } variable "moltbot_ssh_key" { type = string } +variable "gemini_api_key" { type = string } +variable "llama_api_key" { type = string } +variable "brave_api_key" { type = string } variable "defcon_level" { @@ -481,11 +485,12 @@ module "travel_blog" { } module "technitium" { - source = "./technitium" - for_each = contains(local.active_modules, "technitium") ? { technitium = true } : {} - tls_secret_name = var.tls_secret_name - homepage_token = var.homepage_credentials["technitium"]["token"] - tier = local.tiers.core + source = "./technitium" + for_each = contains(local.active_modules, "technitium") ? { technitium = true } : {} + tls_secret_name = var.tls_secret_name + homepage_token = var.homepage_credentials["technitium"]["token"] + technitium_db_password = var.technitium_db_password + tier = local.tiers.core } module "headscale" { @@ -1137,6 +1142,9 @@ module "moltbot" { for_each = contains(local.active_modules, "moltbot") ? { moltbot = true } : {} tls_secret_name = var.tls_secret_name ssh_key = var.moltbot_ssh_key + gemini_api_key = var.gemini_api_key + llama_api_key = var.llama_api_key + brave_api_key = var.brave_api_key tier = local.tiers.aux depends_on = [null_resource.core_services] diff --git a/modules/kubernetes/monitoring/dashboards/technitium-dns.json b/modules/kubernetes/monitoring/dashboards/technitium-dns.json new file mode 100644 index 00000000..b0b17c37 --- /dev/null +++ b/modules/kubernetes/monitoring/dashboards/technitium-dns.json @@ -0,0 +1,488 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { "type": "datasource", "uid": "grafana" }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Technitium DNS query logs from MySQL", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "id": null, + "links": [], + "panels": [ + { + "title": "Total Queries", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 0, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "thresholds": { + "steps": [ + { "color": "green", "value": null } + ] + } + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + }, + "targets": [ + { + "rawSql": "SELECT COUNT(*) as total_queries FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Cached %", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 4, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "unit": "percentunit", + "thresholds": { + "steps": [ + { "color": "red", "value": null }, + { "color": "yellow", "value": 0.3 }, + { "color": "green", "value": 0.5 } + ] + } + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN response_type = 3 THEN 1 ELSE 0 END) / COUNT(*) as cached_pct FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Blocked %", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 8, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "unit": "percentunit", + "thresholds": { + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 0.1 }, + { "color": "red", "value": 0.3 } + ] + } + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN response_type = 4 THEN 1 ELSE 0 END) / COUNT(*) as blocked_pct FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "NxDomain %", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 12, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "unit": "percentunit", + "thresholds": { + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 0.2 }, + { "color": "red", "value": 0.5 } + ] + } + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN rcode = 3 THEN 1 ELSE 0 END) / COUNT(*) as nxdomain_pct FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Avg Response Time", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 16, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "unit": "ms", + "thresholds": { + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 50 }, + { "color": "red", "value": 200 } + ] + } + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false } + }, + "targets": [ + { + "rawSql": "SELECT AVG(response_rtt) as avg_rtt_ms FROM dns_logs WHERE $__timeFilter(timestamp) AND response_rtt IS NOT NULL", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Queries by Protocol", + "type": "stat", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 4, "w": 4, "x": 20, "y": 0 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" } + }, + "overrides": [] + }, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "textMode": "auto", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": true } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN protocol = 0 THEN 1 ELSE 0 END) as UDP, SUM(CASE WHEN protocol = 1 THEN 1 ELSE 0 END) as TCP, SUM(CASE WHEN protocol = 3 THEN 1 ELSE 0 END) as DoH, SUM(CASE WHEN protocol = 4 THEN 1 ELSE 0 END) as DoT FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Queries Over Time", + "type": "timeseries", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 4 }, + "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 }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "never", + "spanNulls": false, + "stacking": { "group": "A", "mode": "normal" } + } + }, + "overrides": [] + }, + "options": { + "legend": { "calcs": ["sum"], "displayMode": "list", "placement": "bottom" }, + "tooltip": { "mode": "multi", "sort": "desc" } + }, + "targets": [ + { + "rawSql": "SELECT $__timeGroup(timestamp, $__interval) as time, SUM(CASE WHEN response_type = 1 THEN 1 ELSE 0 END) as Authoritative, SUM(CASE WHEN response_type = 2 THEN 1 ELSE 0 END) as Recursive, SUM(CASE WHEN response_type = 3 THEN 1 ELSE 0 END) as Cached, SUM(CASE WHEN response_type = 4 THEN 1 ELSE 0 END) as Blocked, SUM(CASE WHEN response_type = 5 THEN 1 ELSE 0 END) as Dropped FROM dns_logs WHERE $__timeFilter(timestamp) GROUP BY time ORDER BY time", + "format": "time_series", + "refId": "A" + } + ] + }, + { + "title": "Response Codes", + "type": "piechart", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 8, "w": 8, "x": 0, "y": 12 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "NOERROR" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "NXDOMAIN" }, "properties": [{ "id": "color", "value": { "fixedColor": "yellow", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "SERVFAIL" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "REFUSED" }, "properties": [{ "id": "color", "value": { "fixedColor": "orange", "mode": "fixed" } }] } + ] + }, + "options": { + "legend": { "displayMode": "table", "placement": "right", "values": ["value", "percent"] }, + "pieType": "donut", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": true }, + "tooltip": { "mode": "single" } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN rcode = 0 THEN 1 ELSE 0 END) as NOERROR, SUM(CASE WHEN rcode = 2 THEN 1 ELSE 0 END) as SERVFAIL, SUM(CASE WHEN rcode = 3 THEN 1 ELSE 0 END) as NXDOMAIN, SUM(CASE WHEN rcode = 5 THEN 1 ELSE 0 END) as REFUSED, SUM(CASE WHEN rcode NOT IN (0,2,3,5) THEN 1 ELSE 0 END) as Other FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Response Types", + "type": "piechart", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 8, "w": 8, "x": 8, "y": 12 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "Cached" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "Blocked" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "Recursive" }, "properties": [{ "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } }] }, + { "matcher": { "id": "byName", "options": "Authoritative" }, "properties": [{ "id": "color", "value": { "fixedColor": "purple", "mode": "fixed" } }] } + ] + }, + "options": { + "legend": { "displayMode": "table", "placement": "right", "values": ["value", "percent"] }, + "pieType": "donut", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": true }, + "tooltip": { "mode": "single" } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN response_type = 1 THEN 1 ELSE 0 END) as Authoritative, SUM(CASE WHEN response_type = 2 THEN 1 ELSE 0 END) as Recursive, SUM(CASE WHEN response_type = 3 THEN 1 ELSE 0 END) as Cached, SUM(CASE WHEN response_type = 4 THEN 1 ELSE 0 END) as Blocked, SUM(CASE WHEN response_type = 5 THEN 1 ELSE 0 END) as Dropped FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Query Types", + "type": "piechart", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 8, "w": 8, "x": 16, "y": 12 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" } + }, + "overrides": [] + }, + "options": { + "legend": { "displayMode": "table", "placement": "right", "values": ["value", "percent"] }, + "pieType": "donut", + "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": true }, + "tooltip": { "mode": "single" } + }, + "targets": [ + { + "rawSql": "SELECT SUM(CASE WHEN qtype = 1 THEN 1 ELSE 0 END) as A, SUM(CASE WHEN qtype = 28 THEN 1 ELSE 0 END) as AAAA, SUM(CASE WHEN qtype = 5 THEN 1 ELSE 0 END) as CNAME, SUM(CASE WHEN qtype = 15 THEN 1 ELSE 0 END) as MX, SUM(CASE WHEN qtype = 16 THEN 1 ELSE 0 END) as TXT, SUM(CASE WHEN qtype = 33 THEN 1 ELSE 0 END) as SRV, SUM(CASE WHEN qtype = 12 THEN 1 ELSE 0 END) as PTR, SUM(CASE WHEN qtype = 6 THEN 1 ELSE 0 END) as SOA, SUM(CASE WHEN qtype = 2 THEN 1 ELSE 0 END) as NS, SUM(CASE WHEN qtype = 65 THEN 1 ELSE 0 END) as HTTPS, SUM(CASE WHEN qtype NOT IN (1,2,5,6,12,15,16,28,33,65) THEN 1 ELSE 0 END) as Other FROM dns_logs WHERE $__timeFilter(timestamp)", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Top 20 Queried Domains", + "type": "table", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 10, "w": 12, "x": 0, "y": 20 }, + "fieldConfig": { + "defaults": { + "custom": { "filterable": true } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "count" }, "properties": [{ "id": "custom.width", "value": 100 }] } + ] + }, + "options": { + "showHeader": true, + "sortBy": [{ "desc": true, "displayName": "count" }] + }, + "targets": [ + { + "rawSql": "SELECT qname as domain, COUNT(*) as count FROM dns_logs WHERE $__timeFilter(timestamp) GROUP BY qname ORDER BY count DESC LIMIT 20", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Top 20 Clients", + "type": "table", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 10, "w": 12, "x": 12, "y": 20 }, + "fieldConfig": { + "defaults": { + "custom": { "filterable": true } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "count" }, "properties": [{ "id": "custom.width", "value": 100 }] } + ] + }, + "options": { + "showHeader": true, + "sortBy": [{ "desc": true, "displayName": "count" }] + }, + "targets": [ + { + "rawSql": "SELECT client_ip, COUNT(*) as count FROM dns_logs WHERE $__timeFilter(timestamp) GROUP BY client_ip ORDER BY count DESC LIMIT 20", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Average Response Time Over Time", + "type": "timeseries", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 30 }, + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "unit": "ms", + "custom": { + "axisBorderShow": false, + "axisLabel": "Response Time (ms)", + "axisPlacement": "auto", + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "lineWidth": 2, + "pointSize": 5, + "showPoints": "never", + "spanNulls": true + } + }, + "overrides": [] + }, + "options": { + "legend": { "calcs": ["mean", "max"], "displayMode": "list", "placement": "bottom" }, + "tooltip": { "mode": "multi", "sort": "desc" } + }, + "targets": [ + { + "rawSql": "SELECT $__timeGroup(timestamp, $__interval) as time, AVG(response_rtt) as avg_rtt, MAX(response_rtt) as max_rtt FROM dns_logs WHERE $__timeFilter(timestamp) AND response_rtt IS NOT NULL GROUP BY time ORDER BY time", + "format": "time_series", + "refId": "A" + } + ] + }, + { + "title": "Top 20 NxDomain Domains", + "type": "table", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 10, "w": 12, "x": 0, "y": 38 }, + "fieldConfig": { + "defaults": { + "custom": { "filterable": true } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "count" }, "properties": [{ "id": "custom.width", "value": 100 }] } + ] + }, + "options": { + "showHeader": true, + "sortBy": [{ "desc": true, "displayName": "count" }] + }, + "targets": [ + { + "rawSql": "SELECT qname as domain, COUNT(*) as count FROM dns_logs WHERE $__timeFilter(timestamp) AND rcode = 3 GROUP BY qname ORDER BY count DESC LIMIT 20", + "format": "table", + "refId": "A" + } + ] + }, + { + "title": "Top 20 Blocked Domains", + "type": "table", + "datasource": { "type": "mysql", "uid": "technitium-mysql" }, + "gridPos": { "h": 10, "w": 12, "x": 12, "y": 38 }, + "fieldConfig": { + "defaults": { + "custom": { "filterable": true } + }, + "overrides": [ + { "matcher": { "id": "byName", "options": "count" }, "properties": [{ "id": "custom.width", "value": 100 }] } + ] + }, + "options": { + "showHeader": true, + "sortBy": [{ "desc": true, "displayName": "count" }] + }, + "targets": [ + { + "rawSql": "SELECT qname as domain, COUNT(*) as count FROM dns_logs WHERE $__timeFilter(timestamp) AND response_type = 4 GROUP BY qname ORDER BY count DESC LIMIT 20", + "format": "table", + "refId": "A" + } + ] + } + ], + "refresh": "5m", + "schemaVersion": 39, + "tags": ["dns", "technitium", "mysql"], + "templating": { "list": [] }, + "time": { "from": "now-24h", "to": "now" }, + "timepicker": {}, + "timezone": "", + "title": "Technitium DNS", + "uid": "technitium-dns", + "version": 1 +} diff --git a/modules/kubernetes/monitoring/grafana_chart_values.yaml b/modules/kubernetes/monitoring/grafana_chart_values.yaml index 9a32eece..d7b4ec7f 100644 --- a/modules/kubernetes/monitoring/grafana_chart_values.yaml +++ b/modules/kubernetes/monitoring/grafana_chart_values.yaml @@ -20,9 +20,8 @@ sidecar: datasources: enabled: "true" dashboards: - enabled: false - # label: "grafana_dashboard" - # folder: "/var/lib/grafana/dashboards" + enabled: true + label: "grafana_dashboard" dashboardProviders: dashboardproviders.yaml: apiVersion: 1 diff --git a/modules/kubernetes/technitium/main.tf b/modules/kubernetes/technitium/main.tf index 8b60f93b..f9d3357e 100644 --- a/modules/kubernetes/technitium/main.tf +++ b/modules/kubernetes/technitium/main.tf @@ -1,6 +1,7 @@ variable "tls_secret_name" {} variable "tier" { type = string } variable "homepage_token" {} +variable "technitium_db_password" {} resource "kubernetes_namespace" "technitium" { metadata { @@ -260,3 +261,45 @@ module "ingress-doh" { service_name = "technitium-web" } +# Grafana datasource for Technitium DNS query logs in MySQL +resource "kubernetes_config_map" "grafana_technitium_datasource" { + metadata { + name = "grafana-technitium-datasource" + namespace = "monitoring" + labels = { + grafana_datasource = "1" + } + } + data = { + "technitium-datasource.yaml" = yamlencode({ + apiVersion = 1 + datasources = [{ + name = "Technitium MySQL" + type = "mysql" + access = "proxy" + url = "mysql.dbaas.svc.cluster.local:3306" + database = "technitium" + user = "technitium" + uid = "technitium-mysql" + secureJsonData = { + password = var.technitium_db_password + } + }] + }) + } +} + +# Grafana dashboard for Technitium DNS query logs +resource "kubernetes_config_map" "grafana_technitium_dashboard" { + metadata { + name = "grafana-technitium-dashboard" + namespace = "monitoring" + labels = { + grafana_dashboard = "1" + } + } + data = { + "technitium-dns.json" = file("${path.module}/../monitoring/dashboards/technitium-dns.json") + } +} +