From ff36c944b3c78206bcd7100330d66bef849aeab1 Mon Sep 17 00:00:00 2001 From: timm Date: Sat, 19 Apr 2025 01:59:11 +0200 Subject: [PATCH] a --- Dockerfile | 9 ++ docker-compose.yml | 39 ++++++++ grafana/dashboards/oidc-dashboard.json | 1 + grafana/provisioning/dashboards/dashboard.yml | 8 ++ .../provisioning/datasources/datasource.yml | 8 ++ oidc-monitor-full.zip | Bin 0 -> 5650 bytes package.json | 16 ++++ prometheus/prometheus.yml | 8 ++ scheduler.js | 83 ++++++++++++++++++ test/monitor.js | 3 + 10 files changed, 175 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100755 grafana/dashboards/oidc-dashboard.json create mode 100755 grafana/provisioning/dashboards/dashboard.yml create mode 100755 grafana/provisioning/datasources/datasource.yml create mode 100644 oidc-monitor-full.zip create mode 100644 package.json create mode 100755 prometheus/prometheus.yml create mode 100644 scheduler.js create mode 100644 test/monitor.js diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1922c41 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ + +FROM node:20-slim +WORKDIR /app +COPY package.json ./ +RUN npm install +COPY test /app/test +COPY scheduler.js /app/scheduler.js +EXPOSE 3000 +CMD ["npm", "start"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b2cdd7b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: '3.8' + +services: + e2e-monitor: + build: . + restart: unless-stopped + env_file: .env + ports: + - "3020:3000" # Web API: /status, /healthz, /run-now + volumes: + - ./test:/app/test:ro + - ./test-results:/app/test-results + depends_on: + - pushgateway + + pushgateway: + image: prom/pushgateway + ports: + - "9091:9091" + + prometheus: + image: prom/prometheus + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + ports: + - "9090:9090" + depends_on: + - pushgateway + + grafana: + image: grafana/grafana + ports: + - "3031:3000" + volumes: + - ./grafana/provisioning:/etc/grafana/provisioning + - ./grafana/dashboards:/var/lib/grafana/dashboards + depends_on: + - prometheus + diff --git a/grafana/dashboards/oidc-dashboard.json b/grafana/dashboards/oidc-dashboard.json new file mode 100755 index 0000000..44e4cc2 --- /dev/null +++ b/grafana/dashboards/oidc-dashboard.json @@ -0,0 +1 @@ +// Placeholder Dashboard JSON \ No newline at end of file diff --git a/grafana/provisioning/dashboards/dashboard.yml b/grafana/provisioning/dashboards/dashboard.yml new file mode 100755 index 0000000..d91b3e0 --- /dev/null +++ b/grafana/provisioning/dashboards/dashboard.yml @@ -0,0 +1,8 @@ + +apiVersion: 1 +providers: + - name: 'OIDC Monitoring' + folder: '' + type: file + options: + path: /var/lib/grafana/dashboards diff --git a/grafana/provisioning/datasources/datasource.yml b/grafana/provisioning/datasources/datasource.yml new file mode 100755 index 0000000..c5e37fc --- /dev/null +++ b/grafana/provisioning/datasources/datasource.yml @@ -0,0 +1,8 @@ + +apiVersion: 1 +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true diff --git a/oidc-monitor-full.zip b/oidc-monitor-full.zip new file mode 100644 index 0000000000000000000000000000000000000000..97c5efe1444f7276102a39af6f5d4aad35ae7ad2 GIT binary patch literal 5650 zcmb7I-H#hr72hO)#8il{3KWULtrg*Mw4U*9K1dwgV%AP#_QRI#ZQ6!n-yL6jCOe)P z=HA(lx)yyvf}%(ukcyBfQAOX7c*p|+iMKxS%nRZ%z;nwVfW$d>W<2A&yKS0i63@Bk zo_jui=i^Ri^TMZ|UBN$peEiE-FaPH+jo-mRWOPMGn4`yMe&t-HHJykJTkj|=L$ zF_U0i$UP?hifP=k*(h>Z2wUT|JVk51+-dikZyp-KvQ%L}Wxa==3F_#Q5<85N@vQ@Is7f#5*J z?Z6gm0Zix~lGnTd409=J!~*7xm}faGx04<@KE4)yux4C0Zb48V_`J(Do1N7B)d(G}neY;s>>&!?Xztw|DnWz2Cf7e`O&Pj0z%dPpDvr^tgJna&t|IKaafxX9$9Ewm3Wcst`Yz!hmw}Q z3Ph{`h^2&46jA{-B7P@xFk>8f7LrI9c^fvf_H`-*n+5{pua#uch+`n@MjwxDK+p}( zKSZ4f!BrnH?D`XZcz@=xL&>0*4B@wW?VboBtMtas$cNxnd7F0K-tg`pp= z5-vu5B;@}Nj1#eX)K%tlFu>%?IpPw7^y>-yh6%wAlTUFQfWe*G0|fcN=xoa zXtC6UN$QvSRH~0#k(vn0shmU~4u4*9o=`8r1NsUbL0%-o+st++4D!zfpa2jq&E%4i zu+E31N{UFBrisl!FFtwaVGN4xxT7OTP+t~8EQhZ$N1(nrX^WW6KjxS@qK6PHS$)3~ z`co!s7I8iH+v;f{l?u+`U)Z}yk`n@w5Ui3E3Hg+9=^k@2V}`Q_{$5S#*>cYCELJOA znl06WQ>*d3FdwGrCLqxvtt=^8!%1KO+2?qJL>u%Go;(L{r5JgUtU+We^E`X1^MErz z+=%D*>FFXd$r_9@n9jGIBR104OLI-CBCDnm_+02i#f0UKF*g%^O>l#mpInAmv!p4j zNk-a?0@|UX%}8;>_h7UT<^FNNiU3Q&j)V#Gf#VgS0RETmJP781%V2J1EMHCtsA8P@`;?66$T#dJzy5pZ!|8SU?QX*4`3XFngdmPF;yB? z$e>B}(`9`oZL|TZ)uq0>n8$GJh57)ZfPsdbwLGCOIU6Upv`rV+uR-9~Dy4WEq)!w= z*Bw)rGZ2JTgOHqZ2HLWXH7-_U3>9cuk;T9lOBDVo%l&q8T;dL?GP*<_d1fj+`R!ZS zcAI5X;FCvA?s}TQK?^n}Oz1@uMu{@a2iSmNURwnu^SI|`Lq_QqQl(!Y&)$}UfgC?j zL2RCgty|KQnOvw1uCQM}DHj}o8I|h{Y1ymQYH?W7e2R~i6O?`p%NmA8FK#jMI-)4n zVcA?9_ef6N_9jv=$eC)OGt6WsG(#KlewkAZYlPhBIvlE-j+g>REryb`24NW+e)#C& zFUUQ%N9vsxao>M08Vf?BG3fwMp}6DTInG9?jJBBI;Ds{*2!s}NqeC)0opoWyBWvUZJYT0(`GzEd0& zO^HS$WhUS2wRe^s_m!{zooA%frB3xU?PK~1?7Ge;_Wf}E!{~2=cV{7 z1o%(O78B3KUh6EPAzdb*xyxdggh&!;a;<@bkB%iJ3f(Hf`!wD>7ZT8e6}j&41{>4J zh59YRh$-;6^V1gwZ-I6ARG-qyg@ZHSB4n0rl%A0T3usX$2`-er8)E~8X!nj6{CKA$;6b-E4twISKY3DI>@&F;exU~{~-j8e{2 zNosY;BwhT1A}PaW4yKqKs!TP_GnxNZWuA=wX-Tghpk{Vui4dGbrn`@b_N;oQq$^xBmkIHumBG literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..daa1eaa --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ + +{ + "name": "oidc-monitor", + "version": "1.0.0", + "scripts": { + "start": "node scheduler.js" + }, + "dependencies": { + "axios": "^1.6.8", + "dotenv": "^16.4.5", + "express": "^4.18.4", + "nodemailer": "^6.9.8", + "playwright": "^1.43.0", + "speakeasy": "^2.0.0" + } +} diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml new file mode 100755 index 0000000..ebe4188 --- /dev/null +++ b/prometheus/prometheus.yml @@ -0,0 +1,8 @@ + +global: + scrape_interval: 15s + +scrape_configs: + - job_name: 'pushgateway' + static_configs: + - targets: ['pushgateway:9091'] diff --git a/scheduler.js b/scheduler.js new file mode 100644 index 0000000..e38201a --- /dev/null +++ b/scheduler.js @@ -0,0 +1,83 @@ + +require('dotenv').config(); +const express = require('express'); +const { exec } = require('child_process'); +const axios = require('axios'); +const nodemailer = require('nodemailer'); + +const INTERVAL_MINUTES = 30; +const MAX_RETRIES = 3; +const PORT = process.env.PORT || 3000; +const app = express(); +let lastStatus = { success: null, message: null, timestamp: null, duration: null }; + +function runCheck(attempt = 1) { + const startTs = Date.now(); + console.log(`[{new Date().toISOString()}] ▶️ Starting OIDC check (try {attempt}/{MAX_RETRIES})...`); + + const child = exec('node /app/test/monitor.js', (error, stdout, stderr) => { + lastStatus.timestamp = new Date().toISOString(); + lastStatus.duration = Date.now() - startTs; + + if (stdout) console.log(stdout); + if (stderr) console.error(stderr); + + lastStatus.success = !error; + lastStatus.message = error ? `Fehlgeschlagen: ${error.message}` : 'Login erfolgreich'; + + if (error) { + notifySlack(`Fehler beim Login:\n${lastStatus.message}`); + sendEmail('❌ OIDC Monitoring Fehler', `Zeit: ${lastStatus.timestamp}\n${lastStatus.message}`); + } + + pushToPrometheus(!error, lastStatus.duration); + }); +} + +function pushToPrometheus(success, duration) { + const labels = `{job="oidc-monitor",instance="${process.env.PROMETHEUS_INSTANCE_ID}"}`; + const metrics = ` +oidc_login_success${labels} ${success ? 1 : 0} +oidc_login_duration_seconds${labels} ${(duration / 1000).toFixed(2)} +`; + axios.post(`${process.env.PUSHGATEWAY_URL}/metrics/job/oidc-monitor`, metrics, { + headers: { 'Content-Type': 'text/plain' } + }).then(() => console.log('📡 Prometheus Push erfolgreich')) + .catch(err => console.error('❌ Prometheus Push fehlgeschlagen:', err.message)); +} + +function notifySlack(message) { + if (!process.env.SLACK_WEBHOOK_URL) return; + axios.post(process.env.SLACK_WEBHOOK_URL, { text: `❗️OIDC Monitoring Alert:\n${message}` }) + .then(() => console.log('📣 Slack-Nachricht gesendet')) + .catch(err => console.error('❌ Slack fehlgeschlagen:', err.message)); +} + +function sendEmail(subject, text) { + const transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port: parseInt(process.env.SMTP_PORT || '25', 10), + secure: false + }); + transporter.sendMail({ + from: process.env.MAIL_FROM, + to: process.env.MAIL_TO, + subject, + text + }).then(() => console.log('✉️ E-Mail gesendet')) + .catch(err => console.error('❌ Mail fehlgeschlagen:', err.message)); +} + +app.get('/run-now', (req, res) => { runCheck(); res.send('▶️ Check gestartet'); }); +app.get('/healthz', (req, res) => { + if (lastStatus.success === false) return res.status(500).send('Letzter Check fehlgeschlagen'); + res.send('OK'); +}); +app.get('/status', (req, res) => res.json(lastStatus)); + +app.listen(PORT, () => { + console.log(`🌐 Web API läuft auf Port ${PORT}`); +}); + +runCheck(); +setInterval(runCheck, INTERVAL_MINUTES * 60 * 1000); diff --git a/test/monitor.js b/test/monitor.js new file mode 100644 index 0000000..bf84619 --- /dev/null +++ b/test/monitor.js @@ -0,0 +1,3 @@ + +// Placeholder für dein Playwright-Login-Script +console.log("▶️ Simulierter Playwright-Check gestartet...");